Version 13 (modified by jkeenan, 12 years ago)

Turn text into subhead

The purpose of the PCC branch is to unify the internal implementation 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:

  tools/build/nativecall.pl
  lib/Parrot/Pmc2c/PCCMETHOD.pm

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.

Known issues

- 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, :optional, :opt_flag etc. (t/compilers/imcc/syn/tail.t, t/pmc/coroutine.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)

- Edge cases on auto boxing/unboxing argument types, e.g. "Unable to set PMC value, the pointer is not a PMC" (t/oo/methods.t, t/oo/subclass.t, t/pmc/hashiteratorkey.t, t/pmc/object-meths.t, t/pmc/resizablestringarray.t, t/pmc/string.t)

- GC attempting to mark a bad variable (t/op/box.t)

- Insufficient checking on positional arguments passed inside named arguments (t/op/calling.t)

- Insufficient checking on missing named arguments (t/op/cc_state.t)

- Insufficient checking on too many arguments passed (t/pmc/exporter.t)

- Some tests need to be updated to match the current error messages (t/op/calling.t, t/op/cc_params.t)

- Segfault in set_returns, possibly a null call object? (t/op/gc.t, t/pmc/exceptionhandler.t)

- Probably a problem with argument handling (t/op/lexicals.t, t/pmc/class.t, t/pmc/codestring.t, t/pmc/object-meths.t, t/pmc/sub.t)

- Two NCI edge cases (t/pmc/nci.t).

- Likely cases of code still calling into the old functions for invoking from C, instead of the new functions (t/pmc/sub.t, t/pmc/threads.t)

- Likely bug in Parrot_call_sub reimplementation (t/src/embed.t)