mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-25 13:47:19 +00:00
vm: expose Context slots, hide Set/ClearRefs on Slot, deprecate Dump*Slot methods
Signed-off-by: ixje <erik@coz.io>
This commit is contained in:
parent
dda2cafdf8
commit
7ec0c1155c
7 changed files with 70 additions and 33 deletions
12
ROADMAP.md
12
ROADMAP.md
|
@ -68,4 +68,14 @@ event-based waiter fallbacks to the old way of block monitoring with
|
|||
`block_added` notifications subscription.
|
||||
|
||||
Removal of stale RPC server compatibility code from `waiter.EventWaiter` is
|
||||
scheduled for Jun-Jul 2024 (~0.107.0 release).
|
||||
scheduled for Jun-Jul 2024 (~0.107.0 release).
|
||||
|
||||
## Dump*Slot() methods of `vm.Context`
|
||||
|
||||
The following new methods have been exposed to give access to VM context slot contents
|
||||
with greater flexibility:
|
||||
- `ArgumentsSlot`
|
||||
- `LocalsSlot`
|
||||
- `StaticsSlot`.
|
||||
|
||||
Removal of the `Dump*Slot()` methods are scheduled for the 0.108.0 release.
|
|
@ -648,11 +648,11 @@ func handleSlots(c *cli.Context) error {
|
|||
var rawSlot string
|
||||
switch c.Command.Name {
|
||||
case "sslot":
|
||||
rawSlot = vmCtx.DumpStaticSlot()
|
||||
rawSlot = dumpSlot(vmCtx.StaticsSlot())
|
||||
case "lslot":
|
||||
rawSlot = vmCtx.DumpLocalSlot()
|
||||
rawSlot = dumpSlot(vmCtx.LocalsSlot())
|
||||
case "aslot":
|
||||
rawSlot = vmCtx.DumpArgumentsSlot()
|
||||
rawSlot = dumpSlot(vmCtx.ArgumentsSlot())
|
||||
default:
|
||||
return errors.New("unknown slot")
|
||||
}
|
||||
|
@ -660,6 +660,14 @@ func handleSlots(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func dumpSlot(s *vm.Slot) string {
|
||||
if s == nil {
|
||||
return "[]"
|
||||
}
|
||||
b, _ := json.MarshalIndent(s, "", " ")
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// prepareVM retrieves --historic flag from context (if set) and resets app state
|
||||
// (to the specified historic height if given).
|
||||
func prepareVM(c *cli.Context, tx *transaction.Transaction) error {
|
||||
|
|
|
@ -30,7 +30,7 @@ type scriptContext struct {
|
|||
// Evaluation stack pointer.
|
||||
estack *Stack
|
||||
|
||||
static slot
|
||||
static Slot
|
||||
|
||||
// Script hash of the prog.
|
||||
scriptHash util.Uint160
|
||||
|
@ -65,8 +65,8 @@ type Context struct {
|
|||
|
||||
sc *scriptContext
|
||||
|
||||
local slot
|
||||
arguments slot
|
||||
local Slot
|
||||
arguments Slot
|
||||
|
||||
// Exception context stack.
|
||||
tryStack Stack
|
||||
|
@ -278,22 +278,26 @@ func (c *Context) IsDeployed() bool {
|
|||
}
|
||||
|
||||
// DumpStaticSlot returns json formatted representation of the given slot.
|
||||
// Deprecated: to be removed in next version. Use [Context.StaticsSlot] instead.
|
||||
func (c *Context) DumpStaticSlot() string {
|
||||
return dumpSlot(&c.sc.static)
|
||||
}
|
||||
|
||||
// DumpLocalSlot returns json formatted representation of the given slot.
|
||||
// Deprecated: to be removed in next version. Use [Context.LocalsSlot] instead.
|
||||
func (c *Context) DumpLocalSlot() string {
|
||||
return dumpSlot(&c.local)
|
||||
}
|
||||
|
||||
// DumpArgumentsSlot returns json formatted representation of the given slot.
|
||||
// Deprecated: to be removed in next version. Use [Context.ArgumentsSlot] instead.
|
||||
func (c *Context) DumpArgumentsSlot() string {
|
||||
return dumpSlot(&c.arguments)
|
||||
}
|
||||
|
||||
// dumpSlot returns json formatted representation of the given slot.
|
||||
func dumpSlot(s *slot) string {
|
||||
// Deprecated: to be removed in next version.
|
||||
func dumpSlot(s *Slot) string {
|
||||
if s == nil || *s == nil {
|
||||
return "[]"
|
||||
}
|
||||
|
@ -354,3 +358,18 @@ func DynamicOnUnload(v *VM, ctx *Context, commit bool) error {
|
|||
func (c *Context) BreakPoints() []int {
|
||||
return slices.Clone(c.sc.breakPoints)
|
||||
}
|
||||
|
||||
// ArgumentsSlot returns the arguments slot of Context.
|
||||
func (c *Context) ArgumentsSlot() *Slot {
|
||||
return &c.arguments
|
||||
}
|
||||
|
||||
// LocalsSlot returns the local slot of Context.
|
||||
func (c *Context) LocalsSlot() *Slot {
|
||||
return &c.local
|
||||
}
|
||||
|
||||
// StaticsSlot returns the static slot of Context.
|
||||
func (c *Context) StaticsSlot() *Slot {
|
||||
return &c.sc.static
|
||||
}
|
||||
|
|
|
@ -240,7 +240,7 @@ func compareStacks(t *testing.T, expected []vmUTStackItem, actual *Stack) {
|
|||
compareItemArrays(t, expected, actual.Len(), func(i int) stackitem.Item { return actual.Peek(i).Item() })
|
||||
}
|
||||
|
||||
func compareSlots(t *testing.T, expected []vmUTStackItem, actual slot) {
|
||||
func compareSlots(t *testing.T, expected []vmUTStackItem, actual Slot) {
|
||||
if actual == nil && len(expected) == 0 {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// slot is a fixed-size slice of stack items.
|
||||
type slot []stackitem.Item
|
||||
// Slot is a fixed-size slice of stack items.
|
||||
type Slot []stackitem.Item
|
||||
|
||||
// init sets static slot size to n. It is intended to be used only by INITSSLOT.
|
||||
func (s *slot) init(n int, rc *refCounter) {
|
||||
func (s *Slot) init(n int, rc *refCounter) {
|
||||
if *s != nil {
|
||||
panic("already initialized")
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ func (s *slot) init(n int, rc *refCounter) {
|
|||
*rc += refCounter(n) // Virtual "Null" elements.
|
||||
}
|
||||
|
||||
// Set sets i-th storage slot.
|
||||
func (s slot) Set(i int, item stackitem.Item, refs *refCounter) {
|
||||
// set sets i-th storage slot.
|
||||
func (s Slot) set(i int, item stackitem.Item, refs *refCounter) {
|
||||
if s[i] == item {
|
||||
return
|
||||
}
|
||||
|
@ -29,30 +29,30 @@ func (s slot) Set(i int, item stackitem.Item, refs *refCounter) {
|
|||
}
|
||||
|
||||
// Get returns the item contained in the i-th slot.
|
||||
func (s slot) Get(i int) stackitem.Item {
|
||||
func (s Slot) Get(i int) stackitem.Item {
|
||||
if item := s[i]; item != nil {
|
||||
return item
|
||||
}
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
// ClearRefs removes all slot variables from the reference counter.
|
||||
func (s slot) ClearRefs(refs *refCounter) {
|
||||
// clearRefs removes all slot variables from the reference counter.
|
||||
func (s Slot) clearRefs(refs *refCounter) {
|
||||
for _, item := range s {
|
||||
refs.Remove(item)
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the slot size.
|
||||
func (s slot) Size() int {
|
||||
func (s Slot) Size() int {
|
||||
if s == nil {
|
||||
panic("not initialized")
|
||||
return 0
|
||||
}
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the JSON marshalling interface.
|
||||
func (s slot) MarshalJSON() ([]byte, error) {
|
||||
func (s Slot) MarshalJSON() ([]byte, error) {
|
||||
arr := make([]json.RawMessage, len(s))
|
||||
for i := range s {
|
||||
data, err := stackitem.ToJSONWithTypes(s[i])
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
|
||||
func TestSlot_Get(t *testing.T) {
|
||||
rc := newRefCounter()
|
||||
var s slot
|
||||
require.Panics(t, func() { s.Size() })
|
||||
var s Slot
|
||||
require.Equal(t, 0, s.Size())
|
||||
|
||||
s.init(3, rc)
|
||||
require.Equal(t, 3, s.Size())
|
||||
|
@ -21,7 +21,7 @@ func TestSlot_Get(t *testing.T) {
|
|||
item := s.Get(2)
|
||||
require.Equal(t, stackitem.Null{}, item)
|
||||
|
||||
s.Set(1, stackitem.NewBigInteger(big.NewInt(42)), rc)
|
||||
s.set(1, stackitem.NewBigInteger(big.NewInt(42)), rc)
|
||||
require.Equal(t, stackitem.NewBigInteger(big.NewInt(42)), s.Get(1))
|
||||
require.Equal(t, 3, int(*rc))
|
||||
}
|
||||
|
|
20
pkg/vm/vm.go
20
pkg/vm/vm.go
|
@ -697,7 +697,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
sz := int(parameter[1])
|
||||
ctx.arguments.init(sz, &v.refs)
|
||||
for i := range sz {
|
||||
ctx.arguments.Set(i, v.estack.Pop().Item(), &v.refs)
|
||||
ctx.arguments.set(i, v.estack.Pop().Item(), &v.refs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -711,11 +711,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
|
||||
case opcode.STSFLD0, opcode.STSFLD1, opcode.STSFLD2, opcode.STSFLD3, opcode.STSFLD4, opcode.STSFLD5, opcode.STSFLD6:
|
||||
item := v.estack.Pop().Item()
|
||||
ctx.sc.static.Set(int(op-opcode.STSFLD0), item, &v.refs)
|
||||
ctx.sc.static.set(int(op-opcode.STSFLD0), item, &v.refs)
|
||||
|
||||
case opcode.STSFLD:
|
||||
item := v.estack.Pop().Item()
|
||||
ctx.sc.static.Set(int(parameter[0]), item, &v.refs)
|
||||
ctx.sc.static.set(int(parameter[0]), item, &v.refs)
|
||||
|
||||
case opcode.LDLOC0, opcode.LDLOC1, opcode.LDLOC2, opcode.LDLOC3, opcode.LDLOC4, opcode.LDLOC5, opcode.LDLOC6:
|
||||
item := ctx.local.Get(int(op - opcode.LDLOC0))
|
||||
|
@ -727,11 +727,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
|
||||
case opcode.STLOC0, opcode.STLOC1, opcode.STLOC2, opcode.STLOC3, opcode.STLOC4, opcode.STLOC5, opcode.STLOC6:
|
||||
item := v.estack.Pop().Item()
|
||||
ctx.local.Set(int(op-opcode.STLOC0), item, &v.refs)
|
||||
ctx.local.set(int(op-opcode.STLOC0), item, &v.refs)
|
||||
|
||||
case opcode.STLOC:
|
||||
item := v.estack.Pop().Item()
|
||||
ctx.local.Set(int(parameter[0]), item, &v.refs)
|
||||
ctx.local.set(int(parameter[0]), item, &v.refs)
|
||||
|
||||
case opcode.LDARG0, opcode.LDARG1, opcode.LDARG2, opcode.LDARG3, opcode.LDARG4, opcode.LDARG5, opcode.LDARG6:
|
||||
item := ctx.arguments.Get(int(op - opcode.LDARG0))
|
||||
|
@ -743,11 +743,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
|
||||
case opcode.STARG0, opcode.STARG1, opcode.STARG2, opcode.STARG3, opcode.STARG4, opcode.STARG5, opcode.STARG6:
|
||||
item := v.estack.Pop().Item()
|
||||
ctx.arguments.Set(int(op-opcode.STARG0), item, &v.refs)
|
||||
ctx.arguments.set(int(op-opcode.STARG0), item, &v.refs)
|
||||
|
||||
case opcode.STARG:
|
||||
item := v.estack.Pop().Item()
|
||||
ctx.arguments.Set(int(parameter[0]), item, &v.refs)
|
||||
ctx.arguments.set(int(parameter[0]), item, &v.refs)
|
||||
|
||||
case opcode.NEWBUFFER:
|
||||
n := toInt(v.estack.Pop().BigInt())
|
||||
|
@ -1692,15 +1692,15 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
|
||||
func (v *VM) unloadContext(ctx *Context) {
|
||||
if ctx.local != nil {
|
||||
ctx.local.ClearRefs(&v.refs)
|
||||
ctx.local.clearRefs(&v.refs)
|
||||
}
|
||||
if ctx.arguments != nil {
|
||||
ctx.arguments.ClearRefs(&v.refs)
|
||||
ctx.arguments.clearRefs(&v.refs)
|
||||
}
|
||||
currCtx := v.Context()
|
||||
if currCtx == nil || ctx.sc != currCtx.sc {
|
||||
if ctx.sc.static != nil {
|
||||
ctx.sc.static.ClearRefs(&v.refs)
|
||||
ctx.sc.static.clearRefs(&v.refs)
|
||||
}
|
||||
if ctx.sc.onUnload != nil {
|
||||
err := ctx.sc.onUnload(v, ctx, v.uncaughtException == nil)
|
||||
|
|
Loading…
Reference in a new issue