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) {
}
}
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address()))
stack.push(balance)
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
callContext.stack.push(balance)
return nil, nil
}
......@@ -80,9 +80,9 @@ func enable1344(jt *JumpTable) {
}
// 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)
stack.push(chainId)
callContext.stack.push(chainId)
return nil, nil
}
......
......@@ -37,48 +37,48 @@ var (
errInvalidJump = errors.New("evm: invalid jump destination")
)
func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opAdd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
math.U256(y.Add(x, y))
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opSub(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
math.U256(y.Sub(x, y))
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
stack.push(math.U256(x.Mul(x, y)))
func opMul(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.pop()
callContext.stack.push(math.U256(x.Mul(x, y)))
interpreter.intPool.put(y)
interpreter.intPool.putOne(y)
return nil, nil
}
func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opDiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
if y.Sign() != 0 {
math.U256(y.Div(x, y))
} else {
y.SetUint64(0)
}
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop())
func opSdiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := math.S256(callContext.stack.pop()), math.S256(callContext.stack.pop())
res := interpreter.intPool.getZero()
if y.Sign() == 0 || x.Sign() == 0 {
stack.push(res)
callContext.stack.push(res)
} else {
if x.Sign() != y.Sign() {
res.Div(x.Abs(x), y.Abs(y))
......@@ -86,29 +86,29 @@ func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
} else {
res.Div(x.Abs(x), y.Abs(y))
}
stack.push(math.U256(res))
callContext.stack.push(math.U256(res))
}
interpreter.intPool.put(x, y)
return nil, nil
}
func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
func opMod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.pop()
if y.Sign() == 0 {
stack.push(x.SetUint64(0))
callContext.stack.push(x.SetUint64(0))
} 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
}
func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop())
func opSmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := math.S256(callContext.stack.pop()), math.S256(callContext.stack.pop())
res := interpreter.intPool.getZero()
if y.Sign() == 0 {
stack.push(res)
callContext.stack.push(res)
} else {
if x.Sign() < 0 {
res.Mod(x.Abs(x), y.Abs(y))
......@@ -116,38 +116,38 @@ func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
} else {
res.Mod(x.Abs(x), y.Abs(y))
}
stack.push(math.U256(res))
callContext.stack.push(math.U256(res))
}
interpreter.intPool.put(x, y)
return nil, nil
}
func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
base, exponent := stack.pop(), stack.pop()
func opExp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
base, exponent := callContext.stack.pop(), callContext.stack.pop()
// some shortcuts
cmpToOne := exponent.Cmp(big1)
if cmpToOne < 0 { // Exponent is zero
// x ^ 0 == 1
stack.push(base.SetUint64(1))
callContext.stack.push(base.SetUint64(1))
} else if base.Sign() == 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
// x ^ 1 == x
stack.push(base)
callContext.stack.push(base)
} else {
stack.push(math.Exp(base, exponent))
interpreter.intPool.put(base)
callContext.stack.push(math.Exp(base, exponent))
interpreter.intPool.putOne(base)
}
interpreter.intPool.put(exponent)
interpreter.intPool.putOne(exponent)
return nil, nil
}
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
back := stack.pop()
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
back := callContext.stack.pop()
if back.Cmp(big.NewInt(31)) < 0 {
bit := uint(back.Uint64()*8 + 7)
num := stack.pop()
num := callContext.stack.pop()
mask := back.Lsh(common.Big1, bit)
mask.Sub(mask, common.Big1)
if num.Bit(int(bit)) > 0 {
......@@ -156,43 +156,43 @@ func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m
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
}
func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x := stack.peek()
func opNot(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x := callContext.stack.peek()
math.U256(x.Not(x))
return nil, nil
}
func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opLt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
if x.Cmp(y) < 0 {
y.SetUint64(1)
} else {
y.SetUint64(0)
}
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opGt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
if x.Cmp(y) > 0 {
y.SetUint64(1)
} else {
y.SetUint64(0)
}
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opSlt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
xSign := x.Cmp(tt255)
ySign := y.Cmp(tt255)
......@@ -211,12 +211,12 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
y.SetUint64(0)
}
}
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opSgt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
xSign := x.Cmp(tt255)
ySign := y.Cmp(tt255)
......@@ -235,23 +235,23 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
y.SetUint64(0)
}
}
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opEq(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
if x.Cmp(y) == 0 {
y.SetUint64(1)
} else {
y.SetUint64(0)
}
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x := stack.peek()
func opIszero(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x := callContext.stack.peek()
if x.Sign() > 0 {
x.SetUint64(0)
} else {
......@@ -260,63 +260,63 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
return nil, nil
}
func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
stack.push(x.And(x, y))
func opAnd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.pop()
callContext.stack.push(x.And(x, y))
interpreter.intPool.put(y)
interpreter.intPool.putOne(y)
return nil, nil
}
func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opOr(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
y.Or(x, y)
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.peek()
func opXor(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y := callContext.stack.pop(), callContext.stack.peek()
y.Xor(x, y)
interpreter.intPool.put(x)
interpreter.intPool.putOne(x)
return nil, nil
}
func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
th, val := stack.pop(), stack.peek()
func opByte(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
th, val := callContext.stack.pop(), callContext.stack.peek()
if th.Cmp(common.Big32) < 0 {
b := math.Byte(val, 32, int(th.Int64()))
val.SetUint64(uint64(b))
} else {
val.SetUint64(0)
}
interpreter.intPool.put(th)
interpreter.intPool.putOne(th)
return nil, nil
}
func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y, z := stack.pop(), stack.pop(), stack.pop()
func opAddmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
if z.Cmp(bigZero) > 0 {
x.Add(x, y)
x.Mod(x, z)
stack.push(math.U256(x))
callContext.stack.push(math.U256(x))
} else {
stack.push(x.SetUint64(0))
callContext.stack.push(x.SetUint64(0))
}
interpreter.intPool.put(y, z)
return nil, nil
}
func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y, z := stack.pop(), stack.pop(), stack.pop()
func opMulmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop()
if z.Cmp(bigZero) > 0 {
x.Mul(x, y)
x.Mod(x, z)
stack.push(math.U256(x))
callContext.stack.push(math.U256(x))
} else {
stack.push(x.SetUint64(0))
callContext.stack.push(x.SetUint64(0))
}
interpreter.intPool.put(y, z)
return nil, nil
......@@ -325,10 +325,10 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
// opSHL implements Shift Left
// 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.
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
shift, value := math.U256(stack.pop()), math.U256(stack.peek())
defer interpreter.intPool.put(shift) // First operand back into the pool
shift, value := math.U256(callContext.stack.pop()), math.U256(callContext.stack.peek())
defer interpreter.intPool.putOne(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 {
value.SetUint64(0)
......@@ -343,10 +343,10 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
// opSHR implements Logical Shift Right
// 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.
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
shift, value := math.U256(stack.pop()), math.U256(stack.peek())
defer interpreter.intPool.put(shift) // First operand back into the pool
shift, value := math.U256(callContext.stack.pop()), math.U256(callContext.stack.peek())
defer interpreter.intPool.putOne(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 {
value.SetUint64(0)
......@@ -361,10 +361,10 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
// opSAR implements Arithmetic Shift Right
// 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.
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
shift, value := math.U256(stack.pop()), math.S256(stack.pop())
defer interpreter.intPool.put(shift) // First operand back into the pool
shift, value := math.U256(callContext.stack.pop()), math.S256(callContext.stack.pop())
defer interpreter.intPool.putOne(shift) // First operand back into the pool
if shift.Cmp(common.Big256) >= 0 {
if value.Sign() >= 0 {
......@@ -372,19 +372,19 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
} else {
value.SetInt64(-1)
}
stack.push(math.U256(value))
callContext.stack.push(math.U256(value))
return nil, nil
}
n := uint(shift.Uint64())
value.Rsh(value, n)
stack.push(math.U256(value))
callContext.stack.push(math.U256(value))
return nil, nil
}
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset, size := stack.pop(), stack.pop()
data := memory.GetPtr(offset.Int64(), size.Int64())
func opSha3(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
offset, size := callContext.stack.pop(), callContext.stack.pop()
data := callContext.memory.GetPtr(offset.Int64(), size.Int64())
if interpreter.hasher == nil {
interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
......@@ -398,70 +398,70 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
if evm.vmConfig.EnablePreimageRecording {
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)
return nil, nil
}
func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(contract.Address().Bytes()))
func opAddress(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetBytes(callContext.contract.Address().Bytes()))
return nil, nil
}
func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
slot := stack.peek()
func opBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := callContext.stack.peek()
slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot)))
return nil, nil
}
func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes()))
func opOrigin(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes()))
return nil, nil
}
func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(contract.Caller().Bytes()))
func opCaller(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetBytes(callContext.contract.Caller().Bytes()))
return nil, nil
}
func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().Set(contract.value))
func opCallValue(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().Set(callContext.contract.value))
return nil, nil
}
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetBytes(getDataBig(callContext.contract.Input, callContext.stack.pop(), big32)))
return nil, nil
}
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetInt64(int64(len(contract.Input))))
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetInt64(int64(len(callContext.contract.Input))))
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 (
memOffset = stack.pop()
dataOffset = stack.pop()
length = stack.pop()
memOffset = callContext.stack.pop()
dataOffset = callContext.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)
return nil, nil
}
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData))))
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData))))
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 (
memOffset = stack.pop()
dataOffset = stack.pop()
length = stack.pop()
memOffset = callContext.stack.pop()
dataOffset = callContext.stack.pop()
length = callContext.stack.pop()
end = interpreter.intPool.get().Add(dataOffset, length)
)
......@@ -470,47 +470,47 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac
if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() {
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
}
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
slot := stack.peek()
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := callContext.stack.peek()
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
return nil, nil
}
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
l := interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
stack.push(l)
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
l := interpreter.intPool.get().SetInt64(int64(len(callContext.contract.Code)))
callContext.stack.push(l)
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 (
memOffset = stack.pop()
codeOffset = stack.pop()
length = stack.pop()
memOffset = callContext.stack.pop()
codeOffset = callContext.stack.pop()
length = callContext.stack.pop()
)
codeCopy := getDataBig(contract.Code, codeOffset, length)
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
codeCopy := getDataBig(callContext.contract.Code, codeOffset, length)
callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
interpreter.intPool.put(memOffset, codeOffset, length)
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 (
addr = common.BigToAddress(stack.pop())
memOffset = stack.pop()
codeOffset = stack.pop()
length = stack.pop()
addr = common.BigToAddress(callContext.stack.pop())
memOffset = callContext.stack.pop()
codeOffset = callContext.stack.pop()
length = callContext.stack.pop()
)
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)
return nil, nil
......@@ -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,
// 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) {
slot := stack.peek()
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
slot := callContext.stack.peek()
address := common.BigToAddress(slot)
if interpreter.evm.StateDB.Empty(address) {
slot.SetUint64(0)
......@@ -553,108 +553,108 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
return nil, nil
}
func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice))
func opGasprice(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice))
return nil, nil
}
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
num := stack.pop()
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
num := callContext.stack.pop()
n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257)
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 {
stack.push(interpreter.intPool.getZero())
callContext.stack.push(interpreter.intPool.getZero())
}
interpreter.intPool.put(num, n)
return nil, nil
}
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes()))
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes()))
return nil, nil
}
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time)))
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time)))
return nil, nil
}
func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber)))
func opNumber(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber)))
return nil, nil
}
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty)))
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty)))
return nil, nil
}
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit)))
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit)))
return nil, nil
}
func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
interpreter.intPool.put(stack.pop())
func opPop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
interpreter.intPool.putOne(callContext.stack.pop())
return nil, nil
}
func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
v := stack.peek()
func opMload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
v := callContext.stack.peek()
offset := v.Int64()
v.SetBytes(memory.GetPtr(offset, 32))
v.SetBytes(callContext.memory.GetPtr(offset, 32))
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
mStart, val := stack.pop(), stack.pop()
memory.Set32(mStart.Uint64(), val)
mStart, val := callContext.stack.pop(), callContext.stack.pop()
callContext.memory.Set32(mStart.Uint64(), val)
interpreter.intPool.put(mStart, val)
return nil, nil
}
func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
off, val := stack.pop().Int64(), stack.pop().Int64()
memory.store[off] = byte(val & 0xff)
func opMstore8(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
off, val := callContext.stack.pop().Int64(), callContext.stack.pop().Int64()
callContext.memory.store[off] = byte(val & 0xff)
return nil, nil
}
func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
loc := stack.peek()
val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))
func opSload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
loc := callContext.stack.peek()
val := interpreter.evm.StateDB.GetState(callContext.contract.Address(), common.BigToHash(loc))
loc.SetBytes(val.Bytes())
return nil, nil
}
func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
loc := common.BigToHash(stack.pop())
val := stack.pop()
interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
func opSstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
loc := common.BigToHash(callContext.stack.pop())
val := callContext.stack.pop()
interpreter.evm.StateDB.SetState(callContext.contract.Address(), loc, common.BigToHash(val))
interpreter.intPool.put(val)
interpreter.intPool.putOne(val)
return nil, nil
}
func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
pos := stack.pop()
if !contract.validJumpdest(pos) {
func opJump(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
pos := callContext.stack.pop()
if !callContext.contract.validJumpdest(pos) {
return nil, errInvalidJump
}
*pc = pos.Uint64()
interpreter.intPool.put(pos)
interpreter.intPool.putOne(pos)
return nil, nil
}
func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
pos, cond := stack.pop(), stack.pop()
func opJumpi(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
pos, cond := callContext.stack.pop(), callContext.stack.pop()
if cond.Sign() != 0 {
if !contract.validJumpdest(pos) {
if !callContext.contract.validJumpdest(pos) {
return nil, errInvalidJump
}
*pc = pos.Uint64()
......@@ -666,50 +666,50 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
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
}
func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetUint64(*pc))
func opPc(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetUint64(*pc))
return nil, nil
}
func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetInt64(int64(memory.Len())))
func opMsize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetInt64(int64(callContext.memory.Len())))
return nil, nil
}
func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.intPool.get().SetUint64(contract.Gas))
func opGas(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(interpreter.intPool.get().SetUint64(callContext.contract.Gas))
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 (
value = stack.pop()
offset, size = stack.pop(), stack.pop()
input = memory.GetCopy(offset.Int64(), size.Int64())
gas = contract.Gas
value = callContext.stack.pop()
offset, size = callContext.stack.pop(), callContext.stack.pop()
input = callContext.memory.GetCopy(offset.Int64(), size.Int64())
gas = callContext.contract.Gas
)
if interpreter.evm.chainRules.IsEIP150 {
gas -= gas / 64
}
contract.UseGas(gas)
res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value)
callContext.contract.UseGas(gas)
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
// homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must
// ignore this error and pretend the operation was successful.
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
stack.push(interpreter.intPool.getZero())
callContext.stack.push(interpreter.intPool.getZero())
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
stack.push(interpreter.intPool.getZero())
callContext.stack.push(interpreter.intPool.getZero())
} 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)
if suberr == errExecutionReverted {
......@@ -718,26 +718,26 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
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 (
endowment = stack.pop()
offset, size = stack.pop(), stack.pop()
salt = stack.pop()
input = memory.GetCopy(offset.Int64(), size.Int64())
gas = contract.Gas
endowment = callContext.stack.pop()
offset, size = callContext.stack.pop(), callContext.stack.pop()
salt = callContext.stack.pop()
input = callContext.memory.GetCopy(offset.Int64(), size.Int64())
gas = callContext.contract.Gas
)
// Apply EIP150
gas -= gas / 64
contract.UseGas(gas)
res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt)
callContext.contract.UseGas(gas)
res, addr, returnGas, suberr := interpreter.evm.Create2(callContext.contract, input, gas, endowment, salt)
// Push item on the stack based on the returned error.
if suberr != nil {
stack.push(interpreter.intPool.getZero())
callContext.stack.push(interpreter.intPool.getZero())
} 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)
if suberr == errExecutionReverted {
......@@ -746,139 +746,139 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
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.
interpreter.intPool.put(stack.pop())
interpreter.intPool.putOne(callContext.stack.pop())
gas := interpreter.evm.callGasTemp
// 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)
value = math.U256(value)
// 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 {
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 {
stack.push(interpreter.intPool.getZero())
callContext.stack.push(interpreter.intPool.getZero())
} else {
stack.push(interpreter.intPool.get().SetUint64(1))
callContext.stack.push(interpreter.intPool.get().SetUint64(1))
}
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)
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.
interpreter.intPool.put(stack.pop())
interpreter.intPool.putOne(callContext.stack.pop())
gas := interpreter.evm.callGasTemp
// 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)
value = math.U256(value)
// Get arguments from the memory.
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64())
if value.Sign() != 0 {
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 {
stack.push(interpreter.intPool.getZero())
callContext.stack.push(interpreter.intPool.getZero())
} else {
stack.push(interpreter.intPool.get().SetUint64(1))
callContext.stack.push(interpreter.intPool.get().SetUint64(1))
}
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)
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.
interpreter.intPool.put(stack.pop())
interpreter.intPool.putOne(callContext.stack.pop())
gas := interpreter.evm.callGasTemp
// 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)
// 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 {
stack.push(interpreter.intPool.getZero())
callContext.stack.push(interpreter.intPool.getZero())
} else {
stack.push(interpreter.intPool.get().SetUint64(1))
callContext.stack.push(interpreter.intPool.get().SetUint64(1))
}
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)
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.
interpreter.intPool.put(stack.pop())
interpreter.intPool.putOne(callContext.stack.pop())
gas := interpreter.evm.callGasTemp
// 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)
// 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 {
stack.push(interpreter.intPool.getZero())
callContext.stack.push(interpreter.intPool.getZero())
} else {
stack.push(interpreter.intPool.get().SetUint64(1))
callContext.stack.push(interpreter.intPool.get().SetUint64(1))
}
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)
return ret, nil
}
func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset, size := stack.pop(), stack.pop()
ret := memory.GetPtr(offset.Int64(), size.Int64())
func opReturn(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
offset, size := callContext.stack.pop(), callContext.stack.pop()
ret := callContext.memory.GetPtr(offset.Int64(), size.Int64())
interpreter.intPool.put(offset, size)
return ret, nil
}
func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset, size := stack.pop(), stack.pop()
ret := memory.GetPtr(offset.Int64(), size.Int64())
func opRevert(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
offset, size := callContext.stack.pop(), callContext.stack.pop()
ret := callContext.memory.GetPtr(offset.Int64(), size.Int64())
interpreter.intPool.put(offset, size)
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
}
func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
balance := interpreter.evm.StateDB.GetBalance(contract.Address())
interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address())
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
}
......@@ -886,16 +886,16 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
// make log instruction function
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)
mStart, mSize := stack.pop(), stack.pop()
mStart, mSize := callContext.stack.pop(), callContext.stack.pop()
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{
Address: contract.Address(),
Address: callContext.contract.Address(),
Topics: topics,
Data: d,
// This is a non-consensus field, but assigned here because
......@@ -909,24 +909,24 @@ func makeLog(size int) executionFunc {
}
// 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 (
codeLen = uint64(len(contract.Code))
codeLen = uint64(len(callContext.contract.Code))
integer = interpreter.intPool.get()
)
*pc += 1
if *pc < codeLen {
stack.push(integer.SetUint64(uint64(contract.Code[*pc])))
callContext.stack.push(integer.SetUint64(uint64(callContext.contract.Code[*pc])))
} else {
stack.push(integer.SetUint64(0))
callContext.stack.push(integer.SetUint64(0))
}
return nil, nil
}
// make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
codeLen := len(contract.Code)
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
codeLen := len(callContext.contract.Code)
startMin := codeLen
if int(*pc+1) < startMin {
......@@ -939,7 +939,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
}
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
return nil, nil
......@@ -948,8 +948,8 @@ func makePush(size uint64, pushByteSize int) executionFunc {
// make dup instruction function
func makeDup(size int64) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.dup(interpreter.intPool, int(size))
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.dup(interpreter.intPool, int(size))
return nil, nil
}
}
......@@ -958,8 +958,8 @@ func makeDup(size int64) executionFunc {
func makeSwap(size int64) executionFunc {
// switch n + 1 otherwise n would be swapped with n
size++
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.swap(int(size))
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.swap(int(size))
return nil, nil
}
}
......@@ -109,7 +109,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
stack.push(x)
stack.push(y)
opFn(&pc, evmInterpreter, nil, nil, stack)
opFn(&pc, evmInterpreter, &callCtx{nil, stack, nil})
actual := stack.pop()
if actual.Cmp(expected) != 0 {
......@@ -223,7 +223,7 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas
y := new(big.Int).SetBytes(common.Hex2Bytes(param.y))
stack.push(x)
stack.push(y)
opFn(&pc, interpreter, nil, nil, stack)
opFn(&pc, interpreter, &callCtx{nil, stack, nil})
actual := stack.pop()
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
}
......@@ -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 (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack()
......@@ -281,7 +281,7 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpret
a := new(big.Int).SetBytes(arg)
stack.push(a)
}
op(&pc, evmInterpreter, nil, nil, stack)
op(&pc, evmInterpreter, &callCtx{nil, stack, nil})
stack.pop()
}
poolOfIntPools.put(evmInterpreter.intPool)
......@@ -509,12 +509,12 @@ func TestOpMstore(t *testing.T) {
pc := uint64(0)
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
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 {
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
}
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" {
t.Fatalf("Mstore failed to overwrite previous value")
}
......@@ -539,7 +539,7 @@ func BenchmarkOpMstore(bench *testing.B) {
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
stack.pushN(value, memStart)
opMstore(&pc, evmInterpreter, nil, mem, stack)
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
}
poolOfIntPools.put(evmInterpreter.intPool)
}
......@@ -560,7 +560,7 @@ func BenchmarkOpSHA3(bench *testing.B) {
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
stack.pushN(big.NewInt(32), start)
opSha3(&pc, evmInterpreter, nil, mem, stack)
opSha3(&pc, evmInterpreter, &callCtx{mem, stack, nil})
}
poolOfIntPools.put(evmInterpreter.intPool)
}
......
......@@ -63,6 +63,14 @@ type Interpreter interface {
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
// 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.
......@@ -160,9 +168,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
var (
op OpCode // current opcode
mem = NewMemory() // bound memory
stack = newstack() // local stack
op OpCode // current opcode
mem = NewMemory() // bound memory
stack = newstack() // local stack
callContext = &callCtx{
memory: mem,
stack: stack,
contract: contract,
}
// 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
// to be uint256. Practically much less so feasible.
......@@ -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
// the execution of one of the operations or until the done flag is set by the
// 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 {
// Capture pre-execution values for tracing.
logged, pcCopy, gasCopy = false, pc, contract.Gas
......@@ -267,7 +285,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
// 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
// of the integer pool by comparing values to a default value.
if verifyPool {
......
......@@ -53,6 +53,17 @@ func (p *intPool) getZero() *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.
// Note, the values as saved as is; neither put nor get zeroes the ints out!
func (p *intPool) put(is ...*big.Int) {
......
......@@ -23,7 +23,7 @@ import (
)
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
// memorySizeFunc returns the required size, and whether the operation overflowed a uint64
memorySizeFunc func(*Stack) (size uint64, overflow bool)
......
......@@ -316,3 +316,31 @@ func TestBlockhash(t *testing.T) {
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