forked from TrueCloudLab/neoneo-go
ee05f73b6f
Hiding refcounter inside a slot is actually a good idea, but it makes the structure somewhat bigger, especially given that the refcounter is the same and belongs more to VM or Context. New structure is a bit more efficient: name old time/op new time/op delta ScriptFibonacci-8 672µs ± 2% 644µs ± 0% -4.15% (p=0.008 n=5+5) ScriptNestedRefCount-8 1.08ms ± 1% 1.05ms ± 2% -2.56% (p=0.008 n=5+5) ScriptPushPop/4-8 1.52µs ± 1% 1.47µs ± 1% -3.14% (p=0.008 n=5+5) ScriptPushPop/16-8 3.66µs ± 1% 3.54µs ± 1% -3.24% (p=0.008 n=5+5) ScriptPushPop/128-8 24.7µs ± 1% 23.2µs ± 1% -6.14% (p=0.008 n=5+5) ScriptPushPop/1024-8 183µs ± 1% 173µs ± 1% -5.01% (p=0.008 n=5+5) name old alloc/op new alloc/op delta ScriptFibonacci-8 114kB ± 0% 114kB ± 0% ~ (p=0.079 n=4+5) ScriptNestedRefCount-8 241kB ± 0% 241kB ± 0% ~ (p=0.333 n=5+4) ScriptPushPop/4-8 160B ± 0% 160B ± 0% ~ (all equal) ScriptPushPop/16-8 640B ± 0% 640B ± 0% ~ (all equal) ScriptPushPop/128-8 8.70kB ± 0% 8.70kB ± 0% ~ (all equal) ScriptPushPop/1024-8 73.2kB ± 0% 73.2kB ± 0% ~ (all equal) name old allocs/op new allocs/op delta ScriptFibonacci-8 3.17k ± 0% 3.17k ± 0% -0.03% (p=0.008 n=5+5) ScriptNestedRefCount-8 10.7k ± 0% 10.7k ± 0% ~ (all equal) ScriptPushPop/4-8 8.00 ± 0% 8.00 ± 0% ~ (all equal) ScriptPushPop/16-8 32.0 ± 0% 32.0 ± 0% ~ (all equal) ScriptPushPop/128-8 259 ± 0% 259 ± 0% ~ (all equal) ScriptPushPop/1024-8 2.05k ± 0% 2.05k ± 0% ~ (all equal) It'd be especially nice to internalize static slot, but as we can't compare slices it's not possible.
66 lines
1.3 KiB
Go
66 lines
1.3 KiB
Go
package vm
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
)
|
|
|
|
// 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) {
|
|
if *s != nil {
|
|
panic("already initialized")
|
|
}
|
|
*s = make([]stackitem.Item, n)
|
|
}
|
|
|
|
// Set sets i-th storage slot.
|
|
func (s slot) Set(i int, item stackitem.Item, refs *refCounter) {
|
|
if s[i] == item {
|
|
return
|
|
}
|
|
old := s[i]
|
|
s[i] = item
|
|
if old != nil {
|
|
refs.Remove(old)
|
|
}
|
|
refs.Add(item)
|
|
}
|
|
|
|
// Get returns item contained in i-th slot.
|
|
func (s slot) Get(i int) stackitem.Item {
|
|
if item := s[i]; item != nil {
|
|
return item
|
|
}
|
|
return stackitem.Null{}
|
|
}
|
|
|
|
// Clear removes all slot variables from reference counter.
|
|
func (s slot) Clear(refs *refCounter) {
|
|
for _, item := range s {
|
|
refs.Remove(item)
|
|
}
|
|
}
|
|
|
|
// Size returns slot size.
|
|
func (s slot) Size() int {
|
|
if s == nil {
|
|
panic("not initialized")
|
|
}
|
|
return len(s)
|
|
}
|
|
|
|
// MarshalJSON implements JSON marshalling interface.
|
|
func (s slot) MarshalJSON() ([]byte, error) {
|
|
arr := make([]json.RawMessage, len(s))
|
|
for i := range s {
|
|
data, err := stackitem.ToJSONWithTypes(s[i])
|
|
if err == nil {
|
|
arr[i] = data
|
|
}
|
|
}
|
|
return json.Marshal(arr)
|
|
}
|