@ -86,8 +86,8 @@ type Program struct {
contract * Contract
instructions [ ] instruction // instruction set
mapping map [ uint64 ] int // real PC mapping to array indices
instructions [ ] programInstruction // instruction set
mapping map [ uint64 ] u int64 // 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 ] u int64 ) ,
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 ]
pc uint64 = 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
}
)
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 )