mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
Merge bd860ff650 into 8b865fa9bf
This commit is contained in:
commit
730694af6e
6 changed files with 140 additions and 18 deletions
|
|
@ -28,6 +28,18 @@ import (
|
|||
type instrFn func(instr instruction, env Environment, context *Context, memory *Memory, stack *stack)
|
||||
type instrExFn func(instr instruction, ret *big.Int, env Environment, context *Context, memory *Memory, stack *stack)
|
||||
|
||||
type segment struct {
|
||||
pc uint64 // pc end
|
||||
|
||||
sreq int // required stack items
|
||||
|
||||
items []*big.Int // items to push
|
||||
gas *big.Int // total gas cost
|
||||
|
||||
jump bool
|
||||
valid bool
|
||||
}
|
||||
|
||||
type instruction struct {
|
||||
op OpCode
|
||||
pc uint64
|
||||
|
|
@ -38,6 +50,8 @@ type instruction struct {
|
|||
gas *big.Int
|
||||
spop int
|
||||
spush int
|
||||
|
||||
seg *segment
|
||||
}
|
||||
|
||||
func opStaticJump(instr instruction, ret *big.Int, env Environment, context *Context, memory *Memory, stack *stack) {
|
||||
|
|
|
|||
121
core/vm/jit.go
121
core/vm/jit.go
|
|
@ -77,7 +77,7 @@ type Program struct {
|
|||
context *Context
|
||||
|
||||
instructions []instruction // instruction set
|
||||
mapping map[uint64]int // real PC mapping to array indices
|
||||
mapping map[uint64]uint64 // real PC mapping to array indices
|
||||
destinations map[uint64]struct{} // cached jump destinations
|
||||
|
||||
code []byte
|
||||
|
|
@ -87,7 +87,7 @@ type Program struct {
|
|||
func NewProgram(code []byte) *Program {
|
||||
program := &Program{
|
||||
Id: crypto.Sha3Hash(code),
|
||||
mapping: make(map[uint64]int),
|
||||
mapping: make(map[uint64]uint64),
|
||||
destinations: make(map[uint64]struct{}),
|
||||
code: code,
|
||||
}
|
||||
|
|
@ -108,10 +108,10 @@ func (p *Program) addInstr(op OpCode, pc uint64, fn instrFn, data *big.Int) {
|
|||
baseOp = DUP1
|
||||
}
|
||||
base := _baseCheck[baseOp]
|
||||
instr := instruction{op, pc, fn, nil, data, base.gas, base.stackPop, base.stackPush}
|
||||
instr := instruction{op, pc, fn, nil, data, base.gas, base.stackPop, base.stackPush, nil}
|
||||
|
||||
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
|
||||
|
|
@ -271,22 +271,97 @@ func CompileProgram(program *Program) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
staticAnalysis(program)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func staticAnalysis(program *Program) {
|
||||
var (
|
||||
sreq int
|
||||
seg *segment
|
||||
stack *stack
|
||||
instrStart int
|
||||
)
|
||||
for i, instr := range program.instructions {
|
||||
if isStatic(instr) {
|
||||
if seg == nil {
|
||||
seg = &segment{gas: new(big.Int)}
|
||||
instrStart = i
|
||||
stack = newstack()
|
||||
}
|
||||
}
|
||||
|
||||
if seg != nil {
|
||||
if isStatic(instr) {
|
||||
stack.push(instr.data)
|
||||
seg.gas.Add(seg.gas, instr.gas)
|
||||
} else if isMod(instr) {
|
||||
if stack.len() >= 2 {
|
||||
instr.fn(instr, nil, nil, nil, stack)
|
||||
seg.gas.Add(seg.gas, instr.gas)
|
||||
} else {
|
||||
seg = nil
|
||||
}
|
||||
} else if isStaticPush(instr) {
|
||||
seg.jump = true
|
||||
to := stack.pop()
|
||||
seg.items = stack.data
|
||||
program.instructions[instrStart].seg = seg
|
||||
if validDest(program.destinations, to) {
|
||||
seg.valid = true
|
||||
seg.pc = program.mapping[to.Uint64()]
|
||||
}
|
||||
seg.gas.Add(seg.gas, instr.gas)
|
||||
|
||||
seg = nil
|
||||
} else {
|
||||
if i-instrStart > 1 {
|
||||
seg.items = stack.data
|
||||
seg.pc = uint64(i)
|
||||
seg.sreq = sreq
|
||||
program.instructions[instrStart].seg = seg
|
||||
}
|
||||
seg = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isStaticPush(instr instruction) bool {
|
||||
return false
|
||||
return instr.op == JUMP
|
||||
}
|
||||
|
||||
func isMod(instr instruction) bool {
|
||||
switch instr.op {
|
||||
case MUL, DIV, ADD, SUB, EXP, MOD:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isStatic(instr instruction) bool {
|
||||
switch instr.op {
|
||||
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RunProgram runs the program given the enviroment and context and returns an
|
||||
// error if the execution failed (non-consensus)
|
||||
func RunProgram(program *Program, env Environment, context *Context, input []byte) ([]byte, error) {
|
||||
return runProgram(program, 0, NewMemory(), newstack(), env, context, input)
|
||||
}
|
||||
|
||||
func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env Environment, context *Context, input []byte) ([]byte, error) {
|
||||
func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env Environment, context *Context, input []byte) (ret []byte, err error) {
|
||||
context.Input = input
|
||||
|
||||
var (
|
||||
caller = context.caller
|
||||
statedb = env.State()
|
||||
pc int = program.mapping[pcstart]
|
||||
caller = context.caller
|
||||
statedb = env.State()
|
||||
pc uint64 = program.mapping[pcstart]
|
||||
|
||||
jump = func(to *big.Int) error {
|
||||
if !validDest(program.destinations, to) {
|
||||
|
|
@ -300,8 +375,34 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env
|
|||
}
|
||||
)
|
||||
|
||||
for pc < len(program.instructions) {
|
||||
for pc < uint64(len(program.instructions)) {
|
||||
instr := program.instructions[pc]
|
||||
//fmt.Println(instr.op)
|
||||
if instr.seg != nil {
|
||||
segment := instr.seg
|
||||
|
||||
// check for jump and make sure it's valid
|
||||
if segment.jump && !segment.valid {
|
||||
return nil, fmt.Errorf("invalid jump destination")
|
||||
}
|
||||
|
||||
// make sure we can pay for the full segment in advance
|
||||
if !context.UseGas(segment.gas) {
|
||||
return nil, OutOfGasError
|
||||
}
|
||||
|
||||
// copy items over to a new slice to prevent modifications
|
||||
// off segment items.
|
||||
items := make([]*big.Int, len(segment.items))
|
||||
for i, item := range segment.items {
|
||||
items[i] = new(big.Int).Set(item)
|
||||
}
|
||||
stack.data = append(stack.data, items...)
|
||||
|
||||
// set the new pc and continue
|
||||
pc = segment.pc
|
||||
continue
|
||||
}
|
||||
|
||||
// calculate the new memory size and gas price for the current executing opcode
|
||||
newMemSize, cost, err := jitCalculateGasAndSize(env, context, caller, instr, statedb, mem, stack)
|
||||
|
|
@ -352,8 +453,8 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env
|
|||
|
||||
instr.fn(instr, env, context, mem, stack)
|
||||
}
|
||||
|
||||
pc++
|
||||
|
||||
}
|
||||
|
||||
context.Input = nil
|
||||
|
|
|
|||
3
tests/jit.txt
Normal file
3
tests/jit.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
PASS
|
||||
BenchmarkVmFibonacci16Tests 30 40426131 ns/op
|
||||
ok github.com/ethereum/go-ethereum/tests 1.325s
|
||||
3
tests/nojit.txt
Normal file
3
tests/nojit.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
PASS
|
||||
BenchmarkVmFibonacci16Tests-4 20 59170476 ns/op
|
||||
ok github.com/ethereum/go-ethereum/tests 1.282s
|
||||
3
tests/seg.txt
Normal file
3
tests/seg.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
PASS
|
||||
BenchmarkVmFibonacci16Tests 50 34768275 ns/op
|
||||
ok github.com/ethereum/go-ethereum/tests 1.839s
|
||||
|
|
@ -84,15 +84,13 @@ func BenchVmTest(p string, conf bconf, b *testing.B) error {
|
|||
env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
|
||||
}
|
||||
|
||||
/*
|
||||
if conf.precomp {
|
||||
program := vm.NewProgram(test.code)
|
||||
err := vm.AttachProgram(program)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if conf.precomp {
|
||||
program := vm.NewProgram(common.Hex2Bytes(test.Pre["0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"].Code))
|
||||
err := vm.CompileProgram(program)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
|
|
|||
Loading…
Reference in a new issue