MCPcopy Index your code
hub / github.com/expr-lang/expr / getArgsForFunc

Method getArgsForFunc

vm/vm.go:725–776  ·  view source on GitHub ↗

getArgsForFunc lazily initializes the buffer the first time it is called for a given program (thus, it also needs "program" to run). It will take "needed" elements from the buffer and populate them with vm.pop() in reverse order. Because the estimation can fall short, this function can occasionally

(argsBuf []any, program *Program, needed int)

Source from the content-addressed store, hash-verified

723// reverse order. Because the estimation can fall short, this function can
724// occasionally make a new allocation.
725func (vm *VM) getArgsForFunc(argsBuf []any, program *Program, needed int) (args []any, argsBufOut []any) {
726 if needed == 0 || program == nil {
727 return nil, argsBuf
728 }
729
730 // Step 1: fix estimations and preallocate
731 if argsBuf == nil {
732 estimatedFnArgsCount := estimateFnArgsCount(program)
733 if estimatedFnArgsCount > maxFnArgsBuf {
734 // put a practical limit to avoid excessive preallocation
735 estimatedFnArgsCount = maxFnArgsBuf
736 }
737 if estimatedFnArgsCount < needed {
738 // in the case that the first call is for example OpCallN with a large
739 // number of arguments, then make sure we will be able to serve them at
740 // least.
741 estimatedFnArgsCount = needed
742 }
743
744 // in the case that we are preparing the arguments for the first
745 // function call of the program, then argsBuf will be nil, so we
746 // initialize it. We delay this initial allocation here because a
747 // program could have many function calls but exit earlier than the
748 // first call, so in that case we avoid allocating unnecessarily
749 argsBuf = make([]any, estimatedFnArgsCount)
750 }
751
752 // Step 2: get the final slice that will be returned
753 var buf []any
754 if len(argsBuf) >= needed {
755 // in this case, we are successfully using the single preallocation. We
756 // use the full slice expression [low : high : max] because in that way
757 // a function that receives this slice as variadic arguments will not be
758 // able to make modifications to contiguous elements with append(). If
759 // they call append on their variadic arguments they will make a new
760 // allocation.
761 buf = (argsBuf)[:needed:needed]
762 argsBuf = (argsBuf)[needed:] // advance the buffer
763 } else {
764 // if we have been making calls to something like OpCallN with many more
765 // arguments than what we estimated, then we will need to allocate
766 // separately
767 buf = make([]any, needed)
768 }
769
770 // Step 3: populate the final slice bulk copying from the stack. This is the
771 // exact order and copy() is a highly optimized operation
772 copy(buf, vm.Stack[len(vm.Stack)-needed:])
773 vm.Stack = vm.Stack[:len(vm.Stack)-needed]
774
775 return buf, argsBuf
776}
777
778func (vm *VM) Step() {
779 vm.step <- struct{}{}

Callers 1

RunMethod · 0.95

Calls 1

estimateFnArgsCountFunction · 0.85

Tested by

no test coverage detected