diff options
author | Jeffrey Wilcke <geffobscura@gmail.com> | 2015-10-07 00:16:03 +0800 |
---|---|---|
committer | Jeffrey Wilcke <geffobscura@gmail.com> | 2015-10-17 04:17:35 +0800 |
commit | 9d61d78de6ad20822b2b48d6c4e3779369ea7331 (patch) | |
tree | de10da7c77e416232cd69d094ceb7c9797eee244 /core/vm/instructions.go | |
parent | 10ed107ba2001d1aabba3d319ba88c5ce6e8fdc0 (diff) | |
download | dexon-9d61d78de6ad20822b2b48d6c4e3779369ea7331.tar dexon-9d61d78de6ad20822b2b48d6c4e3779369ea7331.tar.gz dexon-9d61d78de6ad20822b2b48d6c4e3779369ea7331.tar.bz2 dexon-9d61d78de6ad20822b2b48d6c4e3779369ea7331.tar.lz dexon-9d61d78de6ad20822b2b48d6c4e3779369ea7331.tar.xz dexon-9d61d78de6ad20822b2b48d6c4e3779369ea7331.tar.zst dexon-9d61d78de6ad20822b2b48d6c4e3779369ea7331.zip |
core/vm: abstracted instruction execution away from JIT
Moved the execution of instructions to the instruction it self. This
will allow for specialised instructions (e.g. segments) to be execution
in the same manner as regular instructions.
Diffstat (limited to 'core/vm/instructions.go')
-rw-r--r-- | core/vm/instructions.go | 82 |
1 files changed, 74 insertions, 8 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) |