forked from mirror/go-ethereum
* multi-push segments * static jumps segmentsrelease/1.3.0
parent
9d61d78de6
commit
b196278044
@ -0,0 +1,90 @@ |
||||
package vm |
||||
|
||||
import ( |
||||
"math/big" |
||||
"time" |
||||
|
||||
"github.com/ethereum/go-ethereum/logger" |
||||
"github.com/ethereum/go-ethereum/logger/glog" |
||||
) |
||||
|
||||
// optimeProgram optimises a JIT program creating segments out of program
|
||||
// instructions. Currently covered are multi-pushes and static jumps
|
||||
func optimiseProgram(program *Program) { |
||||
var load []instruction |
||||
|
||||
var ( |
||||
statsJump = 0 |
||||
statsPush = 0 |
||||
) |
||||
|
||||
if glog.V(logger.Debug) { |
||||
glog.Infof("optimising %x\n", program.Id[:4]) |
||||
tstart := time.Now() |
||||
defer func() { |
||||
glog.Infof("optimised %x done in %v with JMP: %d PSH: %d\n", program.Id[:4], time.Since(tstart), statsJump, statsPush) |
||||
}() |
||||
} |
||||
|
||||
for i := 0; i < len(program.instructions); i++ { |
||||
instr := program.instructions[i].(instruction) |
||||
|
||||
switch { |
||||
case instr.op.IsPush(): |
||||
load = append(load, instr) |
||||
case instr.op.IsStaticJump(): |
||||
if len(load) == 0 { |
||||
continue |
||||
} |
||||
// if the push load is greater than 1, finalise that
|
||||
// segment first
|
||||
if len(load) > 2 { |
||||
seg, size := makePushSeg(load[:len(load)-1]) |
||||
program.instructions[i-size-1] = seg |
||||
statsPush++ |
||||
} |
||||
// create a segment consisting of a pre determined
|
||||
// jump, destination and validity.
|
||||
seg := makeStaticJumpSeg(load[len(load)-1].data, program) |
||||
program.instructions[i-1] = seg |
||||
statsJump++ |
||||
|
||||
load = nil |
||||
default: |
||||
// create a new N pushes segment
|
||||
if len(load) > 1 { |
||||
seg, size := makePushSeg(load) |
||||
program.instructions[i-size] = seg |
||||
statsPush++ |
||||
} |
||||
load = nil |
||||
} |
||||
} |
||||
} |
||||
|
||||
// makePushSeg creates a new push segment from N amount of push instructions
|
||||
func makePushSeg(instrs []instruction) (pushSeg, int) { |
||||
var ( |
||||
data []*big.Int |
||||
gas = new(big.Int) |
||||
) |
||||
|
||||
for _, instr := range instrs { |
||||
data = append(data, instr.data) |
||||
gas.Add(gas, instr.gas) |
||||
} |
||||
|
||||
return pushSeg{data, gas}, len(instrs) |
||||
} |
||||
|
||||
// makeStaticJumpSeg creates a new static jump segment from a predefined
|
||||
// destination (PUSH, JUMP).
|
||||
func makeStaticJumpSeg(to *big.Int, program *Program) jumpSeg { |
||||
gas := new(big.Int) |
||||
gas.Add(gas, _baseCheck[PUSH1].gas) |
||||
gas.Add(gas, _baseCheck[JUMP].gas) |
||||
|
||||
contract := &Contract{Code: program.code} |
||||
pos, err := jump(program.mapping, program.destinations, contract, to) |
||||
return jumpSeg{pos, err, gas} |
||||
} |
@ -0,0 +1,44 @@ |
||||
package vm |
||||
|
||||
import "math/big" |
||||
|
||||
type jumpSeg struct { |
||||
pos uint64 |
||||
err error |
||||
gas *big.Int |
||||
} |
||||
|
||||
func (j jumpSeg) do(program *Program, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) ([]byte, error) { |
||||
if !contract.UseGas(j.gas) { |
||||
return nil, OutOfGasError |
||||
} |
||||
if j.err != nil { |
||||
return nil, j.err |
||||
} |
||||
*pc = j.pos |
||||
return nil, nil |
||||
} |
||||
func (s jumpSeg) halts() bool { return false } |
||||
func (s jumpSeg) Op() OpCode { return 0 } |
||||
|
||||
type pushSeg struct { |
||||
data []*big.Int |
||||
gas *big.Int |
||||
} |
||||
|
||||
func (s pushSeg) do(program *Program, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) ([]byte, error) { |
||||
// Use the calculated gas. When insufficient gas is present, use all gas and return an
|
||||
// Out Of Gas error
|
||||
if !contract.UseGas(s.gas) { |
||||
return nil, OutOfGasError |
||||
} |
||||
|
||||
for _, d := range s.data { |
||||
stack.push(new(big.Int).Set(d)) |
||||
} |
||||
*pc += uint64(len(s.data)) |
||||
return nil, nil |
||||
} |
||||
|
||||
func (s pushSeg) halts() bool { return false } |
||||
func (s pushSeg) Op() OpCode { return 0 } |
Loading…
Reference in new issue