.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.