Subroutines
and methods are the basic building blocks of larger programs. At the
heart of every subroutine call are two fundamental actions: it has to
store the current location so it can come back to it, and it has to
transfer control to the subroutine. The
bsr
opcode does both. It pushes the address
of the next instruction onto the control stack, and then branches to
a label that marks the subroutine:
print "in main\n" bsr _sub print "and back\n" end _sub: print "in sub\n" ret
At the end of the subroutine, the ret
instruction
pops a location back off the control stack and goes there, returning
control to the caller. The
jsr
opcode pushes the current location onto
the call stack and jumps to a subroutine. Just like the
jump
opcode, it takes an absolute address in an
integer register, so the address has to be calculated first with the
set_addr
opcode:
print "in main\n" set_addr I0, _sub jsr I0 print "and back\n" end _sub: print "in sub\n" ret
A bsr
or
jsr
is fine for a simple subroutine call, but few subroutines are quite that simple. The biggest issues revolve around register usage. Parrot has 32 registers of each type, and the caller and the subroutine share the same set of registers. How does the subroutine keep from destroying the caller’s values? More importantly, who is responsible for saving and restoring registers? Where are arguments for the subroutine stored? Where are the subroutine’s return values stored? A number of different answers ...
No credit card required