aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/vm/instructions.go82
-rw-r--r--core/vm/jit.go82
2 files changed, 88 insertions, 76 deletions
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 6c6039f74..5dcab6e08 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -17,6 +17,7 @@
package vm
import (
+ "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -25,16 +26,16 @@ import (
)
type programInstruction interface {
- Do(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack)
+ // executes the program instruction and allows the instruction to modify the state of the program
+ do(program *Program, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) ([]byte, error)
+ // returns whether the program instruction halts the execution of the JIT
+ halts() bool
+ // Returns the current op code (debugging purposes)
+ Op() OpCode
}
type instrFn func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack)
-// Do executes the function. This implements programInstruction
-func (fn instrFn) Do(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
- fn(instr, pc, env, contract, memory, stack)
-}
-
type instruction struct {
op OpCode
pc uint64
@@ -44,6 +45,73 @@ type instruction struct {
gas *big.Int
spop int
spush int
+
+ returns bool
+}
+
+func jump(mapping map[uint64]uint64, destinations map[uint64]struct{}, contract *Contract, to *big.Int) (uint64, error) {
+ if !validDest(destinations, to) {
+ nop := contract.GetOp(to.Uint64())
+ return 0, fmt.Errorf("invalid jump destination (%v) %v", nop, to)
+ }
+
+ return mapping[to.Uint64()], nil
+}
+
+func (instr instruction) do(program *Program, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) ([]byte, error) {
+ // calculate the new memory size and gas price for the current executing opcode
+ newMemSize, cost, err := jitCalculateGasAndSize(env, contract, instr, env.Db(), memory, stack)
+ if err != nil {
+ return nil, err
+ }
+
+ // Use the calculated gas. When insufficient gas is present, use all gas and return an
+ // Out Of Gas error
+ if !contract.UseGas(cost) {
+ return nil, OutOfGasError
+ }
+ // Resize the memory calculated previously
+ memory.Resize(newMemSize.Uint64())
+
+ // These opcodes return an argument and are thefor handled
+ // differently from the rest of the opcodes
+ switch instr.op {
+ case JUMP:
+ if pos, err := jump(program.mapping, program.destinations, contract, stack.pop()); err != nil {
+ return nil, err
+ } else {
+ *pc = pos
+ return nil, nil
+ }
+ case JUMPI:
+ pos, cond := stack.pop(), stack.pop()
+ if cond.Cmp(common.BigTrue) >= 0 {
+ if pos, err := jump(program.mapping, program.destinations, contract, pos); err != nil {
+ return nil, err
+ } else {
+ *pc = pos
+ return nil, nil
+ }
+ }
+ case RETURN:
+ offset, size := stack.pop(), stack.pop()
+ return memory.GetPtr(offset.Int64(), size.Int64()), nil
+ default:
+ if instr.fn == nil {
+ return nil, fmt.Errorf("Invalid opcode 0x%x", instr.op)
+ }
+ instr.fn(instr, pc, env, contract, memory, stack)
+ }
+ *pc++
+ return nil, nil
+}
+
+func (instr instruction) halts() bool {
+ return instr.returns
+}
+
+func (instr instruction) Op() OpCode {
+ return instr.op
}
func opStaticJump(instr instruction, pc *uint64, ret *big.Int, env Environment, contract *Contract, memory *Memory, stack *stack) {
@@ -536,8 +604,6 @@ func opStop(instr instruction, pc *uint64, env Environment, contract *Contract,
}
func opSuicide(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) {
- //receiver := env.Db().GetOrNewStateObject(common.BigToAddress(stack.pop()))
- //receiver.AddBalance(balance)
balance := env.Db().GetBalance(contract.Address())
env.Db().AddBalance(common.BigToAddress(stack.pop()), balance)
diff --git a/core/vm/jit.go b/core/vm/jit.go
index 6ad574917..8cb95b860 100644
--- a/core/vm/jit.go
+++ b/core/vm/jit.go
@@ -86,9 +86,9 @@ type Program struct {
contract *Contract
- instructions []instruction // instruction set
- mapping map[uint64]int // real PC mapping to array indices
- destinations map[uint64]struct{} // cached jump destinations
+ instructions []programInstruction // instruction set
+ mapping map[uint64]uint64 // real PC mapping to array indices
+ destinations map[uint64]struct{} // cached jump destinations
code []byte
}
@@ -97,7 +97,7 @@ type Program struct {
func NewProgram(code []byte) *Program {
program := &Program{
Id: crypto.Sha3Hash(code),
- mapping: make(map[uint64]int),
+ mapping: make(map[uint64]uint64),
destinations: make(map[uint64]struct{}),
code: code,
}
@@ -118,10 +118,12 @@ func (p *Program) addInstr(op OpCode, pc uint64, fn instrFn, data *big.Int) {
baseOp = DUP1
}
base := _baseCheck[baseOp]
- instr := instruction{op, pc, fn, data, base.gas, base.stackPop, base.stackPush}
+
+ returns := op == RETURN || op == SUICIDE || op == STOP
+ instr := instruction{op, pc, fn, data, base.gas, base.stackPop, base.stackPush, returns}
p.instructions = append(p.instructions, instr)
- p.mapping[pc] = len(p.instructions) - 1
+ p.mapping[pc] = uint64(len(p.instructions) - 1)
}
// CompileProgram compiles the given program and return an error when it fails
@@ -301,21 +303,8 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env
contract.Input = input
var (
- caller = contract.caller
- statedb = env.Db()
- pc int = program.mapping[pcstart]
- instrCount = 0
-
- jump = func(to *big.Int) error {
- if !validDest(program.destinations, to) {
- nop := contract.GetOp(to.Uint64())
- return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
- }
-
- pc = program.mapping[to.Uint64()]
-
- return nil
- }
+ pc uint64 = program.mapping[pcstart]
+ instrCount = 0
)
if glog.V(logger.Debug) {
@@ -326,62 +315,19 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env
}()
}
- for pc < len(program.instructions) {
+ for pc < uint64(len(program.instructions)) {
instrCount++
instr := program.instructions[pc]
- // calculate the new memory size and gas price for the current executing opcode
- newMemSize, cost, err := jitCalculateGasAndSize(env, contract, caller, instr, statedb, mem, stack)
+ ret, err := instr.do(program, &pc, env, contract, mem, stack)
if err != nil {
return nil, err
}
- // Use the calculated gas. When insufficient gas is present, use all gas and return an
- // Out Of Gas error
- if !contract.UseGas(cost) {
- return nil, OutOfGasError
- }
- // Resize the memory calculated previously
- mem.Resize(newMemSize.Uint64())
-
- // These opcodes return an argument and are thefor handled
- // differently from the rest of the opcodes
- switch instr.op {
- case JUMP:
- if err := jump(stack.pop()); err != nil {
- return nil, err
- }
- continue
- case JUMPI:
- pos, cond := stack.pop(), stack.pop()
-
- if cond.Cmp(common.BigTrue) >= 0 {
- if err := jump(pos); err != nil {
- return nil, err
- }
- continue
- }
- case RETURN:
- offset, size := stack.pop(), stack.pop()
- ret := mem.GetPtr(offset.Int64(), size.Int64())
-
+ if instr.halts() {
return contract.Return(ret), nil
- case SUICIDE:
- instr.fn(instr, nil, env, contract, mem, stack)
-
- return contract.Return(nil), nil
- case STOP:
- return contract.Return(nil), nil
- default:
- if instr.fn == nil {
- return nil, fmt.Errorf("Invalid opcode %x", instr.op)
- }
-
- instr.fn(instr, nil, env, contract, mem, stack)
}
-
- pc++
}
contract.Input = nil
@@ -403,7 +349,7 @@ func validDest(dests map[uint64]struct{}, dest *big.Int) bool {
// jitCalculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
// the operation. This does not reduce gas or resizes the memory.
-func jitCalculateGasAndSize(env Environment, contract *Contract, caller ContractRef, instr instruction, statedb Database, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
+func jitCalculateGasAndSize(env Environment, contract *Contract, instr instruction, statedb Database, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
var (
gas = new(big.Int)
newMemSize *big.Int = new(big.Int)