From bc31c97c320a1ab2d494d554b85203c6cc49b780 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Sat, 28 Aug 2021 22:31:08 +0300 Subject: [PATCH] vm: simplify access to context, don't call Context() twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid going through Value(), avoid doing type casts twice for every instruction. name old time/op new time/op delta ScriptFibonacci-8 793µs ± 3% 736µs ± 1% -7.18% (p=0.000 n=10+9) ScriptNestedRefCount-8 1.09ms ± 1% 1.08ms ± 2% -0.96% (p=0.035 n=10+10) ScriptPushPop/4-8 1.51µs ± 3% 1.48µs ± 3% ~ (p=0.072 n=10+10) ScriptPushPop/16-8 3.76µs ± 1% 3.59µs ± 1% -4.56% (p=0.000 n=10+10) ScriptPushPop/128-8 25.0µs ± 1% 23.7µs ± 1% -5.28% (p=0.000 n=10+10) ScriptPushPop/1024-8 184µs ± 1% 176µs ± 2% -4.22% (p=0.000 n=9+9) --- pkg/vm/context.go | 3 +-- pkg/vm/vm.go | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pkg/vm/context.go b/pkg/vm/context.go index a4a288477..d00e091bc 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -286,8 +286,7 @@ func (v *VM) getContextScriptHash(n int) util.Uint160 { return util.Uint160{} } element := istack.Peek(n) - ctxIface := element.Value() - ctx := ctxIface.(*Context) + ctx := element.value.(*Context) return ctx.ScriptHash() } diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 35b89dfa3..eaa8b93eb 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -322,7 +322,7 @@ func (v *VM) Context() *Context { if v.istack.Len() == 0 { return nil } - return v.istack.Peek(0).Value().(*Context) + return v.istack.Peek(0).value.(*Context) } // PopResult is used to pop the first item of the evaluation stack. This allows @@ -360,6 +360,8 @@ func (v *VM) Ready() bool { // Run starts the execution of the loaded program. func (v *VM) Run() error { + var ctx *Context + if !v.Ready() { v.state = FaultState return errors.New("no program loaded") @@ -372,6 +374,7 @@ func (v *VM) Run() error { } // HaltState (the default) or BreakState are safe to continue. v.state = NoneState + ctx = v.Context() for { switch { case v.state.HasFlag(FaultState): @@ -382,7 +385,7 @@ func (v *VM) Run() error { // Normal exit from this loop. return nil case v.state == NoneState: - if err := v.Step(); err != nil { + if err := v.step(ctx); err != nil { return err } default: @@ -390,7 +393,7 @@ func (v *VM) Run() error { return errors.New("unknown state") } // check for breakpoint before executing the next instruction - ctx := v.Context() + ctx = v.Context() if ctx != nil && ctx.atBreakPoint() { v.state = BreakState } @@ -400,6 +403,11 @@ func (v *VM) Run() error { // Step 1 instruction in the program. func (v *VM) Step() error { ctx := v.Context() + return v.step(ctx) +} + +// step executes one instruction in given context. +func (v *VM) step(ctx *Context) error { op, param, err := ctx.Next() if err != nil { v.state = FaultState @@ -1285,7 +1293,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro } case opcode.RET: - oldCtx := v.istack.Pop().Value().(*Context) + oldCtx := v.istack.Pop().value.(*Context) oldEstack := v.estack v.unloadContext(oldCtx) @@ -1552,7 +1560,7 @@ func calcJumpOffset(ctx *Context, parameter []byte) (int, int, error) { func (v *VM) handleException() { for pop := 0; pop < v.istack.Len(); pop++ { ictxv := v.istack.Peek(pop) - ictx := ictxv.Value().(*Context) + ictx := ictxv.value.(*Context) for j := 0; j < ictx.tryStack.Len(); j++ { e := ictx.tryStack.Peek(j) ectx := e.Value().(*exceptionHandlingContext) @@ -1562,7 +1570,7 @@ func (v *VM) handleException() { continue } for i := 0; i < pop; i++ { - ctx := v.istack.Pop().Value().(*Context) + ctx := v.istack.Pop().value.(*Context) v.unloadContext(ctx) } if ectx.State == eTry && ectx.HasCatch() {