parrotcode: Parrot Calling Conventions | |
Contents | Documentation |
docs/pdds/pdd03_calling_conventions.pod - Parrot Calling Conventions
Parrot's inter-routine calling conventions.
$Revision$
This document describes how to pass arguments from registers to subroutines, and how subroutines can extract their parameters into registers for use.
Since Parrot's calling conventions are continuation-based, there is arguably very little difference between a call and a return. Because of this, the conversion rules are the same regardless of whether code is invoking a subroutine or a return continuation.
There are four opcodes involved in parameter and return value propagation:
set_args
,
for passing arguments;set_returns
,
for returning values;get_params
,
for accepting parameters; andget_results
,
for accepting return values.FAQ: Given Parrot's internal use of continuation-passing style ["CPS"], it would be possible to use one pair of opcodes for both call and return, since under CPS returns are calls. And perhaps someday we will have only two opcodes. But for now, certain efficiency hacks are easier with four opcodes.)
The common syntax of these opcodes is:
<set_opcode> "(flags0, flags1, ..., flagsN)", VAL0, VAL1, ... VALN
<get_opcode> "(flags0, flags1, ..., flagsN)", REG0, REG1, ... REGN
<get_opcode> "(..., 0x200, flags0, ...)", ..., "name", REG0, ...
The flags string is a literal quoted string denoting a list of zero or more comma-separated integers. The list as a whole may be surrounded by parentheses. Integers may be specified either in decimal, or if prefixed with "0b"/"0x", in binary/hexadecimal. There must be exactly one integer for each value or register given.
For documentation purposes we'll number the bits 0 (low) through 30 (high). Bit 31 (and higher, where available) will not be used.
Some values and registers do not correspond directly to values passed or received. (See the descriptions of the OPT_FLAG and NAMED bits, below.)
Each integer in the flag string controls the processing of the corresponding value or register.
These bits of each flag word have common meanings for all argument/ return-value opcodes:
0-3 TYPE
0b0000 = I
0b0001 = S
0b0010 = P
0b0011 = N
Don't set these bits yourself; the assembler will do it.
Just before calling a subroutine with invokecc
or calling a method with <call_methodcc>, use the set_args
opcode to tell Parrot where the subroutine's or method's arguments will come from and how they should be expanded by the target.
Similarly, just before returning from such a subroutine or method, use the set_returns
opcode to tell Parrot where the return values will come from and how to expand them for the caller's use.
These bits of each flag word have these meanings specific to set_args
and set_returns
:
4 CONSTANT
The value is a literal constant, not a register.
(Don't set this bit yourself; the assembler will do it.)
5 FLAT
If this bit is set on a PMC value, then the PMC must be an
aggregate or a scalar containing a reference to an aggregate.
The contents of the aggregate, rather than the aggregate
itself, will be passed.
If the NAMED bit is also set, the aggregate will be used as a
hash; its contents, as key/value pairs, will be passed as
named parameters. The PMC must implement the full hash
interface. {{ TODO: Limit the required interface. }}
If the NAMED is not set, the aggregate will be used as as
array; its contents will be used as positional parameters.
The meaning of this bit is undefined when applied to integer,
number, and string values.
6 MAYBE_FLAT
If this bit is set on a PMC value, and:
(a) the PMC is either an aggregate or a scalar containing a
reference to an aggregate, and
(b) the target register has the SLURPY bit set,
then pass the PMC value as a list of values, in these ways:
(a) if the value is an array, pass its elements in the normal
way (FLAT style);
(b) if the value is a hash, pass its elements as a list of
key/value pairs contained in HLL-specific 'pair' PMCs.
The meaning of this bit is undefined when applied to integer,
number, and string values. It may not be combined with the
NAMED bit.
7 (unused)
8 (unused)
9 NAMED (FLAT or string constant only)
When the FLAT bit is also set, behavior is as described above
in the "FLAT" section. Otherwise, this bit may only be set on
a unique string constant specifying the name of the next
argument (or returned value).
As the first opcode in a subroutine that will be called with invokecc
or a method that will be called with <call_methodcc>, use the get_params
opcode to tell Parrot where the subroutine's or method's arguments should be stored and how they should be expanded.
Similarly, just before (yes, before) calling such a subroutine or method, use the get_results
opcode to tell Parrot where the return values should be stored and how to expand them for your use.
NOTE: It should be obvious, but in case it's not: You must name only registers as targets of these opcodes, not constants. (You can't store anything into a constant. That would make it a variable.)
These bits of each flag word have these meanings specific to get_params
and get_results
:
4 (unused)
5 SLURPY (P only)
If this bit is set on a P register, then it will be populated
with an aggregate that will contain all of the remaining values
that have not already been stored in other registers.
All such values will be converted to PMCs according to the
detailed rules below, and those PMCs will be stored into the
new aggregate.
If the NAMED bit is also set, the aggregate will be an
HLL-specific hash type and the contents will be all
unassigned _named_ parameters.
If the NAMED bit is not set, the aggregate will be an
HLL-specific array type and the contents will be all
unassigned positional parameters.
6 (unused)
7 OPTIONAL
If this bit is set on a register for which no value has been
passed, no exception will be raised; rather, the register will
be set to a default value: a Null PMC for P, an empty string
for S, or zero for N or I.
8 OPT_FLAG (I only)
An I register with this bit set is set to one if the
immediately preceding B<OPTIONAL> register received a value;
otherwise, it is set to zero.
8 READONLY (P only)
XXX - PROPOSED ONLY - XXX
If this bit is set on a P register that receives a value,
Parrot will ensure that the final value in the P register
is read-only (i.e. will not permit modification). If the
received value was a mutable PMC, then Parrot will create
and set the register to a read-only PMC wrapper around the
original PMC.
Parrot's algorithm for deciding what is writable may be pretty
simplistic. In initial implementations, it may assume that any
PMC not of a known read-only-wrapper type is mutable.
9 NAMED (SLURPY or string constant only)
When the SLURPY bit is also set, behavior is as described above
in the "SLURPY" section. Otherwise, this bit may only be set
on a unique string constant specifying the name of the next
argument (or returned value).
If too many values are provided to fit into the given target registers, Parrot will throw an exception. Note that if the final target is a P register with FLAT set, then this exception can never occur.
XXX - FIXME - which exception? We really could use an exception subsystem. Oh, wait, that's my job. Never mind. --Chip
If too few values are provided so that some target registers are left unset, this too results in an exception.
Named values (arguments, or values to return) must appear after all the unnamed values. Within the unnamed and named zones, FLAT and non-FLAT values may be mixed in any order.
Named targets (parameters, or returned values) must appear after all the unnamed targets. Within the unnamed and named zones, SLURPY targets must appear last (if they appear at all).
So the acceptable ordering of targets is:
Unnamed targets can only be filled with unnamed values.
Named targets can be filled with either unnamed or named values. However, if a named target was already filled by an unnamed (positional) value, and then a named value is also given, this is an overflow error.
Unlike the set_*
opcodes, the get_*
opcodes must perform conversion from one register type to another. Here are the conversion rules:
assign
(standard conversion).set
(pass by reference).assign
ed the given integer.assign
ed the given number.assign
ed the given string.[1] according the current HLL type mappings.
Required features are missing:
foo(1, i) # 2 positional arguments
foo(x, ar :flat, y) # flattening array
foo(p, 'q' => q) # named argument
foo(p, q :named('q')) # the same
foo(kw :named :flat) # a flattening hash
.param int i # positional parameter
.param pmc argv :slurpy # slurpy array
.param pmc qu :named('q') # named parameter
.param int x :optional # optional parameter
.param int has_x :opt_flag # flag 0/1 x was passed
.param pmc kw :slurpy :named # slurpy hash
.return (i, ar: flat, q :named('q') )
x = foo() # single result
(i, j :optional, ar :slurpy, q :named('q') ) = foo()
None.
None.
|