forked from TrueCloudLab/neoneo-go
Merge pull request #1939 from nspcc-dev/vm-arith-null
Allow NULL items for LT/LE/GT/GE instructions
This commit is contained in:
commit
5924123927
8 changed files with 75 additions and 61 deletions
|
@ -1901,11 +1901,11 @@ func convertToken(tok token.Token, typ types.Type) (opcode.Opcode, error) {
|
||||||
case token.LSS:
|
case token.LSS:
|
||||||
return opcode.LT, nil
|
return opcode.LT, nil
|
||||||
case token.LEQ:
|
case token.LEQ:
|
||||||
return opcode.LTE, nil
|
return opcode.LE, nil
|
||||||
case token.GTR:
|
case token.GTR:
|
||||||
return opcode.GT, nil
|
return opcode.GT, nil
|
||||||
case token.GEQ:
|
case token.GEQ:
|
||||||
return opcode.GTE, nil
|
return opcode.GE, nil
|
||||||
case token.EQL:
|
case token.EQL:
|
||||||
// VM has separate opcodes for number and string equality
|
// VM has separate opcodes for number and string equality
|
||||||
if isNumber(typ) {
|
if isNumber(typ) {
|
||||||
|
|
|
@ -173,9 +173,9 @@ var coefficients = map[opcode.Opcode]int64{
|
||||||
opcode.NUMEQUAL: 1 << 3,
|
opcode.NUMEQUAL: 1 << 3,
|
||||||
opcode.NUMNOTEQUAL: 1 << 3,
|
opcode.NUMNOTEQUAL: 1 << 3,
|
||||||
opcode.LT: 1 << 3,
|
opcode.LT: 1 << 3,
|
||||||
opcode.LTE: 1 << 3,
|
opcode.LE: 1 << 3,
|
||||||
opcode.GT: 1 << 3,
|
opcode.GT: 1 << 3,
|
||||||
opcode.GTE: 1 << 3,
|
opcode.GE: 1 << 3,
|
||||||
opcode.MIN: 1 << 3,
|
opcode.MIN: 1 << 3,
|
||||||
opcode.MAX: 1 << 3,
|
opcode.MAX: 1 << 3,
|
||||||
opcode.WITHIN: 1 << 3,
|
opcode.WITHIN: 1 << 3,
|
||||||
|
|
|
@ -188,9 +188,9 @@ const (
|
||||||
NUMEQUAL Opcode = 0xB3
|
NUMEQUAL Opcode = 0xB3
|
||||||
NUMNOTEQUAL Opcode = 0xB4
|
NUMNOTEQUAL Opcode = 0xB4
|
||||||
LT Opcode = 0xB5
|
LT Opcode = 0xB5
|
||||||
LTE Opcode = 0xB6
|
LE Opcode = 0xB6
|
||||||
GT Opcode = 0xB7
|
GT Opcode = 0xB7
|
||||||
GTE Opcode = 0xB8
|
GE Opcode = 0xB8
|
||||||
MIN Opcode = 0xB9
|
MIN Opcode = 0xB9
|
||||||
MAX Opcode = 0xBA
|
MAX Opcode = 0xBA
|
||||||
WITHIN Opcode = 0xBB
|
WITHIN Opcode = 0xBB
|
||||||
|
|
|
@ -170,9 +170,9 @@ func _() {
|
||||||
_ = x[NUMEQUAL-179]
|
_ = x[NUMEQUAL-179]
|
||||||
_ = x[NUMNOTEQUAL-180]
|
_ = x[NUMNOTEQUAL-180]
|
||||||
_ = x[LT-181]
|
_ = x[LT-181]
|
||||||
_ = x[LTE-182]
|
_ = x[LE-182]
|
||||||
_ = x[GT-183]
|
_ = x[GT-183]
|
||||||
_ = x[GTE-184]
|
_ = x[GE-184]
|
||||||
_ = x[MIN-185]
|
_ = x[MIN-185]
|
||||||
_ = x[MAX-186]
|
_ = x[MAX-186]
|
||||||
_ = x[WITHIN-187]
|
_ = x[WITHIN-187]
|
||||||
|
@ -200,7 +200,7 @@ func _() {
|
||||||
_ = x[CONVERT-219]
|
_ = x[CONVERT-219]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMP_LJMPIFJMPIF_LJMPIFNOTJMPIFNOT_LJMPEQJMPEQ_LJMPNEJMPNE_LJMPGTJMPGT_LJMPGEJMPGE_LJMPLTJMPLT_LJMPLEJMPLE_LCALLCALL_LCALLACALLTABORTASSERTTHROWTRYTRY_LENDTRYENDTRY_LENDFINALLYRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPROTROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODPOWSQRTSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAY_TNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSPOPITEMISNULLISTYPECONVERT"
|
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMP_LJMPIFJMPIF_LJMPIFNOTJMPIFNOT_LJMPEQJMPEQ_LJMPNEJMPNE_LJMPGTJMPGT_LJMPGEJMPGE_LJMPLTJMPLT_LJMPLEJMPLE_LCALLCALL_LCALLACALLTABORTASSERTTHROWTRYTRY_LENDTRYENDTRY_LENDFINALLYRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPROTROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODPOWSQRTSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLEGTGEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAY_TNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSPOPITEMISNULLISTYPECONVERT"
|
||||||
|
|
||||||
var _Opcode_map = map[Opcode]string{
|
var _Opcode_map = map[Opcode]string{
|
||||||
0: _Opcode_name[0:8],
|
0: _Opcode_name[0:8],
|
||||||
|
@ -363,34 +363,34 @@ var _Opcode_map = map[Opcode]string{
|
||||||
179: _Opcode_name[896:904],
|
179: _Opcode_name[896:904],
|
||||||
180: _Opcode_name[904:915],
|
180: _Opcode_name[904:915],
|
||||||
181: _Opcode_name[915:917],
|
181: _Opcode_name[915:917],
|
||||||
182: _Opcode_name[917:920],
|
182: _Opcode_name[917:919],
|
||||||
183: _Opcode_name[920:922],
|
183: _Opcode_name[919:921],
|
||||||
184: _Opcode_name[922:925],
|
184: _Opcode_name[921:923],
|
||||||
185: _Opcode_name[925:928],
|
185: _Opcode_name[923:926],
|
||||||
186: _Opcode_name[928:931],
|
186: _Opcode_name[926:929],
|
||||||
187: _Opcode_name[931:937],
|
187: _Opcode_name[929:935],
|
||||||
192: _Opcode_name[937:941],
|
192: _Opcode_name[935:939],
|
||||||
193: _Opcode_name[941:947],
|
193: _Opcode_name[939:945],
|
||||||
194: _Opcode_name[947:956],
|
194: _Opcode_name[945:954],
|
||||||
195: _Opcode_name[956:964],
|
195: _Opcode_name[954:962],
|
||||||
196: _Opcode_name[964:974],
|
196: _Opcode_name[962:972],
|
||||||
197: _Opcode_name[974:984],
|
197: _Opcode_name[972:982],
|
||||||
198: _Opcode_name[984:993],
|
198: _Opcode_name[982:991],
|
||||||
200: _Opcode_name[993:999],
|
200: _Opcode_name[991:997],
|
||||||
202: _Opcode_name[999:1003],
|
202: _Opcode_name[997:1001],
|
||||||
203: _Opcode_name[1003:1009],
|
203: _Opcode_name[1001:1007],
|
||||||
204: _Opcode_name[1009:1013],
|
204: _Opcode_name[1007:1011],
|
||||||
205: _Opcode_name[1013:1019],
|
205: _Opcode_name[1011:1017],
|
||||||
206: _Opcode_name[1019:1027],
|
206: _Opcode_name[1017:1025],
|
||||||
207: _Opcode_name[1027:1033],
|
207: _Opcode_name[1025:1031],
|
||||||
208: _Opcode_name[1033:1040],
|
208: _Opcode_name[1031:1038],
|
||||||
209: _Opcode_name[1040:1052],
|
209: _Opcode_name[1038:1050],
|
||||||
210: _Opcode_name[1052:1058],
|
210: _Opcode_name[1050:1056],
|
||||||
211: _Opcode_name[1058:1068],
|
211: _Opcode_name[1056:1066],
|
||||||
212: _Opcode_name[1068:1075],
|
212: _Opcode_name[1066:1073],
|
||||||
216: _Opcode_name[1075:1081],
|
216: _Opcode_name[1073:1079],
|
||||||
217: _Opcode_name[1081:1087],
|
217: _Opcode_name[1079:1085],
|
||||||
219: _Opcode_name[1087:1094],
|
219: _Opcode_name[1085:1092],
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i Opcode) String() string {
|
func (i Opcode) String() string {
|
||||||
|
|
|
@ -571,7 +571,7 @@ func BenchmarkOpcodes(t *testing.B) {
|
||||||
}
|
}
|
||||||
binaries := []opcode.Opcode{opcode.AND, opcode.OR, opcode.XOR, opcode.ADD, opcode.SUB,
|
binaries := []opcode.Opcode{opcode.AND, opcode.OR, opcode.XOR, opcode.ADD, opcode.SUB,
|
||||||
opcode.BOOLAND, opcode.BOOLOR, opcode.NUMEQUAL, opcode.NUMNOTEQUAL,
|
opcode.BOOLAND, opcode.BOOLOR, opcode.NUMEQUAL, opcode.NUMNOTEQUAL,
|
||||||
opcode.LT, opcode.LTE, opcode.GT, opcode.GTE, opcode.MIN, opcode.MAX}
|
opcode.LT, opcode.LE, opcode.GT, opcode.GE, opcode.MIN, opcode.MAX}
|
||||||
for _, op := range binaries {
|
for _, op := range binaries {
|
||||||
t.Run(op.String(), func(t *testing.B) {
|
t.Run(op.String(), func(t *testing.B) {
|
||||||
t.Run("0+0", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, 0, 0)) })
|
t.Run("0+0", func(t *testing.B) { benchOpcode(t, opParamPushVM(op, nil, 0, 0)) })
|
||||||
|
|
2
pkg/vm/testdata/neo-vm
vendored
2
pkg/vm/testdata/neo-vm
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 3fb22406ba72a86fb251c763aea72677f9f9baa2
|
Subproject commit 72e546b176401b85a03bc4653eeb177badb42d3b
|
38
pkg/vm/vm.go
38
pkg/vm/vm.go
|
@ -972,25 +972,27 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
a := v.estack.Pop().BigInt()
|
a := v.estack.Pop().BigInt()
|
||||||
v.estack.PushVal(a.Cmp(b) != 0)
|
v.estack.PushVal(a.Cmp(b) != 0)
|
||||||
|
|
||||||
case opcode.LT:
|
case opcode.LT, opcode.LE, opcode.GT, opcode.GE:
|
||||||
b := v.estack.Pop().BigInt()
|
eb := v.estack.Pop()
|
||||||
a := v.estack.Pop().BigInt()
|
ea := v.estack.Pop()
|
||||||
v.estack.PushVal(a.Cmp(b) == -1)
|
_, aNil := ea.Item().(stackitem.Null)
|
||||||
|
_, bNil := eb.Item().(stackitem.Null)
|
||||||
|
|
||||||
case opcode.LTE:
|
res := !aNil && !bNil
|
||||||
b := v.estack.Pop().BigInt()
|
if res {
|
||||||
a := v.estack.Pop().BigInt()
|
cmp := ea.BigInt().Cmp(eb.BigInt())
|
||||||
v.estack.PushVal(a.Cmp(b) <= 0)
|
switch op {
|
||||||
|
case opcode.LT:
|
||||||
case opcode.GT:
|
res = cmp == -1
|
||||||
b := v.estack.Pop().BigInt()
|
case opcode.LE:
|
||||||
a := v.estack.Pop().BigInt()
|
res = cmp <= 0
|
||||||
v.estack.PushVal(a.Cmp(b) == 1)
|
case opcode.GT:
|
||||||
|
res = cmp == 1
|
||||||
case opcode.GTE:
|
case opcode.GE:
|
||||||
b := v.estack.Pop().BigInt()
|
res = cmp >= 0
|
||||||
a := v.estack.Pop().BigInt()
|
}
|
||||||
v.estack.PushVal(a.Cmp(b) >= 0)
|
}
|
||||||
|
v.estack.PushVal(res)
|
||||||
|
|
||||||
case opcode.MIN:
|
case opcode.MIN:
|
||||||
b := v.estack.Pop().BigInt()
|
b := v.estack.Pop().BigInt()
|
||||||
|
|
|
@ -807,13 +807,25 @@ func TestSHL(t *testing.T) {
|
||||||
t.Run("BigResult", getTestFuncForVM(prog, nil, getBigInt(stackitem.MaxBigIntegerSizeBits/2, 0), stackitem.MaxBigIntegerSizeBits/2))
|
t.Run("BigResult", getTestFuncForVM(prog, nil, getBigInt(stackitem.MaxBigIntegerSizeBits/2, 0), stackitem.MaxBigIntegerSizeBits/2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestArithNullArg(t *testing.T) {
|
||||||
|
for _, op := range []opcode.Opcode{opcode.LT, opcode.LE, opcode.GT, opcode.GE} {
|
||||||
|
prog := makeProgram(op)
|
||||||
|
t.Run(op.String(), func(t *testing.T) {
|
||||||
|
runWithArgs(t, prog, false, stackitem.Null{}, 0)
|
||||||
|
runWithArgs(t, prog, false, 0, stackitem.Null{})
|
||||||
|
runWithArgs(t, prog, nil, stackitem.NewInterop(nil), 1) // also has `.Value() == nil`
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLT(t *testing.T) {
|
func TestLT(t *testing.T) {
|
||||||
prog := makeProgram(opcode.LT)
|
prog := makeProgram(opcode.LT)
|
||||||
runWithArgs(t, prog, false, 4, 3)
|
runWithArgs(t, prog, false, 4, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLTE(t *testing.T) {
|
func TestLE(t *testing.T) {
|
||||||
prog := makeProgram(opcode.LTE)
|
prog := makeProgram(opcode.LE)
|
||||||
runWithArgs(t, prog, true, 2, 3)
|
runWithArgs(t, prog, true, 2, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,8 +834,8 @@ func TestGT(t *testing.T) {
|
||||||
runWithArgs(t, prog, true, 9, 3)
|
runWithArgs(t, prog, true, 9, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGTE(t *testing.T) {
|
func TestGE(t *testing.T) {
|
||||||
prog := makeProgram(opcode.GTE)
|
prog := makeProgram(opcode.GE)
|
||||||
runWithArgs(t, prog, true, 3, 3)
|
runWithArgs(t, prog, true, 3, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue