aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/jit_optimiser.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm/jit_optimiser.go')
-rw-r--r--core/vm/jit_optimiser.go90
1 files changed, 90 insertions, 0 deletions
diff --git a/core/vm/jit_optimiser.go b/core/vm/jit_optimiser.go
new file mode 100644
index 000000000..4823cc1a0
--- /dev/null
+++ b/core/vm/jit_optimiser.go
@@ -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}
+}