Merge pull request #1939 from nspcc-dev/vm-arith-null

Allow NULL items for LT/LE/GT/GE instructions
This commit is contained in:
Roman Khimov 2021-04-29 17:55:13 +03:00 committed by GitHub
commit 5924123927
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 61 deletions

View file

@ -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) {

View file

@ -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,

View file

@ -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

View file

@ -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 {

View file

@ -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)) })

@ -1 +1 @@
Subproject commit 3fb22406ba72a86fb251c763aea72677f9f9baa2 Subproject commit 72e546b176401b85a03bc4653eeb177badb42d3b

View file

@ -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()

View file

@ -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)
} }