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:
|
||||
return opcode.LT, nil
|
||||
case token.LEQ:
|
||||
return opcode.LTE, nil
|
||||
return opcode.LE, nil
|
||||
case token.GTR:
|
||||
return opcode.GT, nil
|
||||
case token.GEQ:
|
||||
return opcode.GTE, nil
|
||||
return opcode.GE, nil
|
||||
case token.EQL:
|
||||
// VM has separate opcodes for number and string equality
|
||||
if isNumber(typ) {
|
||||
|
|
|
@ -173,9 +173,9 @@ var coefficients = map[opcode.Opcode]int64{
|
|||
opcode.NUMEQUAL: 1 << 3,
|
||||
opcode.NUMNOTEQUAL: 1 << 3,
|
||||
opcode.LT: 1 << 3,
|
||||
opcode.LTE: 1 << 3,
|
||||
opcode.LE: 1 << 3,
|
||||
opcode.GT: 1 << 3,
|
||||
opcode.GTE: 1 << 3,
|
||||
opcode.GE: 1 << 3,
|
||||
opcode.MIN: 1 << 3,
|
||||
opcode.MAX: 1 << 3,
|
||||
opcode.WITHIN: 1 << 3,
|
||||
|
|
|
@ -188,9 +188,9 @@ const (
|
|||
NUMEQUAL Opcode = 0xB3
|
||||
NUMNOTEQUAL Opcode = 0xB4
|
||||
LT Opcode = 0xB5
|
||||
LTE Opcode = 0xB6
|
||||
LE Opcode = 0xB6
|
||||
GT Opcode = 0xB7
|
||||
GTE Opcode = 0xB8
|
||||
GE Opcode = 0xB8
|
||||
MIN Opcode = 0xB9
|
||||
MAX Opcode = 0xBA
|
||||
WITHIN Opcode = 0xBB
|
||||
|
|
|
@ -170,9 +170,9 @@ func _() {
|
|||
_ = x[NUMEQUAL-179]
|
||||
_ = x[NUMNOTEQUAL-180]
|
||||
_ = x[LT-181]
|
||||
_ = x[LTE-182]
|
||||
_ = x[LE-182]
|
||||
_ = x[GT-183]
|
||||
_ = x[GTE-184]
|
||||
_ = x[GE-184]
|
||||
_ = x[MIN-185]
|
||||
_ = x[MAX-186]
|
||||
_ = x[WITHIN-187]
|
||||
|
@ -200,7 +200,7 @@ func _() {
|
|||
_ = 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{
|
||||
0: _Opcode_name[0:8],
|
||||
|
@ -363,34 +363,34 @@ var _Opcode_map = map[Opcode]string{
|
|||
179: _Opcode_name[896:904],
|
||||
180: _Opcode_name[904:915],
|
||||
181: _Opcode_name[915:917],
|
||||
182: _Opcode_name[917:920],
|
||||
183: _Opcode_name[920:922],
|
||||
184: _Opcode_name[922:925],
|
||||
185: _Opcode_name[925:928],
|
||||
186: _Opcode_name[928:931],
|
||||
187: _Opcode_name[931:937],
|
||||
192: _Opcode_name[937:941],
|
||||
193: _Opcode_name[941:947],
|
||||
194: _Opcode_name[947:956],
|
||||
195: _Opcode_name[956:964],
|
||||
196: _Opcode_name[964:974],
|
||||
197: _Opcode_name[974:984],
|
||||
198: _Opcode_name[984:993],
|
||||
200: _Opcode_name[993:999],
|
||||
202: _Opcode_name[999:1003],
|
||||
203: _Opcode_name[1003:1009],
|
||||
204: _Opcode_name[1009:1013],
|
||||
205: _Opcode_name[1013:1019],
|
||||
206: _Opcode_name[1019:1027],
|
||||
207: _Opcode_name[1027:1033],
|
||||
208: _Opcode_name[1033:1040],
|
||||
209: _Opcode_name[1040:1052],
|
||||
210: _Opcode_name[1052:1058],
|
||||
211: _Opcode_name[1058:1068],
|
||||
212: _Opcode_name[1068:1075],
|
||||
216: _Opcode_name[1075:1081],
|
||||
217: _Opcode_name[1081:1087],
|
||||
219: _Opcode_name[1087:1094],
|
||||
182: _Opcode_name[917:919],
|
||||
183: _Opcode_name[919:921],
|
||||
184: _Opcode_name[921:923],
|
||||
185: _Opcode_name[923:926],
|
||||
186: _Opcode_name[926:929],
|
||||
187: _Opcode_name[929:935],
|
||||
192: _Opcode_name[935:939],
|
||||
193: _Opcode_name[939:945],
|
||||
194: _Opcode_name[945:954],
|
||||
195: _Opcode_name[954:962],
|
||||
196: _Opcode_name[962:972],
|
||||
197: _Opcode_name[972:982],
|
||||
198: _Opcode_name[982:991],
|
||||
200: _Opcode_name[991:997],
|
||||
202: _Opcode_name[997:1001],
|
||||
203: _Opcode_name[1001:1007],
|
||||
204: _Opcode_name[1007:1011],
|
||||
205: _Opcode_name[1011:1017],
|
||||
206: _Opcode_name[1017:1025],
|
||||
207: _Opcode_name[1025:1031],
|
||||
208: _Opcode_name[1031:1038],
|
||||
209: _Opcode_name[1038:1050],
|
||||
210: _Opcode_name[1050:1056],
|
||||
211: _Opcode_name[1056:1066],
|
||||
212: _Opcode_name[1066:1073],
|
||||
216: _Opcode_name[1073:1079],
|
||||
217: _Opcode_name[1079:1085],
|
||||
219: _Opcode_name[1085:1092],
|
||||
}
|
||||
|
||||
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,
|
||||
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 {
|
||||
t.Run(op.String(), func(t *testing.B) {
|
||||
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
|
36
pkg/vm/vm.go
36
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()
|
||||
v.estack.PushVal(a.Cmp(b) != 0)
|
||||
|
||||
case opcode.LT, opcode.LE, opcode.GT, opcode.GE:
|
||||
eb := v.estack.Pop()
|
||||
ea := v.estack.Pop()
|
||||
_, aNil := ea.Item().(stackitem.Null)
|
||||
_, bNil := eb.Item().(stackitem.Null)
|
||||
|
||||
res := !aNil && !bNil
|
||||
if res {
|
||||
cmp := ea.BigInt().Cmp(eb.BigInt())
|
||||
switch op {
|
||||
case opcode.LT:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) == -1)
|
||||
|
||||
case opcode.LTE:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) <= 0)
|
||||
|
||||
res = cmp == -1
|
||||
case opcode.LE:
|
||||
res = cmp <= 0
|
||||
case opcode.GT:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) == 1)
|
||||
|
||||
case opcode.GTE:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) >= 0)
|
||||
res = cmp == 1
|
||||
case opcode.GE:
|
||||
res = cmp >= 0
|
||||
}
|
||||
}
|
||||
v.estack.PushVal(res)
|
||||
|
||||
case opcode.MIN:
|
||||
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))
|
||||
}
|
||||
|
||||
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) {
|
||||
prog := makeProgram(opcode.LT)
|
||||
runWithArgs(t, prog, false, 4, 3)
|
||||
}
|
||||
|
||||
func TestLTE(t *testing.T) {
|
||||
prog := makeProgram(opcode.LTE)
|
||||
func TestLE(t *testing.T) {
|
||||
prog := makeProgram(opcode.LE)
|
||||
runWithArgs(t, prog, true, 2, 3)
|
||||
}
|
||||
|
||||
|
@ -822,8 +834,8 @@ func TestGT(t *testing.T) {
|
|||
runWithArgs(t, prog, true, 9, 3)
|
||||
}
|
||||
|
||||
func TestGTE(t *testing.T) {
|
||||
prog := makeProgram(opcode.GTE)
|
||||
func TestGE(t *testing.T) {
|
||||
prog := makeProgram(opcode.GE)
|
||||
runWithArgs(t, prog, true, 3, 3)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue