=head1 NAME
Subs - Parrot Subroutines
=head1 DESCRIPTION
Parrot comes with different subroutine and alike classes which implement CPS
(Continuation Passing Style) and PCC (Parrot Calling Conventions)
F<docs/pdds/pdd03_calling_conventions.pod>.
Please note, that this document refers to PASM assembler only. The PIR
assembler has a more HLL-like syntax for Parrot Calling Conventions. S.
F<imcc/docs/calling_conventions.pod>
=head2 Class Tree
Sub
Closure
Continuation
Coroutine
Eval
RetContinuation
=head2 Items in the Subs Context
Subtype Controlstack PadStack UserStack RegStacks Warnings
------------------------------------------------------------------
Sub - - - - C
Closure - C - - C
Continuation C C C C C
Coroutine C C C C C
RetContinuation X X X X X
"C" ... COWed copy is in context
"X" ... is in context
"-" ... isn't.
=head1 SYNOPSIS
=head2 Creation
Create a subroutine of class C<Sub> and assign the subroutine address to it:
new P0, 'Sub'
set_addr P0, _sub_label
This can be done with one opcode:
newsub P0, .Sub, _sub_label
Create a subroutine (in P0) and a return continuation (in P1):
newsub .Sub, .RetContinuation, _sub_label, ret_label
=head2 Refering to existing Subs
Subroutines denoted with B<.pcc_sub> (and all PIR B<.sub> subroutines that use
Parrot Calling Conventions) are stored in the constant table and can be fetched
with the B<find_global> opcode.
E.g. get a reference to a (possibly) external subroutine:
find_global P0, "_the_sub"
...
.pcc_sub _the_sub:
=head2 Program entry point
Exactly one subroutine in the first executed source or byte code file may be
flagged as the "main" subroutine, where executions starts.
.pcc_sub :main _main:
In the absence of a B<:main> entry Parrot starts execution at the first
statement.
=head2 Automatically loaded initializer code
If a subroutine is marked as B<:load> this subroutine is run, before the
B<load_bytecode> opcode returns.
e.g.
.pcc_sub :main _main:
print "in main\n"
load_bytecode "library_code.pasm"
...
# library_code.pasm
...
.pcc_sub :load _my_lib_init:
...
invoke P1
B<:load> is ignored, if another subroutine in that file is marked with
B<:main>.
If a subroutine is marked as B<:init> this subroutine is run, before the
B<:main> or the first subroutine in the source file runs.
=head2 Invocation i.e. calling the sub
invoke # call the subroutine in P0 (P1 was created earlier)
invokecc # call sub in P0 and create return continuation in P1
=head2 Returning from a sub
invoke P1 # call return continuation in P1
=head2 All together now
The following scheme can be used if a subroutine is called once or if
performance doesn't matter:
newsub P0, .Sub, _sub_label # create subroutine
set I5, 42 # pass an argument
invokecc # create ret continuation and call sub
end # fin.
_sub_label:
print I5 # do something with parameters
invoke P1 # return
If a subroutine is called several times, for instance inside a loop, the
creation of the return continuation can be done outside the loop if performance
is an issue:
newsub .Sub, .RetContinuation, _sub_label, ret_label
set I16, 1000000
set I17, 0
lp:
pushtopi # preserve counter vars
invoke
ret_label:
poptopi
inc I17
lt I17, I16, lp
end
_sub_label:
# do_something
invoke P1
If items in the interpreter context are changed between creation of the
subroutine/return continuation and its invocation, the C<updatecc> opcode
should be used, so that the state of the return continuation matches that of
the interpreter:
newsub .Sub, .RetContinuation, _sub_label, ret_label
...
warningson 1
...
updatecc
invoke
...
=head2 Generating a Subroutine Symbol Table Entry
When a subroutine label is prefixed by B<.pcc_sub>, the name of the subroutine
(i.e. the label) gets stored in the global stash.
find_global P0, "_the_sub"
invokecc
print "back\n"
end
.pcc_sub _the_sub:
print "in sub\n"
invoke P1
=head2 Optimized Tail Calls
find_global P0, "_the::sub"
invokecc
print "back\n"
end
.pcc_sub _the::sub:
print "in sub\n" # must preserve P1
find_global P0, "_next::sub"
get_addr I0, P0 # get the absolute address
jump I0 # jump to absolute address
.pcc_sub _next::sub: # must preserve P1
print "in next sub\n"
invoke P1 # return to main
=head1 FILES
F<src/pmc/sub.pmc>, F<src/pmc/closure.pmc>,
F<src/pmc/continuation.pmc>, F<src/pmc/coroutine.pmc>, F<sub.c>,
F<t/pmc/sub.t>
=head1 SEE ALSO
F<docs/pdds/pdd03_calling_conventions.pod> F<imcc/docs/calling_conventions.pod>
=head1 AUTHOR
Leopold Toetsch <lt@toetsch.at>
syntax highlighted by Code2HTML, v. 0.9.1