4.3BSD/usr/contrib/icon/docs/tr83-10c.roff

.NH 3
\*Mrt/arith.s\fR
.SH
Overview
.PP
\*Marith.s\fP contains code for routines that add,\^ subtract,\^ and
multiply integers and check for overflow.  If overflow occurs,\^
run-time error 203 is produced.
.PP
The arguments to \*Mckadd\fP,\^ \*Mcksub\fP,\^ and \*Mckmul\fP are
two C \*Mlong\fP integers on which to operate.  For example,\^
if \*Mckadd\fP were written in C,\^ it would be declared
.Ds
long ckadd(a,\^b)
long a,\^b;
{
\&\*(El
}
.De
The routines return the result of the operation
using standard C return conventions.
.SH
\*Marith\fP on the VAX
.PP
The two arguments appear on the stack; \*Ma\fP is at \*M4(ap)\fP and
\*Mb\fP is at \*M8(ap)\fP.  The appropriate 3-operand VAX instruction
is used to perform the operation and the result is placed in \*Mr0\fP
in accordance with C return conventions.  If overflow occurs
during the operation,\^ the overflow bit in the program status word
is set.
.PP
After the operation is performed,\^ the overflow bit is
checked.  If it is on,\^ indicating that an overflow occurred,\^ a branch
is taken to \*Moflow\fP,\^ where \*Mrunerr(203,\^0)\fP is called.
If overflow did not occur,\^ the routine returns and the value in
\*Mr0\fP is the value returned to the calling expression.
.PP
\*Marith.s\fP is trivial on the VAX because the hardware supports
operations on C \*Mlong\fP integers.  This may not be the case on the
target machine.  If so,\^ \*Marith.s\fP will be considerably more
complicated.  However,\^ it usually is not difficult to locate routines
that perform these functions.  As a last resort,\^ look at the code the C
compiler generates for the various arithmetic operations on long
integers.
.NH 3
\*Mrt/fail.s\fR
.SH
Overview
.PP
\*Mfail\fP handles the failure of built-in procedures and operations.
Built-in procedures and operations are C routines and they signal
failure by calling \*Mfail()\fP.  When a failure of this type
occurs,\^ the failure must be transmitted to the Icon expression
whose evaluation is in progress and that requires the services of
a C routine.
.SH
Generic Operation
.PP
\*Mfail\fP itself does very little,\^ the real work is done by
\*Mefail\fP.  \*Mfail\fP pops the stack
back to where it was before the C routine was called and then
branches to \*Mefail\fP to make the enclosing expression fail.
.PP
\*Mfail\fP is akin to \*Mpfail\fP in that it pops the stack back
to a state that it was in when an expression was being evaluated
and then causes failure of the expression.  The primary difference
is that an Icon procedure frame is being removed in \*Mpfail\fP and
it contains extra information that must be restored.
.SH
\*Mfail\fP on the VAX
.PP
\*M_boundary\fP points to the procedure frame for the first C routine
that was called from Icon.  \*Mfp\fP is loaded from \*M_boundary\fP and
this puts the stack back to the state that it was in when the 
C routine was entered.  The C routine is for either a built-in procedure
such as \*Mread\fP or for an operator such as \*M+\fP.  For a
built-in procedure,\^ the procedure frame now on the top of the stack
(after loading \*Mfp\fP from \*M_boundary\fP) is the frame constructed
in \*Minvoke\fP.  For an operator,\^ the frame on the stack is the
one constructed when the interpreter loop called the C routine
for the operator.
.PP
The task at hand is to remove the procedure frame and restore the
registers that were saved in the frame.  The mask/psw word of the
frame is manipulated so that the mask portion of the word resides
in bits 0:11 of \*Mr0\fP and the remaining bits of \*Mr0\fP are 0.
The VAX \*Mpopr\fP instruction takes a register mask as an operand
and pops words from the stack into the registers indicated by
the mask.  For example,\^
.Ds
popr   $0x0005
.De
moves the top word of the stack into \*Mr0\fP and the second stack
word into \*Mr2\fP.  \*Msp\fP is then incremented by 8.
.PP
The saved registers start at \*M20(fp)\fP and \*Msp\fP is loaded
with this address.  Then \*Mpopr r0\fP restores the registers
that are saved in the frame.  Note that the manipulations of the
mask/psw are necessary because it is not known \fIa priori\fP which
registers were saved.  In particular,\^ \*Mpopr $0x0fff\fP would
be disastrous.
.PP
After the registers have been restored,\^ \*Map\fP and \*Mfp\fP are
restored from the saved \*Map\fP and \*Mfp\fP values in the
frame.
.PP
At this point,\^ the stack is as it was before the frame for
the built-in procedure or operator was created.  All that
remains is to signal failure in the expression being evaluated
and this is done by branching to \*Mefail\fP.
.ne 1i
.NH 3
\*Mlib/pret.s\fR
.SH
Overview
.PP
\*Mpret\fP handles the return of a value from an Icon procedure.
\*Mpret\fP is called from the interpreter loop with a single
argument (which is on the stack)
that is the value being returned.  The value is dereferenced
if necessary.  If tracing is on,\^ a trace message is produced.  The
return value is copied over \*(e0 in the frame of the procedure that
is returning a value.  The procedure frame is removed,\^ leaving
the result on the stack,\^ and \*Mpret\fP returns.
.SH
Generic Operation
.LP
.Ls
.Np
\*M&level\fP is decremented because a procedure is being exited.
.Np
The stack address where the return value is
to be placed is calculated.  Recall that when a procedure is invoked,\^ the
return value (if any) ultimately replaces \*(e0,\^ the descriptor
for the procedure returning the value.
.Np
The value being returned must be dereferenced if it is a local
variable or argument.  This is because local variables and arguments
are on the stack and the portion of the stack associated with
a procedure ``goes away'' when a procedure returns.  If the
return value is a variable (is of type \*MT_VAR\fP)
and its address
is between the base of the current expression stack*,\^
and the stack pointer,\^ it is dereferenced.
If it is a substring trapped variable (is of type \*MT_TVAR\fP
and points to a block of type \*MT_TVSUBS\fP),\^ and the address of the
variable containing the substring 
is between the base of the current expression stack
and the stack pointer,\^ it is dereferenced.
.FS
*For purposes of uniformity,\^ the system stack is treated
as if it were a co-expression stack.  The global variable
\*Mcurrent\fP is a pointer to the descriptor for the co-expression
stack block for the current co-expression.  Co-expressions
need not be implemented; it is only important that \*Mcurrent\fP
and the descriptor that it points to be initialized correctly.
This is done in \*Miconx/init.c\fP.
.FE
.Np
If \*M&trace\fP is non-zero,\^ \*Mrtrace\fP is called with the
address of the block for the returning procedure and the
address of the value being returned.
.Np
\*Mfp\fP,\^ \*M_line\fP,\^ and
\*M_file\fP are restored from the returning procedure.
Because the impending return restores control to the Icon
environment,\^ \*M_boundary\fP is cleared.
.Np
\*Mpret\fP returns from the Icon procedure by executing
a return instruction.  Because the current \*Mfp\fP points to the
procedure frame for the Icon procedure,\^ and the frame was
built by \*Minvoke\fP,\^ the return is effectively a return
from \*Minvoke\fP and the net result is the return value
left on the stack. 
.Le
.SH
\*Mpret\fP on the VAX
.PP
\*Mpret\fP does not save any registers because the frame built
upon entry to \*Mpret\fP is discarded.
.PP
\*M_boundary\fP is set because \*Mderef\fP may be called and \*Mderef\fP
can cause a garbage collection.
.PP
\*M_k_level\fP is decremented because a procedure is being exited.
.PP
\*Mpret\fP needs to know the address of the descriptor for the Icon
procedure that is returning.  Before \*Mpret\fP was called,\^ \*Mfp\fP
pointed at the procedure frame for the current Icon procedure (which
is now returning),\^ and \*Map\fP pointed at its argument list.  The
call to \*Mpret\fP created a procedure frame which contains the old
\*Map\fP.  This value is extracted and used in conjunction with
\fInargs\fP to calculate the address of the descriptor for the
procedure.  This value is stored in \*Mr11\fP for future use.
.PP
As described,\^ the value being returned needs to be dereferenced
in certain cases.  The return value is a descriptor and is the
argument to \*Mpret\fP.  The first word of this descriptor
lies at \*M8(ap)\fP and contains type and flag information.  This
word is placed in \*Mr1\fP for further examination.
.PP
The VAX \*Mbitl\fP instruction tests a set of bits.  The two
operand values are ANDed together and the condition codes
are set according to the value of the result.  The result itself
is discared.  The instruction
.Ds
bitl   $F_NQUAL,\^r1
.De
ANDs the type and flags word with the \*MF_NQUAL\fP mask.
The \*MF_NQUAL\fP bit is set if a descriptor is \fInot\fP a
string qualifier.
If the \*MF_NQUAL\fP bit is not on,\^ the result of the
AND is a 0.  The test is followed by
.Ds
beql   chktrace
.De
Thus,\^ if the return value \fIis\fP a string qualifier,\^ a branch
is taken to \*Mchktrace\fP,\^ and no dereferencing is performed.
.PP
If the return value does have the \*MF_NQUAL\fP attribute,\^ it
is checked to see if it is a variable. The \*MF_VAR\fP bit is tested.
If it is not on,\^ the return value is not a variable and does
not have to be dereferenced.  A branch is made to \*Mchktrace\fP if
this is the case.
.PP
If a variable is in hand,\^ the \*MF_TVAR\fP bit is checked to see
if it is a trapped variable.  If it is not a trapped variable,\^ the
address field of the return value's descriptor is moved into \*Mr1\fP for
further testing and a branch is taken to \*Mchkloc\fP.
.PP
If the return value is a substring trapped variable,\^ it may reference
a local variable or an argument.  The type bits of the descriptor
are isolated by ORing it with \*MTYPEMASK\fP.  If the type
is not \*MT_TVSUBS\fP,\^ no dereferencing is needed and a branch
is taken to \*Mchktrace\fP.  If it is a substring trapped variable,\^
the address of the variable containing the substring is obtained
from the trapped variable's data block and is loaded into \*Mr1\fP.
.PP
At this point (\*Mchkloc\fP),\^ \*Mr1\fP points to a descriptor
that is directly or indirectly referenced by the return value.
If the descriptor is in the current expression stack,\^ the return
value must be dereferenced.  \*Mr1\fP is first compared to
\*Msp\fP.  If it is less than \*Msp\fP,\^ the descriptor is below
the stack and a branch is made to \*Mchktrace\fP.  Otherwise,\^
\*Mr1\fP is compared to the base address of the current expression
stack.  If \*Mr1\fP is greater than the base of stack,\^ it is
above the stack and a branch is made to \*Mchktrace\fP.
.PP
It is now certain that the return value must be
dereferenced,\^ lest it ``disappear'' when the portion of the stack
it is in is re-used.  The address of the return value is pushed
on the stack and \*Mderef\fP is called.  Note that \*Mderef\fP completely
handles dereferencing of substring trapped variables and thus no
special provisions need to be made.
.PP
At \*Mchktrace\fP,\^ the return value has been dereferenced if
necessary and it is time to produce a tracing message if \*M&trace\fP
is non-zero.  \*Mrtrace\fP does the work and it
requires two arguments: the address of the block for the returning
procedure,\^ and the address of the return value.  Earlier,\^ the
address of descriptor for the procedure block was calculated and left
in \*Mr11\fP.  The second word of this descriptor is pushed on
the stack along with the address of the return value.
.PP
\*Mpret\fP ``returns'' the designated
value by overwriting the procedure's descriptor
with the descriptor of the return value.  \*Mr11\fP points at the
descriptor for the procedure and \*M8(ap)\fP still points at the
descriptor for the return value,\^ so
.Ds
movq   8(ap),\^(r11)
.De
does the trick.
.PP
Everything is set,\^ the actual return must be performed.  The \*Mfp\fP
saved in the current frame is the procedure frame pointer of the Icon
procedure and the saved value is loaded into \*Mfp\fP to bring
the Icon procedure frame to the top of the stack.  \*M_line\fP and
\*M_file\fP are restored from the Icon procedure frame.
\*M_boundary\fP is cleared because the return will take execution back
into an Icon realm.
.PP
A \*Mret\fP is executed.  The return goes through the procedure
frame built by \*Minvoke\fP.  Thus,\^ control is returned to the point
just after the call to \*Minvoke\fP and it appears as if \*Minvoke\fP
itself had just returned.
.NH 3
\*Mlib/esusp.s\fR
.SH
Overview
.LP
\*Mesusp\fP suspends a value from an expression.  \*Mesusp\fP is
called from the interpreter loop and the value to suspend appears
as an argument.  A generator frame hiding the current expression
is created.  The surrounding expression frame is duplicated.
\*Mesusp\fP leaves the value being suspended on the top of the stack.
.PP
The \*Mesusp\fP operation arises from the alternation
(\*M\*(x1\ |\ \^\*(x2\fR) control
structure.  For example
.Ds
p(5 | 10)
.De
indicates that the call \*Mp(5)\fP should be made and if it fails,\^ then
\*Mp(10)\fP should be called. 
.PP
The function of \*Mesusp\fP is best explained using an example.
The following ucode is generated for \*Mp(5 | 10)\fP
.Ds
.ta .8i +.8i +.8i +.8i
	mark	L1
	var	0	\fR(the variable \*Mp\fR)\*M
	mark	L2
	int	0	\fR(constant 5)\*M
	esusp
	goto	L3
lab L2
	int	1	\fR(constant 10)\*M
lab L3
	invoke	1
	unmark	1
lab L1
.De
When execution reaches \*Mesusp\fP,\^ the stack looks like
.Ds
.ft R
.ta 1i
	expression marker with \*ML1\fR as failure address
	descriptor for variable \*Mp\fR
\*Mefp\fR \*(ar	expression marker with \*ML2\fR as failure address
\*Msp\fR \*(ar	descriptor for constant 5
.De
\*Mgfp\fP is zero at this point.
After the \*Mesusp\fP is performed,\^ the stack is
.Ds
.ft R
.ta 1i
\*Mefp\fR \*(ar	expression marker with \*ML1\fR as failure address
	descriptor for variable \*Mp\fR
	expression marker with \*ML2\fR as failure address
	descriptor for constant 5
\*Mgfp\fR \*(ar	generator frame built by \*Mesusp\fR
.ta 1i 3.3i
	descriptor for variable \*Mp\fR	} duplicated region
\*Msp\fR \*(ar	descriptor for constant 5
.De
A branch is taken to \*ML3\fP,\^ where \*Minvoke 1\fP is performed.
This invokes \*Mp\fP with one argument,\^ the constant 5 on the
stack.  If \*Mp(5)\fP succeeds,\^ the \*Munmark 1\fP is performed
and the stack is popped back through the \*ML1\fP expression frame,\^
the current location of \*Mefp\fP.
.PP
Suppose that instead of succeeding,\^ \*Mp(5)\fP fails.
\*Mp\fP fails by calling \*Mpfail\fP,\^ which removes the
procedure frame from the stack and then calls \*Mefail\fP.  The
previous stack picture shows what the stack looks like after the
procedure frame has been removed.  \*Mefail\fP finds that
\*Mgfp\fP is not null and restores certain values that are saved
in the generator frame.  The frame,\^ which was created by \*Mesusp\fP,\^
contains a return address that points to \*Mefail\fP.  Thus,\^ when
\*Mefail\fP removes the frame by returning through it,\^ control goes
back to the start of \*Mefail\fP and the stack is
.Ds
.ft R
.ta 1i
	expression marker with \*ML1\fR as failure address
	descriptor for variable \*Mp\fR
\*Mefp\fR \*(ar	expression marker with \*ML2\fR as failure address
\*Msp\fR \*(ar	descriptor for constant 5
.De
This time around,\^ \*Mgfp\fP is zero,\^ so \*Mefail\fP must remove
the current expression frame and branch to the failure address in
the frame's marker.  When the expression frame is removed,\^ the
stack looks like
.Ds
.ft R
.ta 1i
	expression marker with \*ML1\fR as failure address
\*Msp\fR \*(ar	descriptor for variable \*Mp\fR
.De
The failure address in the expression frame was \*ML2\fP,\^ so control
is transferred to \*Mlabel L2\fP in the ucode.  (Note how much went
on as the result of the \*Minvoke\fP being executed.)  The
instruction \*Mint 1\fP is executed and a descriptor for the constant
10 is pushed on the stack giving:
.Ds
.ft R
.ta 1i
	expression marker with \*ML1\fR as failure address
	descriptor for variable \*Mp\fR
\*Msp\fR \*(ar	descriptor for constant 10
.De
\*Minvoke 1\fP is performed again,\^ which does \*Mp(10)\fP.
.PP
If \*Mp(10)\fP succeeds,\^ the \*Munmark 1\fP is executed,\^ which
removes the \*ML1\fP marker and transfers control to \*ML1\fP.
If \*Mp(10)\fP fails,\^ the same thing happens,\^ but \*Mefail\fP
does the work rather than \*Munmark\fP.
.SH
Generic Operation
.LP
.Ls
.Np
The procedure frame created by the call to \*Mesusp\fP partially
forms the generator frame. The frame is completed by pushing
\*M_boundary\fP,\^ \*M_k_level\fP,\^ \*M_line\fP,\^ and \*M_file\fP.
The generator frame pointer is set to point at the word of the
frame which contains the boundary.
.Np
The bounds of the expression frame to be duplicated are determined.
The lower bound is the stack word above the current expression frame
marker.
The upper bound is dependent on \*Mefp\fP and \*Mgfp\fP
values saved in the current expression marker.  If the saved \*Mgfp\fP is
non-zero,\^ the upper bound is the first word below the generator
frame marker.  If the saved \*Mgfp\fP is zero,\^ the upper bound is
the first word below the expression frame marker referenced by the
saved \*Mefp\fP.  In the example,\^ this region only contains
the descriptor for the variable \*Mp\fP.
The region is copied to the top of the stack.  The stack pointer is
adjusted to point to the new top of stack.
.Np
The value being suspended is pushed on the stack.
.Np
The return address in the new generator frame is replaced by the address of
\*Mefail\fP so that when \*Mefail\fP removes the frame by returning through
it,\^ \*Mefail\fP regains control.  The old return address is
momentarily retained.  The procedure frame pointer and argument
pointer are restored.  \*M_boundary\fP is cleared because control is
returning to Icon code.
.Np
\*Mefp\fP in the current expression
marker replaces the expression frame pointer.  Thus,\^ if an \*Munmark\fP
is performed,\^ the entire expression frame is removed.  In the example,\^
this happens if \*Mp(5)\fP or \*Mp(10)\fP succeeds.
.Np
The return \*Mpc\fP value which was saved is jumped to.  This is in
effect a return from \*Mesusp\fP,\^ but the stack is untouched.
.Le
.SH
\*Mesusp\fP on the VAX
.PP
When \*Mesusp\fP is entered,\^ the generator frame is partially
constructed.  \*Mipc\fP,\^ \*Mgfp\fP,\^ and \*Mefp\fP are saved in
the frame.  \*M_boundary\fP is set to the current \*Mfp\fP value
and is pushed on the stack.  The generator frame pointer,\^ is pointed at
the word containing the boundary.
The frame is completed by pushing \*M_k_level\fP,\^ \*M_line\fP,\^
and \*M_file\fP on the stack.
.PP
The lower bound of the region to copy is the first word above the
current expression frame marker.  Recall that an expression frame
looks like
.Ds
.ft R
.St
\*Mefp\fR \*(ar	0	old expression frame pointer
	-4	old generator frame pointer
	-8	failure address
.De
Thus,\^
.Ds
addl3   $4,\^efp,\^r0
.De
points \*Mr0\fP at the lower end of the region to copy.
.PP
The upper bound of the region to copy is the low word of the marker
for the enclosing generator or expression frame.  If \*Mgfp\fP
is non-zero the generator frame marker is used.
Otherwise,\^ the expression frame marker is used.  Recall that a
generator frame looks like
.Ds
.ft R
.St
		saved registers
	20	reactivation address (saved \*Mpc\fR)
	16	saved \*Mfp\fR
	12	saved \*Map\fR
	8	\*Mpsw\fR and register mask
	4	0
\*Mgfp\fR \*(ar	0	boundary
	-4	saved \*M_k_level\fR
	-8	saved \*M_line\fR
	-12	saved \*M_file\fR
.De
So,\^ if the saved \*Mgfp\fP is non-zero,\^ the upper bound of the region
to copy is
.Ds
.ft R
saved \*Mgfp\fR - 12
.De
Otherwise,\^ it is
.Ds
.ft R
saved \*Mefp\fR - 8
.De
The appropriate calculation is performed and \*Mr2\fP pointed at the
bounding word.
.LP
At this point,\^ the stack looks something like
.Ds
.ft R
.St
\*Mr2\fR \*(ar		low word of expression or generator frame marker
		last word of region to copy
		\*(El
\*Mr0\fR \*(ar	4	first word of region to copy
\*Mefp\fR \*(ar	0	saved expression frame pointer
	-4	saved generator frame pointer	expression marker
	-8	failure label
	8	descriptor for value to suspend
	4	\*Mnargs\fR (1)
\*Map\fR \*(ar	0	\*Mnwords\fR (3)
	-4	saved \*Mr11\fR (\*Mefp\fR)
		saved \*Mr10\fR (\*Mgfp\fR)
	24	saved \*Mr9\fR (\*Mipc\fR)
	20	reactivation address (saved \*Mpc\fR)
	16	saved \*Mfp\fR
	12	saved \*Map\fR	generator marker
	8	\*Mpsw\fR and register mask
	4	0
	0	boundary (\*Mfp\fR at entry to \*Mesusp\fR)
	-4	\*M_k_level\fR
	-8	\*M_line\fR
\*Msp\fR \*(ar	-12	\*M_file\fR
.De
.PP
The region starting at \*Mr0\fP and extending to \*Mr2\fP is to be
copied to the top of the stack.  The length of the region in bytes is
calculated in \*Mr2\fP.
The value of \*Mr2\fP is subtracted from \*Msp\fP,\^ moving \*Msp\fP
down to accommodate the region.  The region is then copied using
.Ds
movc3   r2,\^(r0),\^(sp)
.De
which moves \*Mr2\fP bytes starting at \*M0(r0)\fP to \*M0(sp)\fP.
.PP
The descriptor for the value to suspend is at \*M8(ap)\fP and it
is pushed on the stack using
.Ds
movq   8(ap),\^(sp)
.De
.LP
The stack now looks like
.Ds
.ft R
.ta 0.90i
\*Mr2\fR \*(ar	low word of expression or generator frame marker
	last word of region to copy
	\*(El
\*Mr0\fR \*(ar	first word of region to copy
\*Mefp\fR \*(ar	expression frame marker
\*M8(ap)\fR \*(ar	descriptor for value to suspend
	\*(El
\*Mgfp\fR \*(ar	generator frame marker
	last word of copied region
	\*(El
	first word of copied region
\*Msp\fR \*(ar	descriptor for value to suspend
.De
.PP
The reactivation address that is saved in the generator frame is moved
into \*Mr1\fP for later use.  It is then replaced by the address
of \*Mefail\fP so that when the frame is returned through,\^ control
will go to \*Mefail\fP.
.PP
\*Mfp\fP and \*Map\fP are restored from the generator frame.  \*M_boundary\fP
is cleared because control is being returned to Icon code.
.PP
\*Mefp\fP is pointed at the previous expression frame.  That is,\^ \*Mefp\fP
is moved back one step in the expression frame chain.
.PP
Control is returned to the interpreter loop by branching to
\*M0(r1)\fP,\^ the reactivation address originally saved in the generator frame.
.NH 3
\*Mlib/lsusp.s\fR
.SH
Overview
.PP
\*Mlsusp\fP suspends a value from a limited expression.  A limited
expression arises from a source code expression of the form
.Ds
\*(x1\ \e\ \^\*(x2
.De
This limits \*(x1 to at most \*(x2 results.  (\*(x2
must be a non-negative integer.)
.PP
\*Mlsusp\fP is just like \*Mesusp\fP except that it has provisions for
checking and decrementing the limit counter and taking the appropriate
action when the counter reaches zero.  As a simple example,\^ consider
.Ds
p(x\ \e\ \^2)
.De
which generates the ucode
.Ds
.ta .8i +.8i +.8i
	mark	L1
	var	0	\fR(variable \*Mp\fR)\*M
	int	0	\fR(constant 2)\*M
	limit
	mark	L0
	var	1	\fR(variable \*Mx\fR)\*M
	lsusp
	invoke	1
	unmark	1
	\*(El
.De
When control reaches the \*Mlsusp\fP,\^ the stack looks like
.Ds
.ft R
.S1
	expression marker with \*ML1\fR as failure label
	descriptor for variable \*Mp\fR
	descriptor for integer with value of 2
\*Mefp\fR \*(ar	expression marker with \*ML0\fR as failure label
\*Msp\fR \*(ar	descriptor for variable \*Mx\fR
.De
The \*Mlimit\fP instruction insures that the value on the top of
the stack (its argument) is a non-negative integer.  After \*Mlsusp\fP,\^ the
stack is
.Ds
.ft R
.ta 0.75i 3.3i
\*Mefp\fR \*(ar	expression marker with \*ML1\fR as failure label
	descriptor for variable \*Mp\fR
	descriptor for integer with value of 2
	expression marker with \*ML0\fR as failure label
	descriptor for variable \*Mx\fR
\*Mgfp\fR \*(ar	generator frame built by \*Mlsusp\fR
	descriptor for variable \*Mp\fR	} duplicated region
\*Msp\fR \*(ar	descriptor for variable \*Mx\fR
.De
This is the same thing that \*Mesusp\fP would do,\^ with the
exception that the limit counter,\^ the integer descriptor,\^ is not
part of the duplicated region.
.SH
Generic Operation
.LP
.Ls
.Np
The procedure frame created by the call to \*Mesusp\fP partially
forms the generator frame.
.Np
The limit counter is decremented and if it is zero,\^ no suspension
is performed.  Instead,\^ the current expression frame is removed
and the limit counter is replaced by the value that would have been
suspended had the limitation not been in effect.  \*Mlsusp\fP returns,\^
leaving the value on the top of the stack.
.Np
If the limit counter is not zero,\^ execution proceeds exactly
as it does for \*Mesusp\fP with the exception that the determination
of the region to copy takes the limit counter into consideration and
does not include it in the region that is copied.
.Le
.SH
\*Mlsusp\fP on the VAX
.PP
When \*Mlsusp\fP is entered,\^ the generator frame is partially
constructed.  \*Mipc\fP,\^ \*Mgfp\fP,\^ and \*Mefp\fP are saved in
the frame.
.PP
The expression frame and associated limit counter have the following
layout:
.Ds
.ft R
.St
	8	number of results left
\u			limit counter\d
.sp -1
	4	\*MD_INTEGER\fR (type and flags word)
\*Mefp\fR \*(ar	0	old expression frame pointer
	-4	old generator frame pointer	expression frame
	-8	failure label
.De
.PP
The limit counter is decremented and if it is not zero,\^ control
passes to \*Mdosusp:\fP and from then on execution proceeds
exactly as it does in \*Mesusp\fP.  Specifically,\^ 
the code beginning at \*Mdosusp:\fP
is an exact duplicate of that in \*Mesusp\fP with the
exception of the instruction that determines the lower bound of
the region to be duplicated.  \*Mesusp\fP uses
.Ds
addl3 $4,\^efp,\^r0
.De
which points \*Mr0\fP at the word immediately above the expression
frame.  \*Mlsusp\fP uses
.Ds
addl3 $12,\^efp,\^r0
.De
which points \*Mr0\fP at the word above the limit counter that is
directly above the expression frame.
.PP
If the limit counter is zero,\^ the counter is to be replaced with the
value which was to be suspended.  The value appears as an argument to
\*Mlsusp\fP.  This is accomplished with
.Ds
movq   8(ap),\^4(efp)
.De
.PP
The value of \*Mgfp\fP that is stored in the
expression frame is restored.
.PP
The saved \*Mpc\fP in \*Mlsusp\fP's frame is moved into \*Mr0\fP for
later use.
.PP
The expression frame is removed by moving \*Mefp\fP into \*Msp\fP,\^
which leaves the expression frame marker word that contains the old
\*Mefp\fP on the top of the stack.  This word is popped of the stack
and moved into \*Mefp\fP,\^ restoring \*Mefp\fP and leaving the
return (would-be suspended) value on the top of the stack.
.PP
\*Map\fP and \*Mfp\fP are restored from the procedure frame made upon
entry to \*Mlsusp\fP.
.PP
\*Mlsusp\fP ``returns'' by jumping to \*M0(r0)\fP,\^ the return point
that was saved in the frame.  The value that was to be suspended,\^ but
was not because of the limitation,\^ is left on the top of the stack.
.NH 3
\*Mlib/psusp.s\fR
.SH
Overview
.PP
\*Mpsusp\fP suspends a result from an Icon procedure.  \*Mpsusp\fP is
called from the interpreter loop and the value to suspend appears
as an argument to \*Mpsusp\fP.  A generator frame is created and
the generator or expression frame immediately containing the frame
for the suspending procedure
is duplicated on top of the stack.  \*Mpsusp\fP returns through
the duplicated frame,\^ leaving the suspending value on top
of the stack.  A return from \*Mpsusp\fP is manifested as a return
from \*Minvoke\fP.
.PP
The \*Mpsusp\fP operation arises from the \*Msuspend \*(xx\fR statement.
.PP
\*Mpsusp\fP is conceptually similar to \*Mesusp\fP,\^ the difference
being that a procedure frame is part of the expression frame
being duplicated and that requires some extra work.
To get a feel for what \*Mpsusp\fP does,\^ consider a simple example:
.PP
.Ds
.ta .5i +.5i +.5i +.5i +.5i
procedure main()
	f(p(3))
end

procedure p(a)
	suspend a
end
.De
.LP
The generated ucode for \*Mmain\fP is
.Ds
.ta .8i +.8i +.8i +.8i +.8i
	\*(El
	mark	L1
	var	0	\fR(the variable \*Mf\fR)\*M
	var	1	\fR(the variable \*Mp\fR)\*M
	int	0	\fR(the constant 3)\*M
	invoke	1
	invoke	1
	\*(El
lab	L1
.De
and the generated code for \*Mp\fP is
.Ds
	mark	p.L1
	mark	L0
	var	0	\fR(the argument \*Ma\fR)\*M
	psusp
	\*(El
lab	p.L1
.De
.LP
When control reaches the \*Minvoke\fP instruction,\^ the stack resembles
.Ds
.ft R
.S1
\*Mefp\fR \*(ar	expression marker with \*ML1\fR as failure address
	descriptor for variable \*Mf\fR
	descriptor for variable \*Mp\fR
\*Msp\fR \*(ar	descriptor for constant 3
.De
after \*Mp\fP has been invoked,\^ just before the \*Mpsusp\fP is
executed the stack is
.Ds
.ft R
.S1
	expression marker with \*ML1\fR as failure address
	descriptor for variable \*Mf\fR
	descriptor for variable \*Mp\fR
	descriptor for constant 3 (becomes argument \*Ma\fR)
	procedure frame for \*Mp\fR (created by \*Minvoke\fR)
	expression marker with \*Mp.L1\fR as failure address
\*Mefp\fR \*(ar	expression marker with \*ML0\fR as failure address
\*Msp\fR \*(ar	descriptor for argument \*Ma\fR
.De
Just before control returns from \*Mpsusp\fP,\^ the stack is
.Ds
.ta 0.75i 3.25i
.ft R
	expression marker with \*ML1\fR as failure address
	descriptor for variable \*Mf\fR
	descriptor for variable \*Mp\fR
	descriptor for constant 3
	procedure frame for \*Mp\fR
	expression marker with \*Mp.L1\fR as failure address
	expression marker with \*ML0\fR as failure address
	descriptor for argument \*Ma\fR (being suspended)
\*Mgfp\fR \*(ar	generator frame built by \*Mpsusp\fR
	descriptor for variable \*Mf\fR
	descriptor for variable \*Mp\fR	duplicated region
	descriptor for constant 3
\*Msp\fR \*(ar	procedure frame for \*Mp\fR
.De
After \*Mpsusp\fP returns,\^ the situation is
.Ds
\*Mefp\fR \*(ar	expression marker with \*ML1\fR as failure address
	descriptor for variable \*Mf\fR
	descriptor for variable \*Mp\fR
	descriptor for constant 3
	procedure frame for \*Mp\fR
	expression marker with \*Mp.L1\fR as failure address
	expression marker with \*ML0\fR as failure address
	descriptor for argument \*Ma\fR
\*Mgfp\fR \*(ar	generator frame built by \*Mpsusp\fR
	descriptor for variable \*Mf\fR
\*Msp\fR \*(ar	descriptor for constant 3 (the suspended value)
.De
.PP
The return from \*Mpsusp\fP goes to the second \*Minvoke\fP,\^ which
calls \*Mf\fP with one argument,\^ the constant 3 that was
suspended.  If \*Mf(3)\fP fails,\^ the procedure frame for
\*Mf\fP is removed.  \*Mefail\fP takes control and returns through
the generator frame built by \*Mpsusp\fP.  This leaves the
descriptor for \*Ma\fP on top of the stack.  Execution continues
by \*Mp\fP failing,\^ and then \*Mmain\fP failing.
.SH
Generic Operation
.LP
.Ls
.Np
The procedure frame created by the call to \*Mpsusp\fP partially forms
the generator frame.  \*M_boundary\fP is set as the current location
of \*Mfp\fP and it is added to the generator frame.
.Np
As in \*Mpret\fP,\^ the value being suspended must be dereferenced
in certain cases.  For example,\^ if the value is a local variable
or an argument,\^ it is dereferenced.  The same code that handles
dereferencing in \*Mpret\fP appears in \*Mpsusp\fP as well.
Note that while suspension leaves the local variables and arguments
of a procedure intact,\^ if the enclosing expression frame should
be removed by an \*Munmark\fP,\^ the procedure frame would be destroyed,\^
leaving undeferenced values pointing at meaningless data.
.Np
The generator frame is completed by pointing \*Mgfp\fP at the boundary
value already in the frame and by adding \*M_k_level\fP,\^ \*M_line\fP,\^
and \*M_file\fP.
.Np
The bounds of the expression frame to be duplicated are determined.
The lower bound is the low word of the procedure frame for the
suspending procedure and the upper bound is the marker for the
expression frame or generator frame which is just prior to the
procedure frame.  As in \*Mesusp\fP,\^ if \*Mgfp\fP is non-zero,\^
the marker it points to is used.  Otherwise,\^ the marker referenced
by \*Mefp\fP is used.  The \*Mgfp\fP and \*Mefp\fP values used
are those found in the procedure frame of the suspending procedure.
The region is copied to the top of the stack.
In the example,\^ the duplicated region contained the procedure
frame marker for \*Mp\fP,\^ and the descriptors for the constant 3,\^
and the variables \*Mp\fP and \*Mf\fP.
.Np
If \*M&trace\fP is non-zero,\^ \*Mstrace\fP is called to produce
a trace message noting that the procedure is suspending a value.
\*Mstrace\fP requires the address of the block for the suspending
procedure and the address of the descriptor for the value being
suspended.
.Np
\*M_line\fP and \*M_file\fP are restored from the frame of the
suspending procedure.  This is done because when \*Mpsusp\fP is
finished,\^ it is as if the Icon procedure had returned.  Thus,\^
the line number and file name need to be what they were before
the procedure was called.
.Np
The generator frame pointer saved in the duplicated procedure frame
on the top of the stack is replaced by the current value of
\*Mgfp\fP,\^ which points to the newly created generator frame.
When \*Mpsusp\fP returns through the frame on the top of the stack,\^
\*Mgfp\fP is restored from the value in the frame and \*Mgfp\fP
then references the new generator frame.
.Np
The descriptor for \*(a0 in the argument list of the Icon procedure
that is suspending is a descriptor for the procedure itself.  This
descriptor is replaced with the descriptor for the value being
suspended.  When \*Mpsusp\fP is done,\^ this descriptor is left on the
top of the stack.
.Np
\*M_boundary\fP is cleared because control is returning to Icon code.
.Np
\*Mpsusp\fP returns.  The return uses the duplicated procedure frame
on the top of the stack.  The result is that it appears as if the
\*Minvoke\fP that originally called the suspending procedure has
returned.
.Le
.SH
\*Mpsusp\fP on the VAX
.PP
When \*Mpsusp\fP is entered,\^ the generator frame is partially
constructed as a result of the call.  \*M_boundary\fP is set to the
current value of \*Mfp\fP and this value is pushed on the stack
as part of the generator frame.
.PP
The value being suspended needs to be dereferenced if it is a local
variable or an argument.  This operation is the same as is done in
\*Mpret\fP; consult the section on it for details of the actions
taken.
.PP
The generator frame is completed by pointing \*Mgfp\fP at the frame
word containing the boundary value and by adding \*M_k_level\fP,\^
\*M_line\fP,\^ and \*M_file\fP to the frame.
.PP
The region to be duplicated is determined.  The low word to be copied
is the low word of the procedure frame of the suspending procedure.
(The word that contains the 0.)  This is readily accessible as the
\*Mfp\fP saved the procedure frame of \*Mpsusp\fP and is placed in \*Mr7\fP.
.PP
The high word to be copied is dependent upon the expression and generator
environment of the suspending procedure.  If the \*Mgfp\fP
in the suspender's environment is not zero,\^ the word just below the
generator frame marker is the highest word to be copied.  If
\*Mgfp\fP is zero,\^ the word just below the expression marker pointed at
by \*Mefp\fP in the suspender's environment is the highest word to
be copied.
.PP
The fact that the saved \*Mefp\fP and \*Mgfp\fP
appear on the stack just below the \fInwords\fP word (referenced by
\*M0(ap)\fP) is used to retrieve and test them.  As in \*Mesusp\fP,\^
if the saved \*Mgfp\fP is non-zero,\^
.Ds
.ft R
saved \*Mgfp\fR - 12
.De
is used for the lower bound,\^ otherwise
.Ds
.ft R
saved \*Mefp\fR - 8
.De
is the lower bound.  \*Mr4\fP is pointed at the appropriate word on
the upper end.  As in \*Mesusp\fP,\^ \*Msp\fP is moved down to
accommodate the region to be duplicated and the region is copied to
the top of the stack using a \*Mmovc3\fP.
.PP
After \*M_k_level\fP is decremented,\^ \*M_k_trace\fP is checked to see
if a trace message should be produced.  If so,\^ \*Mstrace\fP is called with
pointers to the descriptors for the suspending procedure and the
value being suspended.  The address of the value being suspended is
\*M8(ap)\fP and the address of the descriptor for the procedure is
determined using the standard
.Ds
&\*(a0 = (nargs * 8) + 8 + ap
.De
calculation.
.PP
The values of \*M_line\fP and \*M_file\fP are restored from the
suspender's frame.
.PP
The saved \*Mgfp\fP in the duplicated procedure frame on the top of
the stack must be replaced by the current value of \*Mgfp\fP.  Finding the
location of the saved \*Mgfp\fP is a little tricky.  The distance
between \*Mfp\fP and \*Map\fP in the duplicated frame is calculated
by subtracting the value of \*Mfp\fP from the \*Map\fP value and putting
the result in \*Mr0\fP.  The value in \*Mr0\fP represents the distance
from the top of the stack to \*M0(ap)\fP.  Adding the
current \*Msp\fP (which points at the low word of the duplicated
procedure frame) to \*Mr0\fP points \*Mr0\fP at the \fInwords\fP word
of the new frame.  \*Map\fP normally points at the \fInwords\fP word,\^
so \*Mr0\fP serves as a pseudo-\*Map\fP.  It is known that the saved \*Mgfp\fP
is the second word below the \fInwords\fP word; thus the new \*Mgfp\fP
is stored in \*M\-8(r0)\fP,\^ replacing the old value.  Thus,\^ when \*Mpsusp\fP
returns through the duplicated frame,\^ the value just stored is
the restored value of \*Mgfp\fP.
.PP
The descriptor for the suspending procedure must be replaced by the
descriptor for the return value.  The previous calculation left
\*Mr0\fP pointing at \*M0(ap)\fP in the duplicated frame.  The
address of \*(a0 is calculated using
.Ds
&\*(a0 = (nwords * 4) + 4 + r0
.De
Note that \*M+ 4\fP accounts for the four bytes that the \fInwords\fP
word itself occupies.  The descriptor for the return value is put in
place using a \*Mmovq\fP.
.PP
\*Msp\fP is moved into \*Mfp\fP so that the pending return uses the
new frame on the top of the stack.
.PP
\*M_boundary\fP is cleared because control is going back into Icon
code.
.PP
A \*Mret\fP is executed to return from \*Mpsusp\fP.  This return uses
the duplicated procedure frame and thus the duplicated frame is
removed.  The final result is that it looks like the original call to
\*Minvoke\fP that started the Icon procedure has returned and
the suspended value is left on the top of the stack.
.ne 3v
.NH 3
\*Mrt/suspend.s\fR
.SH
Overview
.PP
\*Msuspend\fP suspends a value from a built-in procedure or operator.
\*Msuspend\fP is similar to \*Mpsusp\fP and amounts to little
more than a simplified version of it.  Recall that built-in
procedures are C functions; thus,\^ \*Msuspend\fP is directly called
from C.
.PP
A generator frame is created and the generator or expression frame
immediately containing the frame for the suspending procedure
is duplicated on the top of the stack.  \*Msuspend\fP returns through
the duplicated frame,\^ leaving the value being suspended on the top
of the stack.  When \*Msuspend\fP returns,\^ it appears as a return
from the original call to the built-in procedure.
.PP
Note that \*Msuspend\fP handles the suspension of values from both
built-in procedures such as \*Mupto\fP and from operators such as
the element generation operator,\^ \*M!\fP.  For built-in procedures,\^
the procedure frame is built by \*Minvoke\fP,\^ while for operators,\^
the procedure frame is built directly by the call to the appropriate
function from the interpreter loop.  
The value being suspended by the C function is represented
by the \*(a0 descriptor in the argument list.  When
\*Msuspend\fP is called,\^ the value to suspend is in place in
\*Marg0\fP.
.SH
Generic Operation
.PP
\*Msuspend\fP can be considered as a ``subset'' of \*Mpsusp\fP.  The
descriptions of operations in this section and the next are excerpts
from \*Mpsusp\fP.
.LP
The actions of \*Mpsusp\fP that are \fInot\fP taken by \*Msuspend\fP are:
.Ls
.Np
The return value does not need to be dereferenced because the
suspending function has already taken care of that.
.Np
No tracing message is produced because tracing is only done
for Icon procedures.
.Np
The return value does not need to be moved into the duplicated
procedure frame because it is already in place in the original procedure
frame and when the frame is duplicated,\^ the return value is
duplicated along with it.
.Np
\*M_k_level\fP is not decremented because \*M&level\fP keeps track of
Icon procedure calls and \*Msuspend\fP is returning from a C routine.
\*M_line\fP,\^ and \*M_file\fP are not restored because they are
not part of the procedure frame of the built-in procedure.
.Le
.LP
The operations that are performed by \*Msuspend\fP are:
.Ls
.Np
The procedure frame created by the call to \*Msuspend\fP partially forms
the generator frame.  \*M_boundary\fP is set as the current location
of \*Mfp\fP and it is added to the generator frame.
.Np
The bounds of the expression frame to be duplicated are determined.
The lower bound is the low word of the procedure frame for the
suspending procedure and the upper bound is the marker for the
expression frame or generator frame which is just prior to the
procedure frame.  As in \*Mesusp\fP,\^ if \*Mgfp\fP is non-zero,\^
the marker it points to is used.  Otherwise,\^ the marker referenced
by \*Mefp\fP is used.  The \*Mgfp\fP and \*Mefp\fP values used
are those found in the procedure frame of the suspending procedure.
The region is copied to the top of the stack.
.Np
The generator frame pointer saved in the duplicated procedure frame
on the top of the stack is replaced by the current value of
\*Mgfp\fP,\^ which points to the newly created generator frame.
When \*Msuspend\fP returns through the frame on the top of the stack,\^
\*Mgfp\fP is restored from the value in the frame and \*Mgfp\fP
then references the new generator frame.
.Np
\*M_boundary\fP is cleared because control is returning to Icon code.
.Np
\*Msuspend\fP returns.  The return uses the duplicated procedure frame
on the top of the stack.  The result is that it appears as if the
original call to the suspending procedure has returned.
.Le
.SH
\*Msuspend\fP on the VAX
.PP
When \*Msuspend\fP is entered,\^ the generator frame is partially
constructed as a result of the call.  \*M_boundary\fP is set to the
current value of \*Mfp\fP and this value is pushed on the stack
as part of the generator frame.
The generator frame is completed by pointing \*Mgfp\fP at the frame
word containing the boundary value and by adding \*M_k_level\fP,\^
\*M_line\fP,\^ and \*M_file\fP to the frame.
.PP
The region to be duplicated is determined.  The low word to be copied
is the low word of the procedure frame of the suspending function.
(The word that contains the 0.)  This is readily accessible as the
\*Mfp\fP saved in the procedure frame of \*Msuspend\fP and \*Mr7\fP is
pointed at the word containing the saved \*Mfp\fP.
.PP
The high word to be copied is dependent upon the expression and generator
environment of the suspending function.  If the \*Mgfp\fP
in the suspender's environment is not zero,\^ the word just below the
generator frame marker is the highest word to be copied.  If
\*Mgfp\fP is zero,\^ the just word below the expression marker pointed at
by \*Mefp\fP in the suspender's environment is the highest word to
be copied.
.PP
The fact that the saved \*Mefp\fP and \*Mgfp\fP
appear on the stack just below the \fInwords\fP word (referenced by
\*M0(ap)\fP) is used to retrieve and test them.  As in \*Mesusp\fP,\^
if the saved \*Mgfp\fP is non-zero,\^
.Ds
.ft R
saved \*Mgfp\fR - 12
.De
is used for the lower bound,\^ otherwise
.Ds
.ft R
saved \*Mefp\fR - 8
.De
is the lower bound.  \*Mr4\fP is pointed at the appropriate word on
the upper end.  As in \*Mesusp\fP,\^ \*Msp\fP is moved down to
accommodate the region to be duplicated and the region is copied to
the top of the stack using a \*Mmovc3\fP.
.PP
The saved \*Mgfp\fP in the duplicated procedure frame on the top of
the stack must be replaced by the current value of \*Mgfp\fP.  Finding the
location of the saved \*Mgfp\fP is a little tricky.  The distance
between \*Mfp\fP and \*Map\fP in the duplicated frame is calculated
by subtracting the \*Mfp\fP value from the \*Map\fP value and putting
the result in \*Mr0\fP.  The value in \*Mr0\fP represents the distance
from the top of the stack to \*M0(ap)\fP.  Adding the
current \*Msp\fP (which points at the low word of the duplicated
procedure frame) to \*Mr0\fP points \*Mr0\fP at the \fInwords\fP word
of the new frame.  \*Map\fP normally points at the \fInwords\fP word,\^
so \*Mr0\fP serves as a pseudo-\*Map\fP.  It is known that the saved \*Mgfp\fP
is the second word below the \fInwords\fP word and thus the new \*Mgfp\fP
is stored in \*M\-8(r0)\fP,\^ replacing the old value.  Thus,\^ when \*Msuspend\fP
returns through the duplicated frame,\^ the value just stored is
the restored value of \*Mgfp\fP.
.PP
A \*Mret\fP is executed to return from \*Msuspend\fP.  This return uses
the duplicated procedure frame and thus the duplicated frame is
removed.  The final result is that it looks like the original call to
function has returned and
the suspended value is left on the top of the stack.
.ne 2i
.NH 3
\*Mfunctions/display.c\fR
.SH
Overview
.PP
\*Mdisplay.c\fP implements the Icon function \*Mdisplay()\fP.
\*Mdisplay\fP traces back through Icon procedure frames printing various
sorts of information.  Therefore,\^ some of the code in \*Mdisplay\fP
is machine dependent.
.SH
Generic Operation
.PP
\*Mdisplay\fP makes one calculation that is machine dependent.  The
calculation is to take a frame whose address is contained in the
variable \*Mfp\fP and calculate the address of the procedure
descriptor in the frame that is pointed at by the \*Mfp\fP value
saved in the frame that \*Mfp\fP references.
.SH
\*Mdisplay\fP on the VAX
.PP
\*Map\fP and \*Mfp\fP are restored from the frame referenced by
\*Mfp\fP.  The number of arguments to the procedure is contained in
\*Map\^[1]\fP.  This is loaded into the variable \*Mn\fP.  The address
of the procedure descriptor (\*(a0) is calculated using:
.Ds
dp = ap + 2 + 2*n
.De
Note that this is the same computation that is made at several points
in the assembly language routines.  As in \*Msweep\fP,\^ the calculations are
being made using \*Mint *\fP variables and thus the constants
represent word counts instead of byte counts as they do in the
assembly language routines.

.NH 3
\*Mrt/gcollect.s\fR
.SH
Overview
.PP
\*Mgcollect\fP is a simple routine that insures that garbage
collections are done using the stack for the main co-expression.
This done by saving certain values in the co-expression block of the
current co-expression,\^ restoring values from the co-expression block
for \*M&main\fP,\^ calling the garbage collector,\^ and then restoring
the original values.
\*Mgcollect\fP takes a single argument that is passed directly
to \*Mcollect\fP.
.PP
If co-expressions are not implemented,\^ \*Mgcollect\fP need only
consist of a call to \*Mcollect\fP,\^ being sure to pass its argument
on through.
.SH
\*Mgcollect\fP on the VAX
.PP
\*Mr0\fP is pointed at the heap block for the current co-expression.
\*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP are saved in the appropriate
words of the block.
.PP
\*Mr0\fP is pointed at the heap block for \*M&main\fP,\^ the
co-expression that is initially active.  \*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP
are restored from values saved in the block.
.PP
The argument to \*Mgcollect\fP is pushed on the stack,\^ and
\*Mcollect\fP is called with one argument.
.PP
\*Mr0\fP is pointed at the heap block for the current co-expression
and the \*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP values saved at the
start of the routine are restored.
.PP
\*Mgcollect\fP returns.
.NH 3
\*Mrt/sweep.c\fR
.SH
Overview
.PP
\*Msweep\fP is used during garbage collection to sweep a stack,\^
marking all the descriptors in the stack.  \*Msweep\fP begins at
the low word (the top) of a stack and moves up through the stack,\^
looking for descriptors and marking them.
A stack is composed of four kinds of
objects: descriptors,\^ and markers for procedure,\^
generator,\^ and expression frames.  \*Msweep\fP uses knowledge of
frame marker formats to skip over markers and to process the
intervening descriptors.
.PP
Although \*Msweep\fP is written in C,\^ the knowledge of frame formats that it
employs requires that it be written on a per-machine basis.
.SH
Generic Operation
.PP
There are three places that descriptors can appear on the stack:
above an expression marker,\^ in an argument list,\^ and above an
argument list.  This can be considered as only two places because
descriptors above the argument list can be considered as part of the
argument list.
.PP
\*Msweep\fP is called with a single argument that is the address of
the first word of a stack to mark.  For purposes of discussion assume
that \*Msp\fP references the stack word of current interest.
\*Msweep\fP has a loop and each time through the loop,\^ one of four actions
is taken based on the word that \*Msp\fP is pointing at:
.Ls
.Np
If \*Msp\fP is pointing at the low word of a procedure frame marker,\^ \*Msp\fP
is moved to point at the low word of the argument list of the
procedure.  \*Mefp\fP,\^ \*Mgfp\fP,\^ and \*Mpfp\fP are restored from the
procedure frame.  The number of arguments to the procedure is placed
in \fInargs\fP.
.Np
If \*Msp\fP is pointing at the low word of a generator frame marker,\^
\*Mfp\fP is restored from the boundary word of the generator frame
and \*Msp\fP is pointed at the low word of the frame referenced by \*Mfp\fP.
.Np
If \*Msp\fP is pointing at the low word of an expression frame
marker,\^ \*Mgfp\fP and \*Mefp\fP are restored from the marker and
\*Msp\fP is pointed at the word above the marker.
.Np
If none of the preceding conditions are true,\^ the word that \*Msp\fP
points at is assumed to be the low word of a descriptor and that
descriptor is marked.  \*Msp\fP is incremented by 2 to move past
the descriptor.  If \fInargs\fP is not zero,\^ it is decremented.
.Le
.PP
This process continues as long as \*Mfp\fP and \fInargs\fP are not
both zero.  \fInargs\fP is used so that the arguments in the very
last frame are processed.  The \*Mfp\fP at that point is 0.
.SH
\*Msweep\fP on the VAX
.PP
The routine \*Mgetap\fP is used by \*Msweep\fP.  \*Mgetap\fP
takes the address of a frame and returns the address of \*M0(ap)\fP
in that frame.  That is,\^ it returns the address of the start of the
argument list for the frame.
.PP
Note that the C code uses \*Mint *\fP variables for the various
calculations that are performed.  Thus,\^ a calculation such as
\*Mx + 2\fP is actually performing \*Mx + 8\fP.  Similarly,\^
\*Mx\^[\-1]\fP would be the address \*Mx \- 4\fP.
.PP
\*Msweep\fP is called with a single parameter,\^ \*Mfp\fP.  \*Mfp\fP
holds the address of the frame with which to start the marking process.  This
address is a \*M_boundary\fP value,\^ and thus it
points to the 0 (condition handler) word of a procedure frame.
.PP
\*Msp\fP is set to \*Mfp \- FRAMELIMIT\fP,\^ so that the first time
throughout the loop,\^ the procedure frame on the top of the stack
is processed.  This gets the ball rolling,\^ so to speak.
.PP
\*Msweep\fP loops while \*Mfp\fP and \fInargs\fP are not both zero.
It should be noted that the variables used in \*Msweep\fP have no
connection to actual registers other than having the same name.
.PP
If \*Msp\fP is equal to \*Mfp \- FRAMELIMIT\fP,\^ it indicates that \*Msp\fP
is pointing at a procedure frame marker.
\*MFRAMELIMIT\fP is 2 on the VAX because
there are two words,\^ the saved values of \*M_line\fP and \*M_file\fP,\^
that lie below the word in the frame that \*Mfp\fP points at.
.PP
When a procedure frame marker is encountered,\^ \*Mefp\fP and \*Mgfp\fP values
are restored using negative displacements from \*Map\fP.  \*Map\fP
points at the \fInwords\fP word of the frame,\^ and \*Msp\fP is set to
\*Map + 2\fP so that it points at the descriptor for the first
argument.  \fInargs\fP is loaded from the argument list.  \*Map\fP
and \*Mfp\fP are restored from the frame
.PP
A generator frame is indicated by \*Msp\fP being equal to \*Mgfp \-
3\fP.  This is because there are three words,\^ \*M_line\fP,\^
\*M_file\fP,\^ and \*M_k_level\fP in the generator frame below the
word that generator frame pointer points at.  \*Mfp\fP is restored
from the frame.  A new \*Map\fP value is calculated from \*Mfp\fP
using \*Mgetap\fP.  \*Msp\fP is set to \*Mfp \- FRAMELIMIT\fP to cause
recognition of a procedure frame the next time around.
.PP
An expression frame marker is indicated by \*Msp\fP being equal to \*Mefp \-
2\fP.  \*Mefp\fP and \*Mgfp\fP are restored from the marker.
\*Msp\fP is incremented by 3 which leaves it pointing at the word
above the marker,\^ which may be a descriptor.
.PP
If \*Msp\fP suits none of the preceding criteria,\^ it is assumed to
point at a descriptor.  \*Mmark\fP is called with the value of \*Msp\fP as
its argument.  \*Msp\fP is incremented by 2 to move past the
descriptor just marked.  If \fInargs\fP is non-zero,\^ it is
decremented.
.bp
.SH
Acknowledgements
.PP
Ralph Griswold patiently suffered through a number of drafts of this
document and made innumerable suggestions about grammar,\^ form,\^ and content.
Steve Wampler graciously answered a number of questions about the internal
workings of Icon and also made a number of comments on a late draft.
.SH
References
.LP
.IP 1.
R. E. Griswold,\^ R. K. McConeghy,\^ and W. H. Mitchell,\^ \fIA Tour Through the
C Implementation of Icon; Version 5.9\fR,\^
Technical Report 84-11, Department of Computer Science, The University of
Arizona, August 1984.
.IP 2.
\fIVAX Architecture Handbook\fP,\^ Digital Equipment Corporation,\^
Maynard,\^ Massachusetts,\^ 1982.
.IP 3.
D. M. Ritchie,\^ A Tour Through the UNIX C Compiler,\^ \fIUNIX Programmers
Manual,\^ Volume 2B\fP,\^ Bell Telephone Laboratories,\^ Inc.,\^ Murray Hill,\^
New Jersey,\^ 1979.
.IP 4.
S. C. Johnson,\^ A Tour Through the Portable C Compiler,\^ \fIUNIX Programmers
Manual,\^ Volume 2B\fP,\^ Bell Telephone Laboratories,\^ Inc.,\^ Murray Hill,\^
New Jersey,\^ 1979.
.IP 5.
R. E. Griswold,\^ \fIAn Overview of the Porting Process for Version 5.9
of Icon\fR,
Department of Computer Science,\^ The University of Arizona,\^ August 1984.