Draft
Conversation
In order to go further with directly passing keyword arguments on the call stack, we need call instructions to aggregate information on the kwargs structure. Previous to this commit, the kwargs hash was constructed as an entirely separate operand, copied to the call's parameters via a temporary variable. This effectively hid the actual hash structure from logic reading the call object. The patch here embeds the operand for the Hash directly into the call's argument list, allowing for it to be processed at the same time as the call. The keys and values are still processed as their own operands at call time, and any elaborate hash or argument list construction pulls the hash back out to its own operand. The change here only allows simple kwargs to be directly associated with the call that will use them. The IR output illustrates the change more clearly. For a call like "foo(1, bar: 1, baz: 2, &boo)", here's old IR: 02: %v_1 := call_0o(self<%self>, callType: VARIABLE, name: baz, potentiallyRefined: false, flags: 0) 03: %v_2 := call_0o(self<%self>, callType: VARIABLE, name: quux, potentiallyRefined: false, flags: 0) 04: %v_3 := copy(hash<sym<a>=>%v_1,sym<b>=>%v_2>) 05: %v_4 := call_0o(self<%self>, callType: VARIABLE, name: boo, potentiallyRefined: false, flags: 0) 06: %v_0 := call(self<%self>, fix<1>, %v_3, %v_4, callType: FUNCTIONAL, name: foo, potentiallyRefined: false, flags: 2) And here is the new IR, with the Hash directly in the call's list of operands: 2: %v_1 := call_0o(self<%self>, callType: VARIABLE, name: baz, potentiallyRefined: false, flags: 0) 3: %v_2 := call_0o(self<%self>, callType: VARIABLE, name: quux, potentiallyRefined: false, flags: 0) 4: %v_3 := call_0o(self<%self>, callType: VARIABLE, name: boo, potentiallyRefined: false, flags: 0) 5: %v_0 := call(self<%self>, fix<1>, hash<sym<a>=>%v_1,sym<b>=>%v_2>, %v_3, callType: FUNCTIONAL, name: foo, potentiallyRefined: false, flags: 2) In both cases, all arguments and all operands to the hash are accessed and constructed in the same order, but there's no temp var required to hold the intermediate hash. It is directly associated with the call.
This is a first step toward passing keyword arguments all the way through the stack without allocating a Hash object. When we detect that there's a trailing Hash operand in the argument list, we know it must be a keyword arguments hash. Rather than eagerly creating the Hash, we instead evaluate its values as normal but leave them on the stack for the call. The invocation takes the positional and keyword argument values along with a keyword names descriptor and reassembles the values into a kwargs hash lazily before invoking a normal call site. Once the normal call process has a way to plumb kwarg values all the way through to a target method, this will push further into that stack.
This is the first place where the Indy compiler will start to seriously diverge from the non-Indy version. It's just too hard to plumb direct keyword arguments through the non-Indy compiler, so we add a way for the IR visitor to alter compilation strategy if running in a mode that has reduced capabilities.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the beginning of passing keyword arguments directly on the stack, without a transient RubyHash object to carry them.
The first pass of this work plumbs the keywords directly through to invokedynamic call sites by making the following changes:
Initially, the indy site will simply reconstitute the keyword names and values into a RubyHash as before, passing it on the stack as normal. The missing piece to continue passing them through is a way to detect that the callee accepts those keyword arguments. Once that piece is in place, the indy site will be able to pass the arguments on the stack straight through to a target method, which will see only the argument values and not have to query a full RubyHash object to get them.