aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/instructions.go
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2015-10-07 00:16:03 +0800
committerJeffrey Wilcke <geffobscura@gmail.com>2015-10-17 04:17:35 +0800
commit9d61d78de6ad20822b2b48d6c4e3779369ea7331 (patch)
treede10da7c77e416232cd69d094ceb7c9797eee244 /core/vm/instructions.go
parent10ed107ba2001d1aabba3d319ba88c5ce6e8fdc0 (diff)
downloaddexon-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.go82
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)