mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 23:25:22 +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) {
|
||||
if actual == nil && len(expected) == 0 {
|
||||
if actual.storage == nil && len(expected) == 0 {
|
||||
return
|
||||
}
|
||||
require.NotNil(t, actual)
|
||||
|
|
|
@ -10,16 +10,25 @@ type Slot struct {
|
|||
refs *refCounter
|
||||
}
|
||||
|
||||
// newSlot returns new slot of n items.
|
||||
func newSlot(n int, refs *refCounter) *Slot {
|
||||
// newSlot returns new slot with the provided reference counter.
|
||||
func newSlot(refs *refCounter) *Slot {
|
||||
return &Slot{
|
||||
storage: make([]stackitem.Item, n),
|
||||
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 {
|
||||
return newSlot(n, v.refs)
|
||||
s := newSlot(v.refs)
|
||||
s.init(n)
|
||||
return s
|
||||
}
|
||||
|
||||
// Set sets i-th storage slot.
|
||||
|
@ -43,12 +52,17 @@ func (s *Slot) Get(i int) stackitem.Item {
|
|||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
// Size returns slot size.
|
||||
func (s *Slot) Size() int { return len(s.storage) }
|
||||
|
||||
// Clear removes all slot variables from reference counter.
|
||||
func (s *Slot) Clear() {
|
||||
for _, item := range s.storage {
|
||||
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) {
|
||||
s := newSlot(3, newRefCounter())
|
||||
s := newSlot(newRefCounter())
|
||||
require.NotNil(t, s)
|
||||
require.Panics(t, func() { s.Size() })
|
||||
|
||||
s.init(3)
|
||||
require.Equal(t, 3, s.Size())
|
||||
|
||||
// Null is the default
|
||||
|
|
|
@ -282,6 +282,7 @@ func (v *VM) LoadScriptWithFlags(b []byte, f smartcontract.CallFlag) {
|
|||
ctx.estack = v.estack
|
||||
ctx.tryStack = NewStack("exception")
|
||||
ctx.callFlag = f
|
||||
ctx.static = newSlot(v.refs)
|
||||
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)
|
||||
|
||||
case opcode.INITSSLOT:
|
||||
if ctx.static != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
if parameter[0] == 0 {
|
||||
panic("zero argument")
|
||||
}
|
||||
ctx.static = v.newSlot(int(parameter[0]))
|
||||
ctx.static.init(int(parameter[0]))
|
||||
|
||||
case opcode.INITSLOT:
|
||||
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("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 {
|
||||
|
|
Loading…
Reference in a new issue