forked from TrueCloudLab/neoneo-go
vm: implement NEWARRAYT opcode
This commit is contained in:
parent
d3b9aef8e2
commit
7c3d7c0261
5 changed files with 75 additions and 29 deletions
|
@ -101,7 +101,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
|
||||||
}
|
}
|
||||||
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.JMPEQ, opcode.JMPNE,
|
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.JMPEQ, opcode.JMPNE,
|
||||||
opcode.JMPGT, opcode.JMPGE, opcode.JMPLT, opcode.JMPLE,
|
opcode.JMPGT, opcode.JMPGE, opcode.JMPLT, opcode.JMPLE,
|
||||||
opcode.CALL, opcode.ISTYPE:
|
opcode.CALL, opcode.ISTYPE, opcode.NEWARRAYT:
|
||||||
numtoread = 1
|
numtoread = 1
|
||||||
case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL,
|
case opcode.JMPL, opcode.JMPIFL, opcode.JMPIFNOTL, opcode.JMPEQL, opcode.JMPNEL,
|
||||||
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL,
|
opcode.JMPGTL, opcode.JMPGEL, opcode.JMPLTL, opcode.JMPLEL,
|
||||||
|
|
|
@ -147,7 +147,7 @@ const (
|
||||||
UNPACK Opcode = 0xC1
|
UNPACK Opcode = 0xC1
|
||||||
NEWARRAY0 Opcode = 0xC2
|
NEWARRAY0 Opcode = 0xC2
|
||||||
NEWARRAY Opcode = 0xC3
|
NEWARRAY Opcode = 0xC3
|
||||||
// NEWARRAYT Opcode = 0xC4
|
NEWARRAYT Opcode = 0xC4
|
||||||
NEWSTRUCT0 Opcode = 0xC5
|
NEWSTRUCT0 Opcode = 0xC5
|
||||||
NEWSTRUCT Opcode = 0xC6
|
NEWSTRUCT Opcode = 0xC6
|
||||||
NEWMAP Opcode = 0xC8
|
NEWMAP Opcode = 0xC8
|
||||||
|
|
|
@ -126,6 +126,7 @@ func _() {
|
||||||
_ = x[UNPACK-193]
|
_ = x[UNPACK-193]
|
||||||
_ = x[NEWARRAY0-194]
|
_ = x[NEWARRAY0-194]
|
||||||
_ = x[NEWARRAY-195]
|
_ = x[NEWARRAY-195]
|
||||||
|
_ = x[NEWARRAYT-196]
|
||||||
_ = x[NEWSTRUCT0-197]
|
_ = x[NEWSTRUCT0-197]
|
||||||
_ = x[NEWSTRUCT-198]
|
_ = x[NEWSTRUCT-198]
|
||||||
_ = x[NEWMAP-200]
|
_ = x[NEWMAP-200]
|
||||||
|
@ -139,11 +140,12 @@ func _() {
|
||||||
_ = x[REVERSEITEMS-209]
|
_ = x[REVERSEITEMS-209]
|
||||||
_ = x[REMOVE-210]
|
_ = x[REMOVE-210]
|
||||||
_ = x[CLEARITEMS-211]
|
_ = x[CLEARITEMS-211]
|
||||||
|
_ = x[ISTYPE-217]
|
||||||
_ = x[THROW-240]
|
_ = x[THROW-240]
|
||||||
_ = x[THROWIFNOT-241]
|
_ = x[THROWIFNOT-241]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPISNULLXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGPACKUNPACKNEWARRAY0NEWARRAYNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSTHROWTHROWIFNOT"
|
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPISNULLXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISTYPETHROWTHROWIFNOT"
|
||||||
|
|
||||||
var _Opcode_map = map[Opcode]string{
|
var _Opcode_map = map[Opcode]string{
|
||||||
0: _Opcode_name[0:8],
|
0: _Opcode_name[0:8],
|
||||||
|
@ -262,21 +264,23 @@ var _Opcode_map = map[Opcode]string{
|
||||||
193: _Opcode_name[621:627],
|
193: _Opcode_name[621:627],
|
||||||
194: _Opcode_name[627:636],
|
194: _Opcode_name[627:636],
|
||||||
195: _Opcode_name[636:644],
|
195: _Opcode_name[636:644],
|
||||||
197: _Opcode_name[644:654],
|
196: _Opcode_name[644:653],
|
||||||
198: _Opcode_name[654:663],
|
197: _Opcode_name[653:663],
|
||||||
200: _Opcode_name[663:669],
|
198: _Opcode_name[663:672],
|
||||||
202: _Opcode_name[669:673],
|
200: _Opcode_name[672:678],
|
||||||
203: _Opcode_name[673:679],
|
202: _Opcode_name[678:682],
|
||||||
204: _Opcode_name[679:683],
|
203: _Opcode_name[682:688],
|
||||||
205: _Opcode_name[683:689],
|
204: _Opcode_name[688:692],
|
||||||
206: _Opcode_name[689:697],
|
205: _Opcode_name[692:698],
|
||||||
207: _Opcode_name[697:703],
|
206: _Opcode_name[698:706],
|
||||||
208: _Opcode_name[703:710],
|
207: _Opcode_name[706:712],
|
||||||
209: _Opcode_name[710:722],
|
208: _Opcode_name[712:719],
|
||||||
210: _Opcode_name[722:728],
|
209: _Opcode_name[719:731],
|
||||||
211: _Opcode_name[728:738],
|
210: _Opcode_name[731:737],
|
||||||
240: _Opcode_name[738:743],
|
211: _Opcode_name[737:747],
|
||||||
241: _Opcode_name[743:753],
|
217: _Opcode_name[747:753],
|
||||||
|
240: _Opcode_name[753:758],
|
||||||
|
241: _Opcode_name[758:768],
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i Opcode) String() string {
|
func (i Opcode) String() string {
|
||||||
|
|
26
pkg/vm/vm.go
26
pkg/vm/vm.go
|
@ -919,7 +919,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
case opcode.NEWARRAY0:
|
case opcode.NEWARRAY0:
|
||||||
v.estack.PushVal(&ArrayItem{[]StackItem{}})
|
v.estack.PushVal(&ArrayItem{[]StackItem{}})
|
||||||
|
|
||||||
case opcode.NEWARRAY:
|
case opcode.NEWARRAY, opcode.NEWARRAYT:
|
||||||
item := v.estack.Pop()
|
item := v.estack.Pop()
|
||||||
switch t := item.value.(type) {
|
switch t := item.value.(type) {
|
||||||
case *StructItem:
|
case *StructItem:
|
||||||
|
@ -933,7 +933,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
if n > MaxArraySize {
|
if n > MaxArraySize {
|
||||||
panic("too long array")
|
panic("too long array")
|
||||||
}
|
}
|
||||||
items := makeArrayOfFalses(int(n))
|
typ := BooleanT
|
||||||
|
if op == opcode.NEWARRAYT {
|
||||||
|
typ = StackItemType(parameter[0])
|
||||||
|
}
|
||||||
|
items := makeArrayOfType(int(n), typ)
|
||||||
v.estack.PushVal(&ArrayItem{items})
|
v.estack.PushVal(&ArrayItem{items})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -954,7 +958,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
if n > MaxArraySize {
|
if n > MaxArraySize {
|
||||||
panic("too long struct")
|
panic("too long struct")
|
||||||
}
|
}
|
||||||
items := makeArrayOfFalses(int(n))
|
items := makeArrayOfType(int(n), BooleanT)
|
||||||
v.estack.PushVal(&StructItem{items})
|
v.estack.PushVal(&StructItem{items})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1492,10 +1496,22 @@ func cloneIfStruct(item StackItem) StackItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeArrayOfFalses(n int) []StackItem {
|
func makeArrayOfType(n int, typ StackItemType) []StackItem {
|
||||||
|
if !typ.IsValid() {
|
||||||
|
panic(fmt.Sprintf("invalid stack item type: %d", typ))
|
||||||
|
}
|
||||||
items := make([]StackItem, n)
|
items := make([]StackItem, n)
|
||||||
for i := range items {
|
for i := range items {
|
||||||
items[i] = &BoolItem{false}
|
switch typ {
|
||||||
|
case BooleanT:
|
||||||
|
items[i] = NewBoolItem(false)
|
||||||
|
case IntegerT:
|
||||||
|
items[i] = NewBigIntegerItem(big.NewInt(0))
|
||||||
|
case ByteArrayT:
|
||||||
|
items[i] = NewByteArrayItem([]byte{})
|
||||||
|
default:
|
||||||
|
items[i] = NullItem{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
|
@ -660,7 +660,7 @@ func TestSerializeArray(t *testing.T) {
|
||||||
|
|
||||||
func TestSerializeArrayBad(t *testing.T) {
|
func TestSerializeArrayBad(t *testing.T) {
|
||||||
vm := load(getSerializeProg())
|
vm := load(getSerializeProg())
|
||||||
item := NewArrayItem(makeArrayOfFalses(2))
|
item := NewArrayItem(makeArrayOfType(2, BooleanT))
|
||||||
item.value[1] = item
|
item.value[1] = item
|
||||||
|
|
||||||
vm.estack.Push(&Element{value: item})
|
vm.estack.Push(&Element{value: item})
|
||||||
|
@ -1337,7 +1337,7 @@ func testNEWARRAYIssue437(t *testing.T, i1, i2 opcode.Opcode, appended bool) {
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
vm.Run()
|
vm.Run()
|
||||||
|
|
||||||
arr := makeArrayOfFalses(4)
|
arr := makeArrayOfType(4, BooleanT)
|
||||||
arr[2] = makeStackItem(3)
|
arr[2] = makeStackItem(3)
|
||||||
arr[3] = makeStackItem(4)
|
arr[3] = makeStackItem(4)
|
||||||
if appended {
|
if appended {
|
||||||
|
@ -1379,6 +1379,32 @@ func TestNEWARRAYByteArray(t *testing.T) {
|
||||||
assert.Equal(t, &ArrayItem{[]StackItem{}}, vm.estack.Pop().value)
|
assert.Equal(t, &ArrayItem{[]StackItem{}}, vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testNEWARRAYT(t *testing.T, typ StackItemType, item StackItem) {
|
||||||
|
prog := makeProgram(opcode.NEWARRAYT, opcode.Opcode(typ), opcode.PUSH0, opcode.PICKITEM)
|
||||||
|
v := load(prog)
|
||||||
|
v.estack.PushVal(1)
|
||||||
|
if item == nil {
|
||||||
|
checkVMFailed(t, v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
runVM(t, v)
|
||||||
|
require.Equal(t, 1, v.estack.Len())
|
||||||
|
require.Equal(t, item, v.estack.Pop().Item())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNEWARRAYT(t *testing.T) {
|
||||||
|
testCases := map[StackItemType]StackItem{
|
||||||
|
BooleanT: NewBoolItem(false),
|
||||||
|
IntegerT: NewBigIntegerItem(big.NewInt(0)),
|
||||||
|
ByteArrayT: NewByteArrayItem([]byte{}),
|
||||||
|
ArrayT: NullItem{},
|
||||||
|
0xFF: nil,
|
||||||
|
}
|
||||||
|
for typ, item := range testCases {
|
||||||
|
t.Run(typ.String(), func(t *testing.T) { testNEWARRAYT(t, typ, item) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNEWARRAYBadSize(t *testing.T) {
|
func TestNEWARRAYBadSize(t *testing.T) {
|
||||||
prog := makeProgram(opcode.NEWARRAY)
|
prog := makeProgram(opcode.NEWARRAY)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
|
Loading…
Reference in a new issue