|Version 9 (modified by allison, 6 years ago)|
The purpose of the PCC branch is to unify the internal implentation of the calling conventions into one code path. The current implementation of subroutine, method, and NCI invocation uses multiple different styles of passing and receiving arguments. A call to a subroutine or method from PIR saves a pointer to the location of the opcode where the arguments were passed, and later extracts the variables or constants from that opcode instruction. A call to a subroutine or method from C may pass around a varargs list and extract the arguments from it later or create a call state struct.
The new implementation standardizes argument passing for all calls (whether from PIR or C). Each call creates a call signature object right away, inserting arguments into the signature object from the opcode pointer or varargs list as soon as the call is made. Parameters are always extracted from a call signature object, and know nothing about the source of the call (they don't need to know what kind of environment invoked them, since all calls follow the same code path, and pass arguments the same way). NCI calls and what was previously known as PCCMETHOD calls also use the same argument passing strategy. Signature strings will be standardized on the PCC form (e.g. PI->S, for a call with a pmc and an integer argument, that returns a string result). The exception is NCI signatures, which will be left alone for now, but may be standardized later.
The following opcodes will be kept, but their implementation changed.
src/ops/core.ops: set_args get_params set_returns get_results
The following functions are deprecated and will be removed, as well as any functions only called by these functions.
src/call/pcc.c: parrot_pass_args parrot_pass_args_fromc Parrot_PCCINVOKE Parrot_init_ret_nci Parrot_init_arg_nci count_signature_elements (static) set_context_sig_returns_varargs (static) src/call/ops.c: runops_args Parrot_run_meth_fromc Parrot_runops_fromc_args Parrot_runops_fromc_args_event Parrot_runops_fromc_args_reti Parrot_runops_fromc_args_retf Parrot_run_meth_fromc_args Parrot_run_meth_fromc_args_reti Parrot_run_meth_fromc_args_retf Parrot_runops_fromc_arglist Parrot_runops_fromc_arglist_reti Parrot_runops_fromc_arglist_retf Parrot_run_meth_fromc_arglist Parrot_run_meth_fromc_arglist_reti Parrot_run_meth_fromc_arglist_retf src/extend.c (these functions are part of the defined public API, so will be modified to be backward compatible for now, and removed after 2.0): Parrot_call_sub Parrot_call_sub_ret_int Parrot_call_sub_ret_float Parrot_call_method Parrot_call_method_ret_int Parrot_call_method_ret_float src/nci.c set_nci_I set_nci_N set_nci_S set_nci_P
The following code generators have been updated to produce new-style argument retrieval, instead of old-style argument retreival:
The following functions are added and act as replacements for the deprecated functions.
src/call/pcc.c: Parrot_pcc_invoke_sub_from_c_args Parrot_pcc_build_sig_object_from_op Parrot_pcc_build_sig_object_returns_from_op Parrot_pcc_build_sig_object_from_varargs (added in an earlier refactor, but for this purpose) Parrot_pcc_fill_params_from_op Parrot_pcc_fill_params_from_c_args Parrot_pcc_fill_returns_from_op Parrot_pcc_fill_returns_from_c_args
The following static functions are added, and support the new argument passing behavior:
src/call/pcc.c: dissect_aggregate_arg extract_named_arg_from_op parse_signature_string src/call/callsignature.c Parrot_pcc_get_call_sig_raw_args Parrot_pcc_get_call_sig_raw_returns Parrot_pcc_set_call_sig_raw_args Parrot_pcc_set_call_sig_raw_returns
The signature object is stored in the current_sig element of the caller's context. This means that argument storing and return value extraction happens on current_sig in CURRENT_CONTEXT(interp), while parameter extraction and return value storing must retrieve the caller's context and use its current_sig element. The reason for this distinction is that the subroutine's local current_sig element will be set for every call it makes. (This will be simplified when contexts and call_signatures are collapsed into one.)
See also the earlier wishlist/tasklist CallingConventionsTasklist which mentions some of the motivations and reasoning for these changes.
The Parrot_call_sub_* and Parrot_call_method_* variants in src/extend.c don't all have the necessary changes to allow them to work with the new calling conventions (these are temporary implementations for backward compatibility before they're removed at the next deprecation point). Parrot_call_sub does have the right changes, and the others can be largely copied from it.
NCI hasn't been fully updated on caller and receiver side to use the new argument passing style.
- Return argument processing (Parrot_pcc_fill_returns_from_op and Parrot_pcc_fill_returns_from_c_args) doesn't currently support :named, :slurpy, :flatten, etc. (t/compilers/imcc/syn/tail.t)
- Parrot_pcc_fill_params_from_op and Parrot_pcc_fill_params_from_c_args are monolithic functions (basically finite state machines iterating over the arguments), that contain a great deal of nearly repeated code (one or two things different each time). Parrot_pcc_fill_returns_from_op and Parrot_pcc_fill_returns_from_c_args will be just as bad once they support all the options. Not a requirement before the merge, but these should be refactored into smaller subroutines. Needs to be thought through carefully though, it was a similar plan that lead to the current mess.
- Flattening an argument doesn't alter the signature string stored, so multiple dispatch can't handle the resulting string. Need to modify the signature string while building the CallSignature object. (t/pmc/multisub.t and t/pmc/multidispatch.t)