mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-24 09:25:21 +00:00
vm: allow to initialize static slot in method
This commit is contained in:
parent
28e0661f82
commit
6ecd1ae437
5 changed files with 37 additions and 14 deletions
|
@ -228,7 +228,7 @@ func compareStacks(t *testing.T, expected []vmUTStackItem, actual *Stack) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareSlots(t *testing.T, expected []vmUTStackItem, actual *Slot) {
|
func compareSlots(t *testing.T, expected []vmUTStackItem, actual *Slot) {
|
||||||
if actual == nil && len(expected) == 0 {
|
if actual.storage == nil && len(expected) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
require.NotNil(t, actual)
|
require.NotNil(t, actual)
|
||||||
|
|
|
@ -10,16 +10,25 @@ type Slot struct {
|
||||||
refs *refCounter
|
refs *refCounter
|
||||||
}
|
}
|
||||||
|
|
||||||
// newSlot returns new slot of n items.
|
// newSlot returns new slot with the provided reference counter.
|
||||||
func newSlot(n int, refs *refCounter) *Slot {
|
func newSlot(refs *refCounter) *Slot {
|
||||||
return &Slot{
|
return &Slot{
|
||||||
storage: make([]stackitem.Item, n),
|
|
||||||
refs: refs,
|
refs: refs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// init sets static slot size to n. It is intended to be used only by INITSSLOT.
|
||||||
|
func (s *Slot) init(n int) {
|
||||||
|
if s.storage != nil {
|
||||||
|
panic("already initialized")
|
||||||
|
}
|
||||||
|
s.storage = make([]stackitem.Item, n)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *VM) newSlot(n int) *Slot {
|
func (v *VM) newSlot(n int) *Slot {
|
||||||
return newSlot(n, v.refs)
|
s := newSlot(v.refs)
|
||||||
|
s.init(n)
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets i-th storage slot.
|
// Set sets i-th storage slot.
|
||||||
|
@ -43,12 +52,17 @@ func (s *Slot) Get(i int) stackitem.Item {
|
||||||
return stackitem.Null{}
|
return stackitem.Null{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns slot size.
|
|
||||||
func (s *Slot) Size() int { return len(s.storage) }
|
|
||||||
|
|
||||||
// Clear removes all slot variables from reference counter.
|
// Clear removes all slot variables from reference counter.
|
||||||
func (s *Slot) Clear() {
|
func (s *Slot) Clear() {
|
||||||
for _, item := range s.storage {
|
for _, item := range s.storage {
|
||||||
s.refs.Remove(item)
|
s.refs.Remove(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Size returns slot size.
|
||||||
|
func (s *Slot) Size() int {
|
||||||
|
if s.storage == nil {
|
||||||
|
panic("not initialized")
|
||||||
|
}
|
||||||
|
return len(s.storage)
|
||||||
|
}
|
||||||
|
|
|
@ -9,8 +9,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSlot_Get(t *testing.T) {
|
func TestSlot_Get(t *testing.T) {
|
||||||
s := newSlot(3, newRefCounter())
|
s := newSlot(newRefCounter())
|
||||||
require.NotNil(t, s)
|
require.NotNil(t, s)
|
||||||
|
require.Panics(t, func() { s.Size() })
|
||||||
|
|
||||||
|
s.init(3)
|
||||||
require.Equal(t, 3, s.Size())
|
require.Equal(t, 3, s.Size())
|
||||||
|
|
||||||
// Null is the default
|
// Null is the default
|
||||||
|
|
|
@ -282,6 +282,7 @@ func (v *VM) LoadScriptWithFlags(b []byte, f smartcontract.CallFlag) {
|
||||||
ctx.estack = v.estack
|
ctx.estack = v.estack
|
||||||
ctx.tryStack = NewStack("exception")
|
ctx.tryStack = NewStack("exception")
|
||||||
ctx.callFlag = f
|
ctx.callFlag = f
|
||||||
|
ctx.static = newSlot(v.refs)
|
||||||
v.istack.PushVal(ctx)
|
v.istack.PushVal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,13 +569,10 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
v.estack.PushVal(result)
|
v.estack.PushVal(result)
|
||||||
|
|
||||||
case opcode.INITSSLOT:
|
case opcode.INITSSLOT:
|
||||||
if ctx.static != nil {
|
|
||||||
panic("already initialized")
|
|
||||||
}
|
|
||||||
if parameter[0] == 0 {
|
if parameter[0] == 0 {
|
||||||
panic("zero argument")
|
panic("zero argument")
|
||||||
}
|
}
|
||||||
ctx.static = v.newSlot(int(parameter[0]))
|
ctx.static.init(int(parameter[0]))
|
||||||
|
|
||||||
case opcode.INITSLOT:
|
case opcode.INITSLOT:
|
||||||
if ctx.local != nil || ctx.arguments != nil {
|
if ctx.local != nil || ctx.arguments != nil {
|
||||||
|
|
|
@ -2596,6 +2596,14 @@ func TestSLOTOpcodes(t *testing.T) {
|
||||||
t.Run("Local", getTestFuncForVM(makeProgram(opcode.INITSLOT, 8, 0, opcode.STLOC, 7, opcode.LDLOC, 7), 42, 42))
|
t.Run("Local", getTestFuncForVM(makeProgram(opcode.INITSLOT, 8, 0, opcode.STLOC, 7, opcode.LDLOC, 7), 42, 42))
|
||||||
t.Run("Argument", getTestFuncForVM(makeProgram(opcode.INITSLOT, 0, 2, opcode.STARG, 1, opcode.LDARG, 1), 42, 42, 1, 2))
|
t.Run("Argument", getTestFuncForVM(makeProgram(opcode.INITSLOT, 0, 2, opcode.STARG, 1, opcode.LDARG, 1), 42, 42, 1, 2))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("InitStaticSlotInMethod", func(t *testing.T) {
|
||||||
|
prog := makeProgram(
|
||||||
|
opcode.CALL, 4, opcode.LDSFLD0, opcode.RET,
|
||||||
|
opcode.INITSSLOT, 1, opcode.PUSH12, opcode.STSFLD0, opcode.RET,
|
||||||
|
)
|
||||||
|
runWithArgs(t, prog, 12)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeProgram(opcodes ...opcode.Opcode) []byte {
|
func makeProgram(opcodes ...opcode.Opcode) []byte {
|
||||||
|
|
Loading…
Reference in a new issue