Skip to content

Commit 64d5d1c

Browse files
committed
simplify code and gain 2% speed
1 parent 39e88fc commit 64d5d1c

File tree

1 file changed

+22
-16
lines changed

1 file changed

+22
-16
lines changed

vm/vm.go

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -357,23 +357,26 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) {
357357
vm.push(out)
358358

359359
case OpCall1:
360-
args := vm.getArgsForFunc(&fnArgsBuf, program, 1)
360+
var args []any
361+
args, fnArgsBuf = vm.getArgsForFunc(fnArgsBuf, program, 1)
361362
out, err := program.functions[arg](args...)
362363
if err != nil {
363364
panic(err)
364365
}
365366
vm.push(out)
366367

367368
case OpCall2:
368-
args := vm.getArgsForFunc(&fnArgsBuf, program, 2)
369+
var args []any
370+
args, fnArgsBuf = vm.getArgsForFunc(fnArgsBuf, program, 2)
369371
out, err := program.functions[arg](args...)
370372
if err != nil {
371373
panic(err)
372374
}
373375
vm.push(out)
374376

375377
case OpCall3:
376-
args := vm.getArgsForFunc(&fnArgsBuf, program, 3)
378+
var args []any
379+
args, fnArgsBuf = vm.getArgsForFunc(fnArgsBuf, program, 3)
377380
out, err := program.functions[arg](args...)
378381
if err != nil {
379382
panic(err)
@@ -382,7 +385,8 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) {
382385

383386
case OpCallN:
384387
fn := vm.pop().(Function)
385-
args := vm.getArgsForFunc(&fnArgsBuf, program, arg)
388+
var args []any
389+
args, fnArgsBuf = vm.getArgsForFunc(fnArgsBuf, program, arg)
386390
out, err := fn(args...)
387391
if err != nil {
388392
panic(err)
@@ -391,12 +395,14 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) {
391395

392396
case OpCallFast:
393397
fn := vm.pop().(func(...any) any)
394-
args := vm.getArgsForFunc(&fnArgsBuf, program, arg)
398+
var args []any
399+
args, fnArgsBuf = vm.getArgsForFunc(fnArgsBuf, program, arg)
395400
vm.push(fn(args...))
396401

397402
case OpCallSafe:
398403
fn := vm.pop().(SafeFunction)
399-
args := vm.getArgsForFunc(&fnArgsBuf, program, arg)
404+
var args []any
405+
args, fnArgsBuf = vm.getArgsForFunc(fnArgsBuf, program, arg)
400406
out, mem, err := fn(args...)
401407
if err != nil {
402408
panic(err)
@@ -601,13 +607,13 @@ func (vm *VM) scope() *Scope {
601607
// take "needed" elements from the buffer and populate them with vm.pop() in
602608
// reverse order. Because the estimation can fall short, this function can
603609
// occasionally make a new allocation.
604-
func (vm *VM) getArgsForFunc(bufPtr *[]any, program *Program, needed int) []any {
605-
if needed == 0 || bufPtr == nil && program == nil {
606-
return nil
610+
func (vm *VM) getArgsForFunc(argsBuf []any, program *Program, needed int) (args []any, argsBufOut []any) {
611+
if needed == 0 || program == nil {
612+
return nil, argsBuf
607613
}
608614

609615
// Step 1: fix estimations and preallocate
610-
if *bufPtr == nil {
616+
if argsBuf == nil {
611617
estimatedFnArgsCount := estimateFnArgsCount(program)
612618
if estimatedFnArgsCount < needed {
613619
// in the case that the first call is for example OpCallN with a large
@@ -617,24 +623,24 @@ func (vm *VM) getArgsForFunc(bufPtr *[]any, program *Program, needed int) []any
617623
}
618624

619625
// in the case that we are preparing the arguments for the first
620-
// function call of the program, then *bufPtr will be nil, so we
626+
// function call of the program, then argsBuf will be nil, so we
621627
// initialize it. We delay this initial allocation here because a
622628
// program could have many function calls but exit earlier than the
623629
// first call, so in that case we avoid allocating unnecessarily
624-
*bufPtr = make([]any, estimatedFnArgsCount)
630+
argsBuf = make([]any, estimatedFnArgsCount)
625631
}
626632

627633
// Step 2: get the final slice that will be returned
628634
var buf []any
629-
if len(*bufPtr) >= needed {
635+
if len(argsBuf) >= needed {
630636
// in this case, we are successfully using the single preallocation. We
631637
// use the full slice expression [low : high : max] because in that way
632638
// a function that receives this slice as variadic arguments will not be
633639
// able to make modifications to contiguous elements with append(). If
634640
// they call append on their variadic arguments they will make a new
635641
// allocation.
636-
buf = (*bufPtr)[:needed:needed]
637-
*bufPtr = (*bufPtr)[needed:] // advance the buffer
642+
buf = (argsBuf)[:needed:needed]
643+
argsBuf = (argsBuf)[needed:] // advance the buffer
638644
} else {
639645
// if we have been making calls to something like OpCallN with many more
640646
// arguments than what we estimated, then we will need to allocate
@@ -647,7 +653,7 @@ func (vm *VM) getArgsForFunc(bufPtr *[]any, program *Program, needed int) []any
647653
copy(buf, vm.Stack[len(vm.Stack)-needed:])
648654
vm.Stack = vm.Stack[:len(vm.Stack)-needed]
649655

650-
return buf
656+
return buf, argsBuf
651657
}
652658

653659
func (vm *VM) Step() {

0 commit comments

Comments
 (0)