Unverified Commit 8dc89415 authored by Martin Holst Swende's avatar Martin Holst Swende Committed by GitHub

core/vm: use a callcontext struct (#20761)

* core/vm: use a callcontext struct

* core/vm: fix tests

* core/vm/runtime: benchmark

* core/vm: make intpool push inlineable, unexpose callcontext
parent 0bec6a43
...@@ -60,9 +60,9 @@ func enable1884(jt *JumpTable) { ...@@ -60,9 +60,9 @@ func enable1884(jt *JumpTable) {
} }
} }
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address())) balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
stack.push(balance) callContext.stack.push(balance)
return nil, nil return nil, nil
} }
...@@ -80,9 +80,9 @@ func enable1344(jt *JumpTable) { ...@@ -80,9 +80,9 @@ func enable1344(jt *JumpTable) {
} }
// opChainID implements CHAINID opcode // opChainID implements CHAINID opcode
func opChainID(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainID) chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainID)
stack.push(chainId) callContext.stack.push(chainId)
return nil, nil return nil, nil
} }
......
...@@ -37,48 +37,48 @@ var ( ...@@ -37,48 +37,48 @@ var (
errInvalidJump = errors.New("evm: invalid jump destination") errInvalidJump = errors.New("evm: invalid jump destination")
) )
func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opAdd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
math.U256(y.Add(x, y)) math.U256(y.Add(x, y))
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSub(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
math.U256(y.Sub(x, y)) math.U256(y.Sub(x, y))
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMul(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := callContext.stack.pop(), callContext.stack.pop()
stack.push(math.U256(x.Mul(x, y))) callContext.stack.push(math.U256(x.Mul(x, y)))
interpreter.intPool.put(y) interpreter.intPool.putOne(y)
return nil, nil return nil, nil
} }
func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opDiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
if y.Sign() != 0 { if y.Sign() != 0 {
math.U256(y.Div(x, y)) math.U256(y.Div(x, y))
} else { } else {
y.SetUint64(0) y.SetUint64(0)
} }
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSdiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop()) x, y := math.S256(callContext.stack.pop()), math.S256(callContext.stack.pop())
res := interpreter.intPool.getZero() res := interpreter.intPool.getZero()
if y.Sign() == 0 || x.Sign() == 0 { if y.Sign() == 0 || x.Sign() == 0 {
stack.push(res) callContext.stack.push(res)
} else { } else {
if x.Sign() != y.Sign() { if x.Sign() != y.Sign() {
res.Div(x.Abs(x), y.Abs(y)) res.Div(x.Abs(x), y.Abs(y))
...@@ -86,29 +86,29 @@ func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory ...@@ -86,29 +86,29 @@ func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
} else { } else {
res.Div(x.Abs(x), y.Abs(y)) res.Div(x.Abs(x), y.Abs(y))
} }
stack.push(math.U256(res)) callContext.stack.push(math.U256(res))
} }
interpreter.intPool.put(x, y) interpreter.intPool.put(x, y)
return nil, nil return nil, nil
} }
func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := callContext.stack.pop(), callContext.stack.pop()
if y.Sign() == 0 { if y.Sign() == 0 {
stack.push(x.SetUint64(0)) callContext.stack.push(x.SetUint64(0))
} else { } else {
stack.push(math.U256(x.Mod(x, y))) callContext.stack.push(math.U256(x.Mod(x, y)))
} }
interpreter.intPool.put(y) interpreter.intPool.putOne(y)
return nil, nil return nil, nil
} }
func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop()) x, y := math.S256(callContext.stack.pop()), math.S256(callContext.stack.pop())
res := interpreter.intPool.getZero() res := interpreter.intPool.getZero()
if y.Sign() == 0 { if y.Sign() == 0 {
stack.push(res) callContext.stack.push(res)
} else { } else {
if x.Sign() < 0 { if x.Sign() < 0 {
res.Mod(x.Abs(x), y.Abs(y)) res.Mod(x.Abs(x), y.Abs(y))
...@@ -116,38 +116,38 @@ func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory ...@@ -116,38 +116,38 @@ func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
} else { } else {
res.Mod(x.Abs(x), y.Abs(y)) res.Mod(x.Abs(x), y.Abs(y))
} }
stack.push(math.U256(res)) callContext.stack.push(math.U256(res))
} }
interpreter.intPool.put(x, y) interpreter.intPool.put(x, y)
return nil, nil return nil, nil
} }
func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opExp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
base, exponent := stack.pop(), stack.pop() base, exponent := callContext.stack.pop(), callContext.stack.pop()
// some shortcuts // some shortcuts
cmpToOne := exponent.Cmp(big1) cmpToOne := exponent.Cmp(big1)
if cmpToOne < 0 { // Exponent is zero if cmpToOne < 0 { // Exponent is zero
// x ^ 0 == 1 // x ^ 0 == 1
stack.push(base.SetUint64(1)) callContext.stack.push(base.SetUint64(1))
} else if base.Sign() == 0 { } else if base.Sign() == 0 {
// 0 ^ y, if y != 0, == 0 // 0 ^ y, if y != 0, == 0
stack.push(base.SetUint64(0)) callContext.stack.push(base.SetUint64(0))
} else if cmpToOne == 0 { // Exponent is one } else if cmpToOne == 0 { // Exponent is one
// x ^ 1 == x // x ^ 1 == x
stack.push(base) callContext.stack.push(base)
} else { } else {
stack.push(math.Exp(base, exponent)) callContext.stack.push(math.Exp(base, exponent))
interpreter.intPool.put(base) interpreter.intPool.putOne(base)
} }
interpreter.intPool.put(exponent) interpreter.intPool.putOne(exponent)
return nil, nil return nil, nil
} }
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSignExtend(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
back := stack.pop() back := callContext.stack.pop()
if back.Cmp(big.NewInt(31)) < 0 { if back.Cmp(big.NewInt(31)) < 0 {
bit := uint(back.Uint64()*8 + 7) bit := uint(back.Uint64()*8 + 7)
num := stack.pop() num := callContext.stack.pop()
mask := back.Lsh(common.Big1, bit) mask := back.Lsh(common.Big1, bit)
mask.Sub(mask, common.Big1) mask.Sub(mask, common.Big1)
if num.Bit(int(bit)) > 0 { if num.Bit(int(bit)) > 0 {
...@@ -156,43 +156,43 @@ func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m ...@@ -156,43 +156,43 @@ func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m
num.And(num, mask) num.And(num, mask)
} }
stack.push(math.U256(num)) callContext.stack.push(math.U256(num))
} }
interpreter.intPool.put(back) interpreter.intPool.putOne(back)
return nil, nil return nil, nil
} }
func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opNot(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x := stack.peek() x := callContext.stack.peek()
math.U256(x.Not(x)) math.U256(x.Not(x))
return nil, nil return nil, nil
} }
func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opLt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
if x.Cmp(y) < 0 { if x.Cmp(y) < 0 {
y.SetUint64(1) y.SetUint64(1)
} else { } else {
y.SetUint64(0) y.SetUint64(0)
} }
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opGt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
if x.Cmp(y) > 0 { if x.Cmp(y) > 0 {
y.SetUint64(1) y.SetUint64(1)
} else { } else {
y.SetUint64(0) y.SetUint64(0)
} }
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSlt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
xSign := x.Cmp(tt255) xSign := x.Cmp(tt255)
ySign := y.Cmp(tt255) ySign := y.Cmp(tt255)
...@@ -211,12 +211,12 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * ...@@ -211,12 +211,12 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
y.SetUint64(0) y.SetUint64(0)
} }
} }
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSgt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
xSign := x.Cmp(tt255) xSign := x.Cmp(tt255)
ySign := y.Cmp(tt255) ySign := y.Cmp(tt255)
...@@ -235,23 +235,23 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * ...@@ -235,23 +235,23 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
y.SetUint64(0) y.SetUint64(0)
} }
} }
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opEq(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
if x.Cmp(y) == 0 { if x.Cmp(y) == 0 {
y.SetUint64(1) y.SetUint64(1)
} else { } else {
y.SetUint64(0) y.SetUint64(0)
} }
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opIszero(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x := stack.peek() x := callContext.stack.peek()
if x.Sign() > 0 { if x.Sign() > 0 {
x.SetUint64(0) x.SetUint64(0)
} else { } else {
...@@ -260,63 +260,63 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor ...@@ -260,63 +260,63 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
return nil, nil return nil, nil
} }
func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opAnd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := callContext.stack.pop(), callContext.stack.pop()
stack.push(x.And(x, y)) callContext.stack.push(x.And(x, y))
interpreter.intPool.put(y) interpreter.intPool.putOne(y)
return nil, nil return nil, nil
} }
func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opOr(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
y.Or(x, y) y.Or(x, y)
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opXor(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := stack.pop(), stack.peek() x, y := callContext.stack.pop(), callContext.stack.peek()
y.Xor(x, y) y.Xor(x, y)
interpreter.intPool.put(x) interpreter.intPool.putOne(x)
return nil, nil return nil, nil
} }
func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opByte(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
th, val := stack.pop(), stack.peek() th, val := callContext.stack.pop(), callContext.stack.peek()
if th.Cmp(common.Big32) < 0 { if th.Cmp(common.Big32) < 0 {
b := math.Byte(val, 32, int(th.Int64())) b := math.Byte(val, 32, int(th.Int64()))
val.SetUint64(uint64(b)) val.SetUint64(uint64(b))
} else { } else {
val.SetUint64(0) val.SetUint64(0)
} }
interpreter.intPool.put(th) interpreter.intPool.putOne(th)
return nil, nil return nil, nil
} }
func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opAddmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y, z := stack.pop(), stack.pop(), stack.pop() x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
if z.Cmp(bigZero) > 0 { if z.Cmp(bigZero) > 0 {
x.Add(x, y) x.Add(x, y)
x.Mod(x, z) x.Mod(x, z)
stack.push(math.U256(x)) callContext.stack.push(math.U256(x))
} else { } else {
stack.push(x.SetUint64(0)) callContext.stack.push(x.SetUint64(0))
} }
interpreter.intPool.put(y, z) interpreter.intPool.put(y, z)
return nil, nil return nil, nil
} }
func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMulmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y, z := stack.pop(), stack.pop(), stack.pop() x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
if z.Cmp(bigZero) > 0 { if z.Cmp(bigZero) > 0 {
x.Mul(x, y) x.Mul(x, y)
x.Mod(x, z) x.Mod(x, z)
stack.push(math.U256(x)) callContext.stack.push(math.U256(x))
} else { } else {
stack.push(x.SetUint64(0)) callContext.stack.push(x.SetUint64(0))
} }
interpreter.intPool.put(y, z) interpreter.intPool.put(y, z)
return nil, nil return nil, nil
...@@ -325,10 +325,10 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor ...@@ -325,10 +325,10 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
// opSHL implements Shift Left // opSHL implements Shift Left
// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the left by arg1 number of bits. // and pushes on the stack arg2 shifted to the left by arg1 number of bits.
func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSHL(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
shift, value := math.U256(stack.pop()), math.U256(stack.peek()) shift, value := math.U256(callContext.stack.pop()), math.U256(callContext.stack.peek())
defer interpreter.intPool.put(shift) // First operand back into the pool defer interpreter.intPool.putOne(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 { if shift.Cmp(common.Big256) >= 0 {
value.SetUint64(0) value.SetUint64(0)
...@@ -343,10 +343,10 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * ...@@ -343,10 +343,10 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
// opSHR implements Logical Shift Right // opSHR implements Logical Shift Right
// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSHR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
shift, value := math.U256(stack.pop()), math.U256(stack.peek()) shift, value := math.U256(callContext.stack.pop()), math.U256(callContext.stack.peek())
defer interpreter.intPool.put(shift) // First operand back into the pool defer interpreter.intPool.putOne(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 { if shift.Cmp(common.Big256) >= 0 {
value.SetUint64(0) value.SetUint64(0)
...@@ -361,10 +361,10 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * ...@@ -361,10 +361,10 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
// opSAR implements Arithmetic Shift Right // opSAR implements Arithmetic Shift Right
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSAR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one
shift, value := math.U256(stack.pop()), math.S256(stack.pop()) shift, value := math.U256(callContext.stack.pop()), math.S256(callContext.stack.pop())
defer interpreter.intPool.put(shift) // First operand back into the pool defer interpreter.intPool.putOne(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 { if shift.Cmp(common.Big256) >= 0 {
if value.Sign() >= 0 { if value.Sign() >= 0 {
...@@ -372,19 +372,19 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * ...@@ -372,19 +372,19 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
} else { } else {
value.SetInt64(-1) value.SetInt64(-1)
} }
stack.push(math.U256(value)) callContext.stack.push(math.U256(value))
return nil, nil return nil, nil
} }
n := uint(shift.Uint64()) n := uint(shift.Uint64())
value.Rsh(value, n) value.Rsh(value, n)
stack.push(math.U256(value)) callContext.stack.push(math.U256(value))
return nil, nil return nil, nil
} }
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSha3(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
offset, size := stack.pop(), stack.pop() offset, size := callContext.stack.pop(), callContext.stack.pop()
data := memory.GetPtr(offset.Int64(), size.Int64()) data := callContext.memory.GetPtr(offset.Int64(), size.Int64())
if interpreter.hasher == nil { if interpreter.hasher == nil {
interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState) interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
...@@ -398,70 +398,70 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory ...@@ -398,70 +398,70 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
if evm.vmConfig.EnablePreimageRecording { if evm.vmConfig.EnablePreimageRecording {
evm.StateDB.AddPreimage(interpreter.hasherBuf, data) evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
} }
stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:])) callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:]))
interpreter.intPool.put(offset, size) interpreter.intPool.put(offset, size)
return nil, nil return nil, nil
} }
func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opAddress(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(contract.Address().Bytes())) callContext.stack.push(interpreter.intPool.get().SetBytes(callContext.contract.Address().Bytes()))
return nil, nil return nil, nil
} }
func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := stack.peek() slot := callContext.stack.peek()
slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot))) slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot)))
return nil, nil return nil, nil
} }
func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opOrigin(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes())) callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes()))
return nil, nil return nil, nil
} }
func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCaller(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(contract.Caller().Bytes())) callContext.stack.push(interpreter.intPool.get().SetBytes(callContext.contract.Caller().Bytes()))
return nil, nil return nil, nil
} }
func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCallValue(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().Set(contract.value)) callContext.stack.push(interpreter.intPool.get().Set(callContext.contract.value))
return nil, nil return nil, nil
} }
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32))) callContext.stack.push(interpreter.intPool.get().SetBytes(getDataBig(callContext.contract.Input, callContext.stack.pop(), big32)))
return nil, nil return nil, nil
} }
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) callContext.stack.push(interpreter.intPool.get().SetInt64(int64(len(callContext.contract.Input))))
return nil, nil return nil, nil
} }
func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var ( var (
memOffset = stack.pop() memOffset = callContext.stack.pop()
dataOffset = stack.pop() dataOffset = callContext.stack.pop()
length = stack.pop() length = callContext.stack.pop()
) )
memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length)) callContext.memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(callContext.contract.Input, dataOffset, length))
interpreter.intPool.put(memOffset, dataOffset, length) interpreter.intPool.put(memOffset, dataOffset, length)
return nil, nil return nil, nil
} }
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData)))) callContext.stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData))))
return nil, nil return nil, nil
} }
func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var ( var (
memOffset = stack.pop() memOffset = callContext.stack.pop()
dataOffset = stack.pop() dataOffset = callContext.stack.pop()
length = stack.pop() length = callContext.stack.pop()
end = interpreter.intPool.get().Add(dataOffset, length) end = interpreter.intPool.get().Add(dataOffset, length)
) )
...@@ -470,47 +470,47 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac ...@@ -470,47 +470,47 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac
if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() { if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() {
return nil, errReturnDataOutOfBounds return nil, errReturnDataOutOfBounds
} }
memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()]) callContext.memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()])
return nil, nil return nil, nil
} }
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := stack.peek() slot := callContext.stack.peek()
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
return nil, nil return nil, nil
} }
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
l := interpreter.intPool.get().SetInt64(int64(len(contract.Code))) l := interpreter.intPool.get().SetInt64(int64(len(callContext.contract.Code)))
stack.push(l) callContext.stack.push(l)
return nil, nil return nil, nil
} }
func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var ( var (
memOffset = stack.pop() memOffset = callContext.stack.pop()
codeOffset = stack.pop() codeOffset = callContext.stack.pop()
length = stack.pop() length = callContext.stack.pop()
) )
codeCopy := getDataBig(contract.Code, codeOffset, length) codeCopy := getDataBig(callContext.contract.Code, codeOffset, length)
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
interpreter.intPool.put(memOffset, codeOffset, length) interpreter.intPool.put(memOffset, codeOffset, length)
return nil, nil return nil, nil
} }
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var ( var (
addr = common.BigToAddress(stack.pop()) addr = common.BigToAddress(callContext.stack.pop())
memOffset = stack.pop() memOffset = callContext.stack.pop()
codeOffset = stack.pop() codeOffset = callContext.stack.pop()
length = stack.pop() length = callContext.stack.pop()
) )
codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length) codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length)
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
interpreter.intPool.put(memOffset, codeOffset, length) interpreter.intPool.put(memOffset, codeOffset, length)
return nil, nil return nil, nil
...@@ -542,8 +542,8 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, ...@@ -542,8 +542,8 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
// //
// (6) Caller tries to get the code hash for an account which is marked as deleted, // (6) Caller tries to get the code hash for an account which is marked as deleted,
// this account should be regarded as a non-existent account and zero should be returned. // this account should be regarded as a non-existent account and zero should be returned.
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := stack.peek() slot := callContext.stack.peek()
address := common.BigToAddress(slot) address := common.BigToAddress(slot)
if interpreter.evm.StateDB.Empty(address) { if interpreter.evm.StateDB.Empty(address) {
slot.SetUint64(0) slot.SetUint64(0)
...@@ -553,108 +553,108 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, ...@@ -553,108 +553,108 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
return nil, nil return nil, nil
} }
func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opGasprice(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice)) callContext.stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice))
return nil, nil return nil, nil
} }
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
num := stack.pop() num := callContext.stack.pop()
n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257) n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257)
if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 { if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 {
stack.push(interpreter.evm.GetHash(num.Uint64()).Big()) callContext.stack.push(interpreter.evm.GetHash(num.Uint64()).Big())
} else { } else {
stack.push(interpreter.intPool.getZero()) callContext.stack.push(interpreter.intPool.getZero())
} }
interpreter.intPool.put(num, n) interpreter.intPool.put(num, n)
return nil, nil return nil, nil
} }
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCoinbase(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes())) callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes()))
return nil, nil return nil, nil
} }
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opTimestamp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time))) callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time)))
return nil, nil return nil, nil
} }
func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opNumber(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber))) callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber)))
return nil, nil return nil, nil
} }
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opDifficulty(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty))) callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty)))
return nil, nil return nil, nil
} }
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit))) callContext.stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit)))
return nil, nil return nil, nil
} }
func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opPop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
interpreter.intPool.put(stack.pop()) interpreter.intPool.putOne(callContext.stack.pop())
return nil, nil return nil, nil
} }
func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
v := stack.peek() v := callContext.stack.peek()
offset := v.Int64() offset := v.Int64()
v.SetBytes(memory.GetPtr(offset, 32)) v.SetBytes(callContext.memory.GetPtr(offset, 32))
return nil, nil return nil, nil
} }
func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// pop value of the stack // pop value of the stack
mStart, val := stack.pop(), stack.pop() mStart, val := callContext.stack.pop(), callContext.stack.pop()
memory.Set32(mStart.Uint64(), val) callContext.memory.Set32(mStart.Uint64(), val)
interpreter.intPool.put(mStart, val) interpreter.intPool.put(mStart, val)
return nil, nil return nil, nil
} }
func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMstore8(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
off, val := stack.pop().Int64(), stack.pop().Int64() off, val := callContext.stack.pop().Int64(), callContext.stack.pop().Int64()
memory.store[off] = byte(val & 0xff) callContext.memory.store[off] = byte(val & 0xff)
return nil, nil return nil, nil
} }
func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
loc := stack.peek() loc := callContext.stack.peek()
val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc)) val := interpreter.evm.StateDB.GetState(callContext.contract.Address(), common.BigToHash(loc))
loc.SetBytes(val.Bytes()) loc.SetBytes(val.Bytes())
return nil, nil return nil, nil
} }
func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
loc := common.BigToHash(stack.pop()) loc := common.BigToHash(callContext.stack.pop())
val := stack.pop() val := callContext.stack.pop()
interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) interpreter.evm.StateDB.SetState(callContext.contract.Address(), loc, common.BigToHash(val))
interpreter.intPool.put(val) interpreter.intPool.putOne(val)
return nil, nil return nil, nil
} }
func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opJump(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
pos := stack.pop() pos := callContext.stack.pop()
if !contract.validJumpdest(pos) { if !callContext.contract.validJumpdest(pos) {
return nil, errInvalidJump return nil, errInvalidJump
} }
*pc = pos.Uint64() *pc = pos.Uint64()
interpreter.intPool.put(pos) interpreter.intPool.putOne(pos)
return nil, nil return nil, nil
} }
func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opJumpi(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
pos, cond := stack.pop(), stack.pop() pos, cond := callContext.stack.pop(), callContext.stack.pop()
if cond.Sign() != 0 { if cond.Sign() != 0 {
if !contract.validJumpdest(pos) { if !callContext.contract.validJumpdest(pos) {
return nil, errInvalidJump return nil, errInvalidJump
} }
*pc = pos.Uint64() *pc = pos.Uint64()
...@@ -666,50 +666,50 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory ...@@ -666,50 +666,50 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
return nil, nil return nil, nil
} }
func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opJumpdest(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
return nil, nil return nil, nil
} }
func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opPc(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetUint64(*pc)) callContext.stack.push(interpreter.intPool.get().SetUint64(*pc))
return nil, nil return nil, nil
} }
func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMsize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetInt64(int64(memory.Len()))) callContext.stack.push(interpreter.intPool.get().SetInt64(int64(callContext.memory.Len())))
return nil, nil return nil, nil
} }
func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opGas(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.push(interpreter.intPool.get().SetUint64(contract.Gas)) callContext.stack.push(interpreter.intPool.get().SetUint64(callContext.contract.Gas))
return nil, nil return nil, nil
} }
func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var ( var (
value = stack.pop() value = callContext.stack.pop()
offset, size = stack.pop(), stack.pop() offset, size = callContext.stack.pop(), callContext.stack.pop()
input = memory.GetCopy(offset.Int64(), size.Int64()) input = callContext.memory.GetCopy(offset.Int64(), size.Int64())
gas = contract.Gas gas = callContext.contract.Gas
) )
if interpreter.evm.chainRules.IsEIP150 { if interpreter.evm.chainRules.IsEIP150 {
gas -= gas / 64 gas -= gas / 64
} }
contract.UseGas(gas) callContext.contract.UseGas(gas)
res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value) res, addr, returnGas, suberr := interpreter.evm.Create(callContext.contract, input, gas, value)
// Push item on the stack based on the returned error. If the ruleset is // Push item on the stack based on the returned error. If the ruleset is
// homestead we must check for CodeStoreOutOfGasError (homestead only // homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must // rule) and treat as an error, if the ruleset is frontier we must
// ignore this error and pretend the operation was successful. // ignore this error and pretend the operation was successful.
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas { if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
stack.push(interpreter.intPool.getZero()) callContext.stack.push(interpreter.intPool.getZero())
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas { } else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
stack.push(interpreter.intPool.getZero()) callContext.stack.push(interpreter.intPool.getZero())
} else { } else {
stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) callContext.stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
} }
contract.Gas += returnGas callContext.contract.Gas += returnGas
interpreter.intPool.put(value, offset, size) interpreter.intPool.put(value, offset, size)
if suberr == errExecutionReverted { if suberr == errExecutionReverted {
...@@ -718,26 +718,26 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor ...@@ -718,26 +718,26 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
return nil, nil return nil, nil
} }
func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var ( var (
endowment = stack.pop() endowment = callContext.stack.pop()
offset, size = stack.pop(), stack.pop() offset, size = callContext.stack.pop(), callContext.stack.pop()
salt = stack.pop() salt = callContext.stack.pop()
input = memory.GetCopy(offset.Int64(), size.Int64()) input = callContext.memory.GetCopy(offset.Int64(), size.Int64())
gas = contract.Gas gas = callContext.contract.Gas
) )
// Apply EIP150 // Apply EIP150
gas -= gas / 64 gas -= gas / 64
contract.UseGas(gas) callContext.contract.UseGas(gas)
res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt) res, addr, returnGas, suberr := interpreter.evm.Create2(callContext.contract, input, gas, endowment, salt)
// Push item on the stack based on the returned error. // Push item on the stack based on the returned error.
if suberr != nil { if suberr != nil {
stack.push(interpreter.intPool.getZero()) callContext.stack.push(interpreter.intPool.getZero())
} else { } else {
stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) callContext.stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
} }
contract.Gas += returnGas callContext.contract.Gas += returnGas
interpreter.intPool.put(endowment, offset, size, salt) interpreter.intPool.put(endowment, offset, size, salt)
if suberr == errExecutionReverted { if suberr == errExecutionReverted {
...@@ -746,139 +746,139 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo ...@@ -746,139 +746,139 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
return nil, nil return nil, nil
} }
func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Pop gas. The actual gas in interpreter.evm.callGasTemp. // Pop gas. The actual gas in interpreter.evm.callGasTemp.
interpreter.intPool.put(stack.pop()) interpreter.intPool.putOne(callContext.stack.pop())
gas := interpreter.evm.callGasTemp gas := interpreter.evm.callGasTemp
// Pop other call parameters. // Pop other call parameters.
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() addr, value, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
toAddr := common.BigToAddress(addr) toAddr := common.BigToAddress(addr)
value = math.U256(value) value = math.U256(value)
// Get the arguments from the memory. // Get the arguments from the memory.
args := memory.GetPtr(inOffset.Int64(), inSize.Int64()) args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
if value.Sign() != 0 { if value.Sign() != 0 {
gas += params.CallStipend gas += params.CallStipend
} }
ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value) ret, returnGas, err := interpreter.evm.Call(callContext.contract, toAddr, args, gas, value)
if err != nil { if err != nil {
stack.push(interpreter.intPool.getZero()) callContext.stack.push(interpreter.intPool.getZero())
} else { } else {
stack.push(interpreter.intPool.get().SetUint64(1)) callContext.stack.push(interpreter.intPool.get().SetUint64(1))
} }
if err == nil || err == errExecutionReverted { if err == nil || err == errExecutionReverted {
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
} }
contract.Gas += returnGas callContext.contract.Gas += returnGas
interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
return ret, nil return ret, nil
} }
func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCallCode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Pop gas. The actual gas is in interpreter.evm.callGasTemp. // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
interpreter.intPool.put(stack.pop()) interpreter.intPool.putOne(callContext.stack.pop())
gas := interpreter.evm.callGasTemp gas := interpreter.evm.callGasTemp
// Pop other call parameters. // Pop other call parameters.
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() addr, value, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
toAddr := common.BigToAddress(addr) toAddr := common.BigToAddress(addr)
value = math.U256(value) value = math.U256(value)
// Get arguments from the memory. // Get arguments from the memory.
args := memory.GetPtr(inOffset.Int64(), inSize.Int64()) args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
if value.Sign() != 0 { if value.Sign() != 0 {
gas += params.CallStipend gas += params.CallStipend
} }
ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value) ret, returnGas, err := interpreter.evm.CallCode(callContext.contract, toAddr, args, gas, value)
if err != nil { if err != nil {
stack.push(interpreter.intPool.getZero()) callContext.stack.push(interpreter.intPool.getZero())
} else { } else {
stack.push(interpreter.intPool.get().SetUint64(1)) callContext.stack.push(interpreter.intPool.get().SetUint64(1))
} }
if err == nil || err == errExecutionReverted { if err == nil || err == errExecutionReverted {
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
} }
contract.Gas += returnGas callContext.contract.Gas += returnGas
interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
return ret, nil return ret, nil
} }
func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Pop gas. The actual gas is in interpreter.evm.callGasTemp. // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
interpreter.intPool.put(stack.pop()) interpreter.intPool.putOne(callContext.stack.pop())
gas := interpreter.evm.callGasTemp gas := interpreter.evm.callGasTemp
// Pop other call parameters. // Pop other call parameters.
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() addr, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
toAddr := common.BigToAddress(addr) toAddr := common.BigToAddress(addr)
// Get arguments from the memory. // Get arguments from the memory.
args := memory.GetPtr(inOffset.Int64(), inSize.Int64()) args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas) ret, returnGas, err := interpreter.evm.DelegateCall(callContext.contract, toAddr, args, gas)
if err != nil { if err != nil {
stack.push(interpreter.intPool.getZero()) callContext.stack.push(interpreter.intPool.getZero())
} else { } else {
stack.push(interpreter.intPool.get().SetUint64(1)) callContext.stack.push(interpreter.intPool.get().SetUint64(1))
} }
if err == nil || err == errExecutionReverted { if err == nil || err == errExecutionReverted {
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
} }
contract.Gas += returnGas callContext.contract.Gas += returnGas
interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
return ret, nil return ret, nil
} }
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opStaticCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
// Pop gas. The actual gas is in interpreter.evm.callGasTemp. // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
interpreter.intPool.put(stack.pop()) interpreter.intPool.putOne(callContext.stack.pop())
gas := interpreter.evm.callGasTemp gas := interpreter.evm.callGasTemp
// Pop other call parameters. // Pop other call parameters.
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() addr, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
toAddr := common.BigToAddress(addr) toAddr := common.BigToAddress(addr)
// Get arguments from the memory. // Get arguments from the memory.
args := memory.GetPtr(inOffset.Int64(), inSize.Int64()) args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas) ret, returnGas, err := interpreter.evm.StaticCall(callContext.contract, toAddr, args, gas)
if err != nil { if err != nil {
stack.push(interpreter.intPool.getZero()) callContext.stack.push(interpreter.intPool.getZero())
} else { } else {
stack.push(interpreter.intPool.get().SetUint64(1)) callContext.stack.push(interpreter.intPool.get().SetUint64(1))
} }
if err == nil || err == errExecutionReverted { if err == nil || err == errExecutionReverted {
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
} }
contract.Gas += returnGas callContext.contract.Gas += returnGas
interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
return ret, nil return ret, nil
} }
func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opReturn(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
offset, size := stack.pop(), stack.pop() offset, size := callContext.stack.pop(), callContext.stack.pop()
ret := memory.GetPtr(offset.Int64(), size.Int64()) ret := callContext.memory.GetPtr(offset.Int64(), size.Int64())
interpreter.intPool.put(offset, size) interpreter.intPool.put(offset, size)
return ret, nil return ret, nil
} }
func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opRevert(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
offset, size := stack.pop(), stack.pop() offset, size := callContext.stack.pop(), callContext.stack.pop()
ret := memory.GetPtr(offset.Int64(), size.Int64()) ret := callContext.memory.GetPtr(offset.Int64(), size.Int64())
interpreter.intPool.put(offset, size) interpreter.intPool.put(offset, size)
return ret, nil return ret, nil
} }
func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opStop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
return nil, nil return nil, nil
} }
func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
balance := interpreter.evm.StateDB.GetBalance(contract.Address()) balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address())
interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) interpreter.evm.StateDB.AddBalance(common.BigToAddress(callContext.stack.pop()), balance)
interpreter.evm.StateDB.Suicide(contract.Address()) interpreter.evm.StateDB.Suicide(callContext.contract.Address())
return nil, nil return nil, nil
} }
...@@ -886,16 +886,16 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo ...@@ -886,16 +886,16 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
// make log instruction function // make log instruction function
func makeLog(size int) executionFunc { func makeLog(size int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
topics := make([]common.Hash, size) topics := make([]common.Hash, size)
mStart, mSize := stack.pop(), stack.pop() mStart, mSize := callContext.stack.pop(), callContext.stack.pop()
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
topics[i] = common.BigToHash(stack.pop()) topics[i] = common.BigToHash(callContext.stack.pop())
} }
d := memory.GetCopy(mStart.Int64(), mSize.Int64()) d := callContext.memory.GetCopy(mStart.Int64(), mSize.Int64())
interpreter.evm.StateDB.AddLog(&types.Log{ interpreter.evm.StateDB.AddLog(&types.Log{
Address: contract.Address(), Address: callContext.contract.Address(),
Topics: topics, Topics: topics,
Data: d, Data: d,
// This is a non-consensus field, but assigned here because // This is a non-consensus field, but assigned here because
...@@ -909,24 +909,24 @@ func makeLog(size int) executionFunc { ...@@ -909,24 +909,24 @@ func makeLog(size int) executionFunc {
} }
// opPush1 is a specialized version of pushN // opPush1 is a specialized version of pushN
func opPush1(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opPush1(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
var ( var (
codeLen = uint64(len(contract.Code)) codeLen = uint64(len(callContext.contract.Code))
integer = interpreter.intPool.get() integer = interpreter.intPool.get()
) )
*pc += 1 *pc += 1
if *pc < codeLen { if *pc < codeLen {
stack.push(integer.SetUint64(uint64(contract.Code[*pc]))) callContext.stack.push(integer.SetUint64(uint64(callContext.contract.Code[*pc])))
} else { } else {
stack.push(integer.SetUint64(0)) callContext.stack.push(integer.SetUint64(0))
} }
return nil, nil return nil, nil
} }
// make push instruction function // make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc { func makePush(size uint64, pushByteSize int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
codeLen := len(contract.Code) codeLen := len(callContext.contract.Code)
startMin := codeLen startMin := codeLen
if int(*pc+1) < startMin { if int(*pc+1) < startMin {
...@@ -939,7 +939,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { ...@@ -939,7 +939,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
} }
integer := interpreter.intPool.get() integer := interpreter.intPool.get()
stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize))) callContext.stack.push(integer.SetBytes(common.RightPadBytes(callContext.contract.Code[startMin:endMin], pushByteSize)))
*pc += size *pc += size
return nil, nil return nil, nil
...@@ -948,8 +948,8 @@ func makePush(size uint64, pushByteSize int) executionFunc { ...@@ -948,8 +948,8 @@ func makePush(size uint64, pushByteSize int) executionFunc {
// make dup instruction function // make dup instruction function
func makeDup(size int64) executionFunc { func makeDup(size int64) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.dup(interpreter.intPool, int(size)) callContext.stack.dup(interpreter.intPool, int(size))
return nil, nil return nil, nil
} }
} }
...@@ -958,8 +958,8 @@ func makeDup(size int64) executionFunc { ...@@ -958,8 +958,8 @@ func makeDup(size int64) executionFunc {
func makeSwap(size int64) executionFunc { func makeSwap(size int64) executionFunc {
// switch n + 1 otherwise n would be swapped with n // switch n + 1 otherwise n would be swapped with n
size++ size++
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
stack.swap(int(size)) callContext.stack.swap(int(size))
return nil, nil return nil, nil
} }
} }
...@@ -109,7 +109,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu ...@@ -109,7 +109,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected)) expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
stack.push(x) stack.push(x)
stack.push(y) stack.push(y)
opFn(&pc, evmInterpreter, nil, nil, stack) opFn(&pc, evmInterpreter, &callCtx{nil, stack, nil})
actual := stack.pop() actual := stack.pop()
if actual.Cmp(expected) != 0 { if actual.Cmp(expected) != 0 {
...@@ -223,7 +223,7 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas ...@@ -223,7 +223,7 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas
y := new(big.Int).SetBytes(common.Hex2Bytes(param.y)) y := new(big.Int).SetBytes(common.Hex2Bytes(param.y))
stack.push(x) stack.push(x)
stack.push(y) stack.push(y)
opFn(&pc, interpreter, nil, nil, stack) opFn(&pc, interpreter, &callCtx{nil, stack, nil})
actual := stack.pop() actual := stack.pop()
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)} result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
} }
...@@ -260,7 +260,7 @@ func TestJsonTestcases(t *testing.T) { ...@@ -260,7 +260,7 @@ func TestJsonTestcases(t *testing.T) {
} }
} }
func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) { func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
...@@ -281,7 +281,7 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpret ...@@ -281,7 +281,7 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpret
a := new(big.Int).SetBytes(arg) a := new(big.Int).SetBytes(arg)
stack.push(a) stack.push(a)
} }
op(&pc, evmInterpreter, nil, nil, stack) op(&pc, evmInterpreter, &callCtx{nil, stack, nil})
stack.pop() stack.pop()
} }
poolOfIntPools.put(evmInterpreter.intPool) poolOfIntPools.put(evmInterpreter.intPool)
...@@ -509,12 +509,12 @@ func TestOpMstore(t *testing.T) { ...@@ -509,12 +509,12 @@ func TestOpMstore(t *testing.T) {
pc := uint64(0) pc := uint64(0)
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0)) stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0))
opMstore(&pc, evmInterpreter, nil, mem, stack) opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v { if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
t.Fatalf("Mstore fail, got %v, expected %v", got, v) t.Fatalf("Mstore fail, got %v, expected %v", got, v)
} }
stack.pushN(big.NewInt(0x1), big.NewInt(0)) stack.pushN(big.NewInt(0x1), big.NewInt(0))
opMstore(&pc, evmInterpreter, nil, mem, stack) opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
t.Fatalf("Mstore failed to overwrite previous value") t.Fatalf("Mstore failed to overwrite previous value")
} }
...@@ -539,7 +539,7 @@ func BenchmarkOpMstore(bench *testing.B) { ...@@ -539,7 +539,7 @@ func BenchmarkOpMstore(bench *testing.B) {
bench.ResetTimer() bench.ResetTimer()
for i := 0; i < bench.N; i++ { for i := 0; i < bench.N; i++ {
stack.pushN(value, memStart) stack.pushN(value, memStart)
opMstore(&pc, evmInterpreter, nil, mem, stack) opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
} }
poolOfIntPools.put(evmInterpreter.intPool) poolOfIntPools.put(evmInterpreter.intPool)
} }
...@@ -560,7 +560,7 @@ func BenchmarkOpSHA3(bench *testing.B) { ...@@ -560,7 +560,7 @@ func BenchmarkOpSHA3(bench *testing.B) {
bench.ResetTimer() bench.ResetTimer()
for i := 0; i < bench.N; i++ { for i := 0; i < bench.N; i++ {
stack.pushN(big.NewInt(32), start) stack.pushN(big.NewInt(32), start)
opSha3(&pc, evmInterpreter, nil, mem, stack) opSha3(&pc, evmInterpreter, &callCtx{mem, stack, nil})
} }
poolOfIntPools.put(evmInterpreter.intPool) poolOfIntPools.put(evmInterpreter.intPool)
} }
......
...@@ -63,6 +63,14 @@ type Interpreter interface { ...@@ -63,6 +63,14 @@ type Interpreter interface {
CanRun([]byte) bool CanRun([]byte) bool
} }
// callCtx contains the things that are per-call, such as stack and memory,
// but not transients like pc and gas
type callCtx struct {
memory *Memory
stack *Stack
contract *Contract
}
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
// Read to get a variable amount of data from the hash state. Read is faster than Sum // Read to get a variable amount of data from the hash state. Read is faster than Sum
// because it doesn't copy the internal state, but also modifies the internal state. // because it doesn't copy the internal state, but also modifies the internal state.
...@@ -163,6 +171,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( ...@@ -163,6 +171,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
op OpCode // current opcode op OpCode // current opcode
mem = NewMemory() // bound memory mem = NewMemory() // bound memory
stack = newstack() // local stack stack = newstack() // local stack
callContext = &callCtx{
memory: mem,
stack: stack,
contract: contract,
}
// For optimisation reason we're using uint64 as the program counter. // For optimisation reason we're using uint64 as the program counter.
// It's theoretically possible to go above 2^64. The YP defines the PC // It's theoretically possible to go above 2^64. The YP defines the PC
// to be uint256. Practically much less so feasible. // to be uint256. Practically much less so feasible.
...@@ -194,7 +207,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( ...@@ -194,7 +207,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during // 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 // the execution of one of the operations or until the done flag is set by the
// parent context. // parent context.
for atomic.LoadInt32(&in.evm.abort) == 0 { steps := 0
for {
steps++
if steps%1000 == 0 && atomic.LoadInt32(&in.evm.abort) != 0 {
break
}
if in.cfg.Debug { if in.cfg.Debug {
// Capture pre-execution values for tracing. // Capture pre-execution values for tracing.
logged, pcCopy, gasCopy = false, pc, contract.Gas logged, pcCopy, gasCopy = false, pc, contract.Gas
...@@ -267,7 +285,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( ...@@ -267,7 +285,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
} }
// execute the operation // execute the operation
res, err = operation.execute(&pc, in, contract, mem, stack) res, err = operation.execute(&pc, in, callContext)
// verifyPool is a build flag. Pool verification makes sure the integrity // verifyPool is a build flag. Pool verification makes sure the integrity
// of the integer pool by comparing values to a default value. // of the integer pool by comparing values to a default value.
if verifyPool { if verifyPool {
......
...@@ -53,6 +53,17 @@ func (p *intPool) getZero() *big.Int { ...@@ -53,6 +53,17 @@ func (p *intPool) getZero() *big.Int {
return new(big.Int) return new(big.Int)
} }
// putOne returns an allocated big int to the pool to be later reused by get calls.
// Note, the values as saved as is; neither put nor get zeroes the ints out!
// As opposed to 'put' with variadic args, this method becomes inlined by the
// go compiler
func (p *intPool) putOne(i *big.Int) {
if len(p.pool.data) > poolLimit {
return
}
p.pool.push(i)
}
// put returns an allocated big int to the pool to be later reused by get calls. // put returns an allocated big int to the pool to be later reused by get calls.
// Note, the values as saved as is; neither put nor get zeroes the ints out! // Note, the values as saved as is; neither put nor get zeroes the ints out!
func (p *intPool) put(is ...*big.Int) { func (p *intPool) put(is ...*big.Int) {
......
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
) )
type ( type (
executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error)
gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
// memorySizeFunc returns the required size, and whether the operation overflowed a uint64 // memorySizeFunc returns the required size, and whether the operation overflowed a uint64
memorySizeFunc func(*Stack) (size uint64, overflow bool) memorySizeFunc func(*Stack) (size uint64, overflow bool)
......
...@@ -316,3 +316,31 @@ func TestBlockhash(t *testing.T) { ...@@ -316,3 +316,31 @@ func TestBlockhash(t *testing.T) {
t.Errorf("suboptimal; too much chain iteration, expected %d, got %d", exp, got) t.Errorf("suboptimal; too much chain iteration, expected %d, got %d", exp, got)
} }
} }
// BenchmarkSimpleLoop test a pretty simple loop which loops
// 1M (1 048 575) times.
// Takes about 200 ms
func BenchmarkSimpleLoop(b *testing.B) {
// 0xfffff = 1048575 loops
code := []byte{
byte(vm.PUSH3), 0x0f, 0xff, 0xff,
byte(vm.JUMPDEST), // [ count ]
byte(vm.PUSH1), 1, // [count, 1]
byte(vm.SWAP1), // [1, count]
byte(vm.SUB), // [ count -1 ]
byte(vm.DUP1), // [ count -1 , count-1]
byte(vm.PUSH1), 4, // [count-1, count -1, label]
byte(vm.JUMPI), // [ 0 ]
byte(vm.STOP),
}
//tracer := vm.NewJSONLogger(nil, os.Stdout)
//Execute(code, nil, &Config{
// EVMConfig: vm.Config{
// Debug: true,
// Tracer: tracer,
// }})
for i := 0; i < b.N; i++ {
Execute(code, nil, nil)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment