vm: implement REVERSE* opcodes
Use new opcodes in the compiler instead of XSWAP/ROLL.
This commit is contained in:
parent
c8a1188ee1
commit
d18199ce42
6 changed files with 161 additions and 81 deletions
|
@ -940,13 +940,12 @@ func (c *codegen) emitReverse(num int) {
|
||||||
case 2:
|
case 2:
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
|
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
|
||||||
case 3:
|
case 3:
|
||||||
emit.Int(c.prog.BinWriter, 2)
|
emit.Opcode(c.prog.BinWriter, opcode.REVERSE3)
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.XSWAP)
|
case 4:
|
||||||
|
emit.Opcode(c.prog.BinWriter, opcode.REVERSE4)
|
||||||
default:
|
default:
|
||||||
for i := 1; i < num; i++ {
|
emit.Int(c.prog.BinWriter, int64(num))
|
||||||
emit.Int(c.prog.BinWriter, int64(i))
|
emit.Opcode(c.prog.BinWriter, opcode.REVERSEN)
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.ROLL)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,9 +79,9 @@ const (
|
||||||
OLDPUSH1 Opcode = 0x51 // FIXME remove #927
|
OLDPUSH1 Opcode = 0x51 // FIXME remove #927
|
||||||
ROT Opcode = 0x51
|
ROT Opcode = 0x51
|
||||||
ROLL Opcode = 0x52
|
ROLL Opcode = 0x52
|
||||||
// REVERSE3 Opcode = 0x53
|
REVERSE3 Opcode = 0x53
|
||||||
// REVERSE4 Opcode = 0x54
|
REVERSE4 Opcode = 0x54
|
||||||
// REVERSEN Opcode = 0x55
|
REVERSEN Opcode = 0x55
|
||||||
|
|
||||||
RET Opcode = 0x66
|
RET Opcode = 0x66
|
||||||
APPCALL Opcode = 0x67
|
APPCALL Opcode = 0x67
|
||||||
|
|
|
@ -72,6 +72,9 @@ func _() {
|
||||||
_ = x[OLDPUSH1-81]
|
_ = x[OLDPUSH1-81]
|
||||||
_ = x[ROT-81]
|
_ = x[ROT-81]
|
||||||
_ = x[ROLL-82]
|
_ = x[ROLL-82]
|
||||||
|
_ = x[REVERSE3-83]
|
||||||
|
_ = x[REVERSE4-84]
|
||||||
|
_ = x[REVERSEN-85]
|
||||||
_ = x[RET-102]
|
_ = x[RET-102]
|
||||||
_ = x[APPCALL-103]
|
_ = x[APPCALL-103]
|
||||||
_ = x[SYSCALL-104]
|
_ = x[SYSCALL-104]
|
||||||
|
@ -141,7 +144,7 @@ func _() {
|
||||||
_ = x[THROWIFNOT-241]
|
_ = x[THROWIFNOT-241]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLRETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXSWAPXTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT"
|
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENRETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXSWAPXTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT"
|
||||||
|
|
||||||
var _Opcode_map = map[Opcode]string{
|
var _Opcode_map = map[Opcode]string{
|
||||||
0: _Opcode_name[0:8],
|
0: _Opcode_name[0:8],
|
||||||
|
@ -205,73 +208,76 @@ var _Opcode_map = map[Opcode]string{
|
||||||
80: _Opcode_name[338:342],
|
80: _Opcode_name[338:342],
|
||||||
81: _Opcode_name[342:350],
|
81: _Opcode_name[342:350],
|
||||||
82: _Opcode_name[350:354],
|
82: _Opcode_name[350:354],
|
||||||
102: _Opcode_name[354:357],
|
83: _Opcode_name[354:362],
|
||||||
103: _Opcode_name[357:364],
|
84: _Opcode_name[362:370],
|
||||||
104: _Opcode_name[364:371],
|
85: _Opcode_name[370:378],
|
||||||
105: _Opcode_name[371:379],
|
102: _Opcode_name[378:381],
|
||||||
106: _Opcode_name[379:394],
|
103: _Opcode_name[381:388],
|
||||||
107: _Opcode_name[394:404],
|
104: _Opcode_name[388:395],
|
||||||
108: _Opcode_name[404:416],
|
105: _Opcode_name[395:403],
|
||||||
114: _Opcode_name[416:421],
|
106: _Opcode_name[403:418],
|
||||||
115: _Opcode_name[421:426],
|
107: _Opcode_name[418:428],
|
||||||
126: _Opcode_name[426:429],
|
108: _Opcode_name[428:440],
|
||||||
127: _Opcode_name[429:435],
|
114: _Opcode_name[440:445],
|
||||||
128: _Opcode_name[435:439],
|
115: _Opcode_name[445:450],
|
||||||
129: _Opcode_name[439:444],
|
126: _Opcode_name[450:453],
|
||||||
144: _Opcode_name[444:450],
|
127: _Opcode_name[453:459],
|
||||||
145: _Opcode_name[450:453],
|
128: _Opcode_name[459:463],
|
||||||
146: _Opcode_name[453:455],
|
129: _Opcode_name[463:468],
|
||||||
147: _Opcode_name[455:458],
|
144: _Opcode_name[468:474],
|
||||||
151: _Opcode_name[458:463],
|
145: _Opcode_name[474:477],
|
||||||
152: _Opcode_name[463:471],
|
146: _Opcode_name[477:479],
|
||||||
153: _Opcode_name[471:475],
|
147: _Opcode_name[479:482],
|
||||||
154: _Opcode_name[475:478],
|
151: _Opcode_name[482:487],
|
||||||
155: _Opcode_name[478:484],
|
152: _Opcode_name[487:495],
|
||||||
156: _Opcode_name[484:487],
|
153: _Opcode_name[495:499],
|
||||||
157: _Opcode_name[487:490],
|
154: _Opcode_name[499:502],
|
||||||
158: _Opcode_name[490:493],
|
155: _Opcode_name[502:508],
|
||||||
159: _Opcode_name[493:496],
|
156: _Opcode_name[508:511],
|
||||||
160: _Opcode_name[496:499],
|
157: _Opcode_name[511:514],
|
||||||
161: _Opcode_name[499:502],
|
158: _Opcode_name[514:517],
|
||||||
162: _Opcode_name[502:505],
|
159: _Opcode_name[517:520],
|
||||||
168: _Opcode_name[505:508],
|
160: _Opcode_name[520:523],
|
||||||
169: _Opcode_name[508:511],
|
161: _Opcode_name[523:526],
|
||||||
170: _Opcode_name[511:514],
|
162: _Opcode_name[526:529],
|
||||||
171: _Opcode_name[514:521],
|
168: _Opcode_name[529:532],
|
||||||
172: _Opcode_name[521:527],
|
169: _Opcode_name[532:535],
|
||||||
177: _Opcode_name[527:529],
|
170: _Opcode_name[535:538],
|
||||||
179: _Opcode_name[529:537],
|
171: _Opcode_name[538:545],
|
||||||
180: _Opcode_name[537:548],
|
172: _Opcode_name[545:551],
|
||||||
181: _Opcode_name[548:550],
|
177: _Opcode_name[551:553],
|
||||||
182: _Opcode_name[550:553],
|
179: _Opcode_name[553:561],
|
||||||
183: _Opcode_name[553:555],
|
180: _Opcode_name[561:572],
|
||||||
184: _Opcode_name[555:558],
|
181: _Opcode_name[572:574],
|
||||||
185: _Opcode_name[558:561],
|
182: _Opcode_name[574:577],
|
||||||
186: _Opcode_name[561:564],
|
183: _Opcode_name[577:579],
|
||||||
187: _Opcode_name[564:570],
|
184: _Opcode_name[579:582],
|
||||||
192: _Opcode_name[570:574],
|
185: _Opcode_name[582:585],
|
||||||
193: _Opcode_name[574:580],
|
186: _Opcode_name[585:588],
|
||||||
194: _Opcode_name[580:589],
|
187: _Opcode_name[588:594],
|
||||||
195: _Opcode_name[589:597],
|
192: _Opcode_name[594:598],
|
||||||
196: _Opcode_name[597:606],
|
193: _Opcode_name[598:604],
|
||||||
197: _Opcode_name[606:616],
|
194: _Opcode_name[604:613],
|
||||||
198: _Opcode_name[616:625],
|
195: _Opcode_name[613:621],
|
||||||
200: _Opcode_name[625:631],
|
196: _Opcode_name[621:630],
|
||||||
202: _Opcode_name[631:635],
|
197: _Opcode_name[630:640],
|
||||||
203: _Opcode_name[635:641],
|
198: _Opcode_name[640:649],
|
||||||
204: _Opcode_name[641:645],
|
200: _Opcode_name[649:655],
|
||||||
205: _Opcode_name[645:651],
|
202: _Opcode_name[655:659],
|
||||||
206: _Opcode_name[651:659],
|
203: _Opcode_name[659:665],
|
||||||
207: _Opcode_name[659:665],
|
204: _Opcode_name[665:669],
|
||||||
208: _Opcode_name[665:672],
|
205: _Opcode_name[669:675],
|
||||||
209: _Opcode_name[672:684],
|
206: _Opcode_name[675:683],
|
||||||
210: _Opcode_name[684:690],
|
207: _Opcode_name[683:689],
|
||||||
211: _Opcode_name[690:700],
|
208: _Opcode_name[689:696],
|
||||||
216: _Opcode_name[700:706],
|
209: _Opcode_name[696:708],
|
||||||
217: _Opcode_name[706:712],
|
210: _Opcode_name[708:714],
|
||||||
219: _Opcode_name[712:719],
|
211: _Opcode_name[714:724],
|
||||||
240: _Opcode_name[719:724],
|
216: _Opcode_name[724:730],
|
||||||
241: _Opcode_name[724:734],
|
217: _Opcode_name[730:736],
|
||||||
|
219: _Opcode_name[736:743],
|
||||||
|
240: _Opcode_name[743:748],
|
||||||
|
241: _Opcode_name[748:758],
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i Opcode) String() string {
|
func (i Opcode) String() string {
|
||||||
|
|
|
@ -353,9 +353,31 @@ func (s *Stack) Swap(n1, n2 int) error {
|
||||||
if n1 == n2 {
|
if n1 == n2 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
s.swap(n1, n2)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stack) swap(n1, n2 int) {
|
||||||
a := s.Peek(n1)
|
a := s.Peek(n1)
|
||||||
b := s.Peek(n2)
|
b := s.Peek(n2)
|
||||||
a.value, b.value = b.value, a.value
|
a.value, b.value = b.value, a.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReverseTop reverses top n items of the stack.
|
||||||
|
func (s *Stack) ReverseTop(n int) error {
|
||||||
|
if n < 0 {
|
||||||
|
return errors.New("negative index")
|
||||||
|
} else if n > s.len {
|
||||||
|
return errors.New("too big index")
|
||||||
|
} else if n <= 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, j := 0, n-1; i < j; {
|
||||||
|
s.swap(i, j)
|
||||||
|
i++
|
||||||
|
j--
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
pkg/vm/vm.go
12
pkg/vm/vm.go
|
@ -732,6 +732,18 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case opcode.REVERSE3, opcode.REVERSE4, opcode.REVERSEN:
|
||||||
|
n := 3
|
||||||
|
switch op {
|
||||||
|
case opcode.REVERSE4:
|
||||||
|
n = 4
|
||||||
|
case opcode.REVERSEN:
|
||||||
|
n = int(v.estack.Pop().BigInt().Int64())
|
||||||
|
}
|
||||||
|
if err := v.estack.ReverseTop(n); err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
// Bit operations.
|
// Bit operations.
|
||||||
case opcode.INVERT:
|
case opcode.INVERT:
|
||||||
// inplace
|
// inplace
|
||||||
|
|
|
@ -1049,22 +1049,32 @@ func runWithArgs(t *testing.T, prog []byte, result interface{}, args ...interfac
|
||||||
getTestFuncForVM(prog, result, args...)(t)
|
getTestFuncForVM(prog, result, args...)(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func(t *testing.T) {
|
func getCustomTestFuncForVM(prog []byte, check func(t *testing.T, v *VM), args ...interface{}) func(t *testing.T) {
|
||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
v := load(prog)
|
v := load(prog)
|
||||||
for i := range args {
|
for i := range args {
|
||||||
v.estack.PushVal(args[i])
|
v.estack.PushVal(args[i])
|
||||||
}
|
}
|
||||||
if result == nil {
|
if check == nil {
|
||||||
checkVMFailed(t, v)
|
checkVMFailed(t, v)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
runVM(t, v)
|
runVM(t, v)
|
||||||
require.Equal(t, 1, v.estack.Len())
|
check(t, v)
|
||||||
require.Equal(t, makeStackItem(result), v.estack.Pop().value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func(t *testing.T) {
|
||||||
|
var f func(t *testing.T, v *VM)
|
||||||
|
if result != nil {
|
||||||
|
f = func(t *testing.T, v *VM) {
|
||||||
|
require.Equal(t, 1, v.estack.Len())
|
||||||
|
require.Equal(t, makeStackItem(result), v.estack.Pop().value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getCustomTestFuncForVM(prog, f, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNOTEQUALByteArray(t *testing.T) {
|
func TestNOTEQUALByteArray(t *testing.T) {
|
||||||
prog := makeProgram(opcode.NOTEQUAL)
|
prog := makeProgram(opcode.NOTEQUAL)
|
||||||
t.Run("True", getTestFuncForVM(prog, true, []byte{1, 2}, []byte{0, 1, 2}))
|
t.Run("True", getTestFuncForVM(prog, true, []byte{1, 2}, []byte{0, 1, 2}))
|
||||||
|
@ -1568,6 +1578,37 @@ func TestROLLGood(t *testing.T) {
|
||||||
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCheckEStackFunc(items ...interface{}) func(t *testing.T, v *VM) {
|
||||||
|
return func(t *testing.T, v *VM) {
|
||||||
|
require.Equal(t, len(items), v.estack.Len())
|
||||||
|
for i := 0; i < len(items); i++ {
|
||||||
|
assert.Equal(t, makeStackItem(items[i]), v.estack.Peek(i).Item())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestREVERSE3(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.REVERSE3)
|
||||||
|
t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2))
|
||||||
|
t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3), 1, 2, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestREVERSE4(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.REVERSE4)
|
||||||
|
t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2, 3))
|
||||||
|
t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4), 1, 2, 3, 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestREVERSEN(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.REVERSEN)
|
||||||
|
t.Run("NoArgument", getTestFuncForVM(prog, nil))
|
||||||
|
t.Run("SmallStack", getTestFuncForVM(prog, nil, 1, 2, 3))
|
||||||
|
t.Run("NegativeArgument", getTestFuncForVM(prog, nil, 1, 2, -1))
|
||||||
|
t.Run("Zero", getCustomTestFuncForVM(prog, getCheckEStackFunc(3, 2, 1), 1, 2, 3, 0))
|
||||||
|
t.Run("OneItem", getCustomTestFuncForVM(prog, getCheckEStackFunc(42), 42, 1))
|
||||||
|
t.Run("Good", getCustomTestFuncForVM(prog, getCheckEStackFunc(1, 2, 3, 4, 5), 1, 2, 3, 4, 5, 5))
|
||||||
|
}
|
||||||
|
|
||||||
func TestXTUCK(t *testing.T) {
|
func TestXTUCK(t *testing.T) {
|
||||||
prog := makeProgram(opcode.XTUCK)
|
prog := makeProgram(opcode.XTUCK)
|
||||||
t.Run("NoItem", getTestFuncForVM(prog, nil, 1))
|
t.Run("NoItem", getTestFuncForVM(prog, nil, 1))
|
||||||
|
|
Loading…
Reference in a new issue