vm: optimize eq, slt, sgt and iszero + tests

This commit is contained in:
Martin Holst Swende 2018-02-09 11:34:50 +01:00
parent 3ec1b9a92d
commit 788755760c
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
2 changed files with 82 additions and 25 deletions

View file

@ -30,6 +30,8 @@ import (
var ( var (
bigZero = new(big.Int) bigZero = new(big.Int)
tt255 = math.BigPow(2, 255)
tt256 = math.BigPow(2, 256)
errWriteProtection = errors.New("evm: write protection") errWriteProtection = errors.New("evm: write protection")
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
errExecutionReverted = errors.New("evm: execution reverted") errExecutionReverted = errors.New("evm: execution reverted")
@ -191,50 +193,97 @@ func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack
} }
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop()) x, y := stack.pop(), stack.peek()
if x.Cmp(math.S256(y)) < 0 {
stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
evm.interpreter.intPool.put(x, y) xSign := x.Cmp(tt255)
ySign := y.Cmp(tt255)
if xSign >= 0 {
//x negative
if ySign < 0 {
// y positive
y.SetUint64(1)
return nil, nil
}
// Both negative
if x.Cmp(y) > 0 {
y.SetUint64(1)
} else {
y.SetUint64(0)
}
} else {
// x positive
if ySign >= 0 {
// y negative
y.SetUint64(0)
return nil, nil
}
// Both positive
if x.Cmp(y) >= 0 {
y.SetUint64(0)
} else {
y.SetUint64(1)
}
}
evm.interpreter.intPool.put(x)
return nil, nil return nil, nil
} }
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop()) x, y := stack.pop(), stack.peek()
if x.Cmp(y) > 0 {
stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
evm.interpreter.intPool.put(x, y) xSign := x.Cmp(tt255)
ySign := y.Cmp(tt255)
if xSign >= 0 {
//x negative
if ySign < 0 {
// y positive
y.SetUint64(0)
return nil, nil
}
// Both negative (note: equality -> 0)
if x.Cmp(y) >= 0 {
y.SetUint64(0)
} else {
y.SetUint64(1)
}
} else {
// x positive
if ySign >= 0 {
// y negative
y.SetUint64(1)
return nil, nil
}
// Both positive
if x.Cmp(y) > 0 {
y.SetUint64(1)
} else {
y.SetUint64(0)
}
}
evm.interpreter.intPool.put(x)
return nil, nil return nil, nil
} }
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.peek()
if x.Cmp(y) == 0 { if x.Cmp(y) == 0 {
stack.push(evm.interpreter.intPool.get().SetUint64(1)) y.SetUint64(1)
} else { } else {
stack.push(new(big.Int)) y.SetUint64(0)
} }
evm.interpreter.intPool.put(x)
evm.interpreter.intPool.put(x, y)
return nil, nil return nil, nil
} }
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x := stack.pop() x := stack.peek()
if x.Sign() > 0 { if x.Sign() > 0 {
stack.push(new(big.Int)) x.SetUint64(0)
} else { } else {
stack.push(evm.interpreter.intPool.get().SetUint64(1)) x.SetUint64(1)
} }
evm.interpreter.intPool.put(x)
return nil, nil return nil, nil
} }

View file

@ -349,7 +349,11 @@ func BenchmarkOpEq(b *testing.B) {
opBenchmark(b, opEq, x, y) opBenchmark(b, opEq, x, y)
} }
func BenchmarkOpEq2(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe"
opBenchmark(b, opEq, x, y)
}
func BenchmarkOpAnd(b *testing.B) { func BenchmarkOpAnd(b *testing.B) {
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
@ -412,3 +416,7 @@ func BenchmarkOpSAR(b *testing.B) {
opBenchmark(b, opSAR, x, y) opBenchmark(b, opSAR, x, y)
} }
func BenchmarkOpIsZero(b *testing.B) {
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
opBenchmark(b, opIszero, x)
}