diff options
author | alandonovan <adonovan@google.com> | 2020-06-17 14:22:58 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-17 14:22:58 -0400 |
commit | fd77f1382f3580e9991b1b20a9985b14dd670dda (patch) | |
tree | 3539d39096a45ef2cc89e0c11a82526b19167296 | |
parent | 61b64bc459900eebc728a4e58505ae6f32215e02 (diff) | |
download | starlark-go-fd77f1382f3580e9991b1b20a9985b14dd670dda.tar.gz |
Avoid defensive copy in CALL operator when callee is a Starlark function (#281)
This saves 22% of CPU cycles on one call-intensive benchmark.
-rw-r--r-- | starlark/interp.go | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/starlark/interp.go b/starlark/interp.go index 5290730..004763e 100644 --- a/starlark/interp.go +++ b/starlark/interp.go @@ -19,6 +19,9 @@ const vmdebug = false // TODO(adonovan): use a bitfield of specific kinds of err // - opt: record MaxIterStack during compilation and preallocate the stack. func (fn *Function) CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) { + // Postcondition: args is not mutated. This is stricter than required by Callable, + // but allows CALL to avoid a copy. + if !resolve.AllowRecursion { // detect recursion for _, fr := range thread.stack[:len(thread.stack)-1] { @@ -276,9 +279,15 @@ loop: // positional args var positional Tuple if npos := int(arg >> 8); npos > 0 { - positional = make(Tuple, npos) + positional = stack[sp-npos : sp] sp -= npos - copy(positional, stack[sp:]) + + // Copy positional arguments into a new array, + // unless the callee is another Starlark function, + // in which case it can be trusted not to mutate them. + if _, ok := stack[sp-1].(*Function); !ok || args != nil { + positional = append(Tuple(nil), positional...) + } } if args != nil { // Add elements from *args sequence. |