vm: don't create reference counter when it's not needed

* invocation stack doesn't need refcounting
 * exception stack doesn't need refcounting
 * evaluation stack always has VM-level refcounter
This commit is contained in:
Roman Khimov 2021-08-02 22:38:41 +03:00
parent 2c2ccdca74
commit 85936de254
3 changed files with 16 additions and 14 deletions

View file

@ -18,6 +18,9 @@ func newRefCounter() *refCounter {
// Add adds an item to the reference counter. // Add adds an item to the reference counter.
func (r *refCounter) Add(item stackitem.Item) { func (r *refCounter) Add(item stackitem.Item) {
if r == nil {
return
}
r.size++ r.size++
switch item.(type) { switch item.(type) {
@ -41,6 +44,9 @@ func (r *refCounter) Add(item stackitem.Item) {
// Remove removes item from the reference counter. // Remove removes item from the reference counter.
func (r *refCounter) Remove(item stackitem.Item) { func (r *refCounter) Remove(item stackitem.Item) {
if r == nil {
return
}
r.size-- r.size--
switch item.(type) { switch item.(type) {

View file

@ -158,13 +158,16 @@ type Stack struct {
// NewStack returns a new stack name by the given name. // NewStack returns a new stack name by the given name.
func NewStack(n string) *Stack { func NewStack(n string) *Stack {
return newStack(n, newRefCounter())
}
func newStack(n string, refc *refCounter) *Stack {
s := &Stack{ s := &Stack{
name: n, name: n,
refs: refc,
} }
s.top.next = &s.top s.top.next = &s.top
s.top.prev = &s.top s.top.prev = &s.top
s.len = 0
s.refs = newRefCounter()
return s return s
} }

View file

@ -99,7 +99,7 @@ func New() *VM {
func NewWithTrigger(t trigger.Type) *VM { func NewWithTrigger(t trigger.Type) *VM {
vm := &VM{ vm := &VM{
state: NoneState, state: NoneState,
istack: NewStack("invocation"), istack: newStack("invocation", nil),
refs: newRefCounter(), refs: newRefCounter(),
trigger: t, trigger: t,
@ -107,17 +107,10 @@ func NewWithTrigger(t trigger.Type) *VM {
Invocations: make(map[util.Uint160]int), Invocations: make(map[util.Uint160]int),
} }
vm.estack = vm.newItemStack("evaluation") vm.estack = newStack("evaluation", vm.refs)
return vm return vm
} }
func (v *VM) newItemStack(n string) *Stack {
s := NewStack(n)
s.refs = v.refs
return s
}
// SetPriceGetter registers the given PriceGetterFunc in v. // SetPriceGetter registers the given PriceGetterFunc in v.
// f accepts vm's Context, current instruction and instruction parameter. // f accepts vm's Context, current instruction and instruction parameter.
func (v *VM) SetPriceGetter(f func(opcode.Opcode, []byte) int64) { func (v *VM) SetPriceGetter(f func(opcode.Opcode, []byte) int64) {
@ -288,9 +281,9 @@ func (v *VM) LoadScript(b []byte) {
func (v *VM) LoadScriptWithFlags(b []byte, f callflag.CallFlag) { func (v *VM) LoadScriptWithFlags(b []byte, f callflag.CallFlag) {
v.checkInvocationStackSize() v.checkInvocationStackSize()
ctx := NewContextWithParams(b, 0, -1, 0) ctx := NewContextWithParams(b, 0, -1, 0)
v.estack = v.newItemStack("estack") v.estack = newStack("evaluation", v.refs)
ctx.estack = v.estack ctx.estack = v.estack
ctx.tryStack = NewStack("exception") ctx.tryStack = newStack("exception", nil)
ctx.callFlag = f ctx.callFlag = f
ctx.static = newSlot(v.refs) ctx.static = newSlot(v.refs)
ctx.callingScriptHash = v.GetCurrentScriptHash() ctx.callingScriptHash = v.GetCurrentScriptHash()
@ -1527,7 +1520,7 @@ func (v *VM) call(ctx *Context, offset int) {
newCtx.RetCount = -1 newCtx.RetCount = -1
newCtx.local = nil newCtx.local = nil
newCtx.arguments = nil newCtx.arguments = nil
newCtx.tryStack = NewStack("exception") newCtx.tryStack = newStack("exception", nil)
newCtx.NEF = ctx.NEF newCtx.NEF = ctx.NEF
v.istack.PushVal(newCtx) v.istack.PushVal(newCtx)
v.Jump(newCtx, offset) v.Jump(newCtx, offset)