Merge pull request #2122 from nspcc-dev/vm-microopt

VM-related microoptimizations
This commit is contained in:
Roman Khimov 2021-08-12 10:34:49 +03:00 committed by GitHub
commit 3360c4a0d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 37 additions and 27 deletions

View file

@ -48,14 +48,20 @@ type Context struct {
VM *vm.VM VM *vm.VM
Functions []Function Functions []Function
getContract func(dao.DAO, util.Uint160) (*state.Contract, error) getContract func(dao.DAO, util.Uint160) (*state.Contract, error)
baseExecFee int64
} }
// NewContext returns new interop context. // NewContext returns new interop context.
func NewContext(trigger trigger.Type, bc blockchainer.Blockchainer, d dao.DAO, func NewContext(trigger trigger.Type, bc blockchainer.Blockchainer, d dao.DAO,
getContract func(dao.DAO, util.Uint160) (*state.Contract, error), natives []Contract, getContract func(dao.DAO, util.Uint160) (*state.Contract, error), natives []Contract,
block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context { block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
baseExecFee := int64(DefaultBaseExecFee)
dao := d.GetWrapped() dao := d.GetWrapped()
nes := make([]state.NotificationEvent, 0) nes := make([]state.NotificationEvent, 0)
if bc != nil && (block == nil || block.Index != 0) {
baseExecFee = bc.GetPolicer().GetBaseExecFee()
}
return &Context{ return &Context{
Chain: bc, Chain: bc,
Network: uint32(bc.GetConfig().Magic), Network: uint32(bc.GetConfig().Magic),
@ -69,6 +75,7 @@ func NewContext(trigger trigger.Type, bc blockchainer.Blockchainer, d dao.DAO,
// Functions is a slice of interops sorted by ID. // Functions is a slice of interops sorted by ID.
Functions: []Function{}, Functions: []Function{},
getContract: getContract, getContract: getContract,
baseExecFee: baseExecFee,
} }
} }
@ -254,10 +261,7 @@ func (ic *Context) GetFunction(id uint32) *Function {
// BaseExecFee represents factor to multiply syscall prices with. // BaseExecFee represents factor to multiply syscall prices with.
func (ic *Context) BaseExecFee() int64 { func (ic *Context) BaseExecFee() int64 {
if ic.Chain == nil || (ic.Block != nil && ic.Block.Index == 0) { return ic.baseExecFee
return DefaultBaseExecFee
}
return ic.Chain.GetPolicer().GetBaseExecFee()
} }
// SyscallHandler handles syscall with id. // SyscallHandler handles syscall with id.

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/nspcc-dev/neo-go/internal/fakechain"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/fee" "github.com/nspcc-dev/neo-go/pkg/core/fee"
@ -67,12 +68,15 @@ func initCheckMultisigVMNoArgs(container *transaction.Transaction) *vm.VM {
buf[0] = byte(opcode.SYSCALL) buf[0] = byte(opcode.SYSCALL)
binary.LittleEndian.PutUint32(buf[1:], neoCryptoCheckMultisigID) binary.LittleEndian.PutUint32(buf[1:], neoCryptoCheckMultisigID)
ic := &interop.Context{ ic := interop.NewContext(
Network: uint32(netmode.UnitTestNet), trigger.Verification,
Trigger: trigger.Verification, fakechain.NewFakeChain(),
Container: container, dao.NewSimple(storage.NewMemoryStore(), false),
Functions: Interops, nil, nil, nil,
} container,
nil)
ic.Container = container
ic.Functions = Interops
v := ic.SpawnVM() v := ic.SpawnVM()
v.LoadScript(buf) v.LoadScript(buf)
return v return v

View file

@ -7,5 +7,5 @@ import (
// GetPrice returns a price for executing op with the provided parameter. // GetPrice returns a price for executing op with the provided parameter.
func (ic *Context) GetPrice(op opcode.Opcode, parameter []byte) int64 { func (ic *Context) GetPrice(op opcode.Opcode, parameter []byte) int64 {
return fee.Opcode(ic.BaseExecFee(), op) return fee.Opcode(ic.baseExecFee, op)
} }

View file

@ -26,7 +26,7 @@ func (s *Slot) init(n int) {
} }
func (v *VM) newSlot(n int) *Slot { func (v *VM) newSlot(n int) *Slot {
s := newSlot(v.refs) s := newSlot(&v.refs)
s.init(n) s.init(n)
return s return s
} }

View file

@ -162,13 +162,15 @@ func NewStack(n string) *Stack {
} }
func newStack(n string, refc *refCounter) *Stack { func newStack(n string, refc *refCounter) *Stack {
s := &Stack{ s := new(Stack)
name: n, initStack(s, n, refc)
refs: refc, return s
} }
func initStack(s *Stack, n string, refc *refCounter) {
s.name = n
s.refs = refc
s.top.next = &s.top s.top.next = &s.top
s.top.prev = &s.top s.top.prev = &s.top
return s
} }
// Clear clears all elements on the stack and set its length to 0. // Clear clears all elements on the stack and set its length to 0.

View file

@ -68,12 +68,12 @@ type VM struct {
// callback to get interop price // callback to get interop price
getPrice func(opcode.Opcode, []byte) int64 getPrice func(opcode.Opcode, []byte) int64
istack *Stack // invocation stack. istack Stack // invocation stack.
estack *Stack // execution stack. estack *Stack // execution stack.
uncaughtException stackitem.Item // exception being handled uncaughtException stackitem.Item // exception being handled
refs *refCounter refs refCounter
gasConsumed int64 gasConsumed int64
GasLimit int64 GasLimit int64
@ -99,15 +99,15 @@ 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", nil),
refs: newRefCounter(),
trigger: t, trigger: t,
SyscallHandler: defaultSyscallHandler, SyscallHandler: defaultSyscallHandler,
Invocations: make(map[util.Uint160]int), Invocations: make(map[util.Uint160]int),
} }
vm.estack = newStack("evaluation", vm.refs) vm.refs.items = make(map[stackitem.Item]int)
initStack(&vm.istack, "invocation", nil)
vm.estack = newStack("evaluation", &vm.refs)
return vm return vm
} }
@ -135,7 +135,7 @@ func (v *VM) Estack() *Stack {
// Istack returns the invocation stack so interop hooks can utilize this. // Istack returns the invocation stack so interop hooks can utilize this.
func (v *VM) Istack() *Stack { func (v *VM) Istack() *Stack {
return v.istack return &v.istack
} }
// LoadArgs loads in the arguments used in the Mian entry point. // LoadArgs loads in the arguments used in the Mian entry point.
@ -281,11 +281,11 @@ 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 = newStack("evaluation", v.refs) v.estack = newStack("evaluation", &v.refs)
ctx.estack = v.estack ctx.estack = v.estack
ctx.tryStack = newStack("exception", nil) 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()
v.istack.PushVal(ctx) v.istack.PushVal(ctx)
} }
@ -340,7 +340,7 @@ func (v *VM) PopResult() interface{} {
func (v *VM) Stack(n string) string { func (v *VM) Stack(n string) string {
var s *Stack var s *Stack
if n == "istack" { if n == "istack" {
s = v.istack s = &v.istack
} }
if n == "estack" { if n == "estack" {
s = v.estack s = v.estack
@ -1786,7 +1786,7 @@ func (v *VM) GetCallingScriptHash() util.Uint160 {
// GetEntryScriptHash implements ScriptHashGetter interface. // GetEntryScriptHash implements ScriptHashGetter interface.
func (v *VM) GetEntryScriptHash() util.Uint160 { func (v *VM) GetEntryScriptHash() util.Uint160 {
return v.getContextScriptHash(v.Istack().Len() - 1) return v.getContextScriptHash(v.istack.len - 1)
} }
// GetCurrentScriptHash implements ScriptHashGetter interface. // GetCurrentScriptHash implements ScriptHashGetter interface.