Annotation of 43BSD/contrib/icon/docs/tr83-10c.roff, revision 1.1.1.1

1.1       root        1: .NH 3
                      2: \*Mrt/arith.s\fR
                      3: .SH
                      4: Overview
                      5: .PP
                      6: \*Marith.s\fP contains code for routines that add,\^ subtract,\^ and
                      7: multiply integers and check for overflow.  If overflow occurs,\^
                      8: run-time error 203 is produced.
                      9: .PP
                     10: The arguments to \*Mckadd\fP,\^ \*Mcksub\fP,\^ and \*Mckmul\fP are
                     11: two C \*Mlong\fP integers on which to operate.  For example,\^
                     12: if \*Mckadd\fP were written in C,\^ it would be declared
                     13: .Ds
                     14: long ckadd(a,\^b)
                     15: long a,\^b;
                     16: {
                     17: \&\*(El
                     18: }
                     19: .De
                     20: The routines return the result of the operation
                     21: using standard C return conventions.
                     22: .SH
                     23: \*Marith\fP on the VAX
                     24: .PP
                     25: The two arguments appear on the stack; \*Ma\fP is at \*M4(ap)\fP and
                     26: \*Mb\fP is at \*M8(ap)\fP.  The appropriate 3-operand VAX instruction
                     27: is used to perform the operation and the result is placed in \*Mr0\fP
                     28: in accordance with C return conventions.  If overflow occurs
                     29: during the operation,\^ the overflow bit in the program status word
                     30: is set.
                     31: .PP
                     32: After the operation is performed,\^ the overflow bit is
                     33: checked.  If it is on,\^ indicating that an overflow occurred,\^ a branch
                     34: is taken to \*Moflow\fP,\^ where \*Mrunerr(203,\^0)\fP is called.
                     35: If overflow did not occur,\^ the routine returns and the value in
                     36: \*Mr0\fP is the value returned to the calling expression.
                     37: .PP
                     38: \*Marith.s\fP is trivial on the VAX because the hardware supports
                     39: operations on C \*Mlong\fP integers.  This may not be the case on the
                     40: target machine.  If so,\^ \*Marith.s\fP will be considerably more
                     41: complicated.  However,\^ it usually is not difficult to locate routines
                     42: that perform these functions.  As a last resort,\^ look at the code the C
                     43: compiler generates for the various arithmetic operations on long
                     44: integers.
                     45: .NH 3
                     46: \*Mrt/fail.s\fR
                     47: .SH
                     48: Overview
                     49: .PP
                     50: \*Mfail\fP handles the failure of built-in procedures and operations.
                     51: Built-in procedures and operations are C routines and they signal
                     52: failure by calling \*Mfail()\fP.  When a failure of this type
                     53: occurs,\^ the failure must be transmitted to the Icon expression
                     54: whose evaluation is in progress and that requires the services of
                     55: a C routine.
                     56: .SH
                     57: Generic Operation
                     58: .PP
                     59: \*Mfail\fP itself does very little,\^ the real work is done by
                     60: \*Mefail\fP.  \*Mfail\fP pops the stack
                     61: back to where it was before the C routine was called and then
                     62: branches to \*Mefail\fP to make the enclosing expression fail.
                     63: .PP
                     64: \*Mfail\fP is akin to \*Mpfail\fP in that it pops the stack back
                     65: to a state that it was in when an expression was being evaluated
                     66: and then causes failure of the expression.  The primary difference
                     67: is that an Icon procedure frame is being removed in \*Mpfail\fP and
                     68: it contains extra information that must be restored.
                     69: .SH
                     70: \*Mfail\fP on the VAX
                     71: .PP
                     72: \*M_boundary\fP points to the procedure frame for the first C routine
                     73: that was called from Icon.  \*Mfp\fP is loaded from \*M_boundary\fP and
                     74: this puts the stack back to the state that it was in when the 
                     75: C routine was entered.  The C routine is for either a built-in procedure
                     76: such as \*Mread\fP or for an operator such as \*M+\fP.  For a
                     77: built-in procedure,\^ the procedure frame now on the top of the stack
                     78: (after loading \*Mfp\fP from \*M_boundary\fP) is the frame constructed
                     79: in \*Minvoke\fP.  For an operator,\^ the frame on the stack is the
                     80: one constructed when the interpreter loop called the C routine
                     81: for the operator.
                     82: .PP
                     83: The task at hand is to remove the procedure frame and restore the
                     84: registers that were saved in the frame.  The mask/psw word of the
                     85: frame is manipulated so that the mask portion of the word resides
                     86: in bits 0:11 of \*Mr0\fP and the remaining bits of \*Mr0\fP are 0.
                     87: The VAX \*Mpopr\fP instruction takes a register mask as an operand
                     88: and pops words from the stack into the registers indicated by
                     89: the mask.  For example,\^
                     90: .Ds
                     91: popr   $0x0005
                     92: .De
                     93: moves the top word of the stack into \*Mr0\fP and the second stack
                     94: word into \*Mr2\fP.  \*Msp\fP is then incremented by 8.
                     95: .PP
                     96: The saved registers start at \*M20(fp)\fP and \*Msp\fP is loaded
                     97: with this address.  Then \*Mpopr r0\fP restores the registers
                     98: that are saved in the frame.  Note that the manipulations of the
                     99: mask/psw are necessary because it is not known \fIa priori\fP which
                    100: registers were saved.  In particular,\^ \*Mpopr $0x0fff\fP would
                    101: be disastrous.
                    102: .PP
                    103: After the registers have been restored,\^ \*Map\fP and \*Mfp\fP are
                    104: restored from the saved \*Map\fP and \*Mfp\fP values in the
                    105: frame.
                    106: .PP
                    107: At this point,\^ the stack is as it was before the frame for
                    108: the built-in procedure or operator was created.  All that
                    109: remains is to signal failure in the expression being evaluated
                    110: and this is done by branching to \*Mefail\fP.
                    111: .ne 1i
                    112: .NH 3
                    113: \*Mlib/pret.s\fR
                    114: .SH
                    115: Overview
                    116: .PP
                    117: \*Mpret\fP handles the return of a value from an Icon procedure.
                    118: \*Mpret\fP is called from the interpreter loop with a single
                    119: argument (which is on the stack)
                    120: that is the value being returned.  The value is dereferenced
                    121: if necessary.  If tracing is on,\^ a trace message is produced.  The
                    122: return value is copied over \*(e0 in the frame of the procedure that
                    123: is returning a value.  The procedure frame is removed,\^ leaving
                    124: the result on the stack,\^ and \*Mpret\fP returns.
                    125: .SH
                    126: Generic Operation
                    127: .LP
                    128: .Ls
                    129: .Np
                    130: \*M&level\fP is decremented because a procedure is being exited.
                    131: .Np
                    132: The stack address where the return value is
                    133: to be placed is calculated.  Recall that when a procedure is invoked,\^ the
                    134: return value (if any) ultimately replaces \*(e0,\^ the descriptor
                    135: for the procedure returning the value.
                    136: .Np
                    137: The value being returned must be dereferenced if it is a local
                    138: variable or argument.  This is because local variables and arguments
                    139: are on the stack and the portion of the stack associated with
                    140: a procedure ``goes away'' when a procedure returns.  If the
                    141: return value is a variable (is of type \*MT_VAR\fP)
                    142: and its address
                    143: is between the base of the current expression stack*,\^
                    144: and the stack pointer,\^ it is dereferenced.
                    145: If it is a substring trapped variable (is of type \*MT_TVAR\fP
                    146: and points to a block of type \*MT_TVSUBS\fP),\^ and the address of the
                    147: variable containing the substring 
                    148: is between the base of the current expression stack
                    149: and the stack pointer,\^ it is dereferenced.
                    150: .FS
                    151: *For purposes of uniformity,\^ the system stack is treated
                    152: as if it were a co-expression stack.  The global variable
                    153: \*Mcurrent\fP is a pointer to the descriptor for the co-expression
                    154: stack block for the current co-expression.  Co-expressions
                    155: need not be implemented; it is only important that \*Mcurrent\fP
                    156: and the descriptor that it points to be initialized correctly.
                    157: This is done in \*Miconx/init.c\fP.
                    158: .FE
                    159: .Np
                    160: If \*M&trace\fP is non-zero,\^ \*Mrtrace\fP is called with the
                    161: address of the block for the returning procedure and the
                    162: address of the value being returned.
                    163: .Np
                    164: \*Mfp\fP,\^ \*M_line\fP,\^ and
                    165: \*M_file\fP are restored from the returning procedure.
                    166: Because the impending return restores control to the Icon
                    167: environment,\^ \*M_boundary\fP is cleared.
                    168: .Np
                    169: \*Mpret\fP returns from the Icon procedure by executing
                    170: a return instruction.  Because the current \*Mfp\fP points to the
                    171: procedure frame for the Icon procedure,\^ and the frame was
                    172: built by \*Minvoke\fP,\^ the return is effectively a return
                    173: from \*Minvoke\fP and the net result is the return value
                    174: left on the stack. 
                    175: .Le
                    176: .SH
                    177: \*Mpret\fP on the VAX
                    178: .PP
                    179: \*Mpret\fP does not save any registers because the frame built
                    180: upon entry to \*Mpret\fP is discarded.
                    181: .PP
                    182: \*M_boundary\fP is set because \*Mderef\fP may be called and \*Mderef\fP
                    183: can cause a garbage collection.
                    184: .PP
                    185: \*M_k_level\fP is decremented because a procedure is being exited.
                    186: .PP
                    187: \*Mpret\fP needs to know the address of the descriptor for the Icon
                    188: procedure that is returning.  Before \*Mpret\fP was called,\^ \*Mfp\fP
                    189: pointed at the procedure frame for the current Icon procedure (which
                    190: is now returning),\^ and \*Map\fP pointed at its argument list.  The
                    191: call to \*Mpret\fP created a procedure frame which contains the old
                    192: \*Map\fP.  This value is extracted and used in conjunction with
                    193: \fInargs\fP to calculate the address of the descriptor for the
                    194: procedure.  This value is stored in \*Mr11\fP for future use.
                    195: .PP
                    196: As described,\^ the value being returned needs to be dereferenced
                    197: in certain cases.  The return value is a descriptor and is the
                    198: argument to \*Mpret\fP.  The first word of this descriptor
                    199: lies at \*M8(ap)\fP and contains type and flag information.  This
                    200: word is placed in \*Mr1\fP for further examination.
                    201: .PP
                    202: The VAX \*Mbitl\fP instruction tests a set of bits.  The two
                    203: operand values are ANDed together and the condition codes
                    204: are set according to the value of the result.  The result itself
                    205: is discared.  The instruction
                    206: .Ds
                    207: bitl   $F_NQUAL,\^r1
                    208: .De
                    209: ANDs the type and flags word with the \*MF_NQUAL\fP mask.
                    210: The \*MF_NQUAL\fP bit is set if a descriptor is \fInot\fP a
                    211: string qualifier.
                    212: If the \*MF_NQUAL\fP bit is not on,\^ the result of the
                    213: AND is a 0.  The test is followed by
                    214: .Ds
                    215: beql   chktrace
                    216: .De
                    217: Thus,\^ if the return value \fIis\fP a string qualifier,\^ a branch
                    218: is taken to \*Mchktrace\fP,\^ and no dereferencing is performed.
                    219: .PP
                    220: If the return value does have the \*MF_NQUAL\fP attribute,\^ it
                    221: is checked to see if it is a variable. The \*MF_VAR\fP bit is tested.
                    222: If it is not on,\^ the return value is not a variable and does
                    223: not have to be dereferenced.  A branch is made to \*Mchktrace\fP if
                    224: this is the case.
                    225: .PP
                    226: If a variable is in hand,\^ the \*MF_TVAR\fP bit is checked to see
                    227: if it is a trapped variable.  If it is not a trapped variable,\^ the
                    228: address field of the return value's descriptor is moved into \*Mr1\fP for
                    229: further testing and a branch is taken to \*Mchkloc\fP.
                    230: .PP
                    231: If the return value is a substring trapped variable,\^ it may reference
                    232: a local variable or an argument.  The type bits of the descriptor
                    233: are isolated by ORing it with \*MTYPEMASK\fP.  If the type
                    234: is not \*MT_TVSUBS\fP,\^ no dereferencing is needed and a branch
                    235: is taken to \*Mchktrace\fP.  If it is a substring trapped variable,\^
                    236: the address of the variable containing the substring is obtained
                    237: from the trapped variable's data block and is loaded into \*Mr1\fP.
                    238: .PP
                    239: At this point (\*Mchkloc\fP),\^ \*Mr1\fP points to a descriptor
                    240: that is directly or indirectly referenced by the return value.
                    241: If the descriptor is in the current expression stack,\^ the return
                    242: value must be dereferenced.  \*Mr1\fP is first compared to
                    243: \*Msp\fP.  If it is less than \*Msp\fP,\^ the descriptor is below
                    244: the stack and a branch is made to \*Mchktrace\fP.  Otherwise,\^
                    245: \*Mr1\fP is compared to the base address of the current expression
                    246: stack.  If \*Mr1\fP is greater than the base of stack,\^ it is
                    247: above the stack and a branch is made to \*Mchktrace\fP.
                    248: .PP
                    249: It is now certain that the return value must be
                    250: dereferenced,\^ lest it ``disappear'' when the portion of the stack
                    251: it is in is re-used.  The address of the return value is pushed
                    252: on the stack and \*Mderef\fP is called.  Note that \*Mderef\fP completely
                    253: handles dereferencing of substring trapped variables and thus no
                    254: special provisions need to be made.
                    255: .PP
                    256: At \*Mchktrace\fP,\^ the return value has been dereferenced if
                    257: necessary and it is time to produce a tracing message if \*M&trace\fP
                    258: is non-zero.  \*Mrtrace\fP does the work and it
                    259: requires two arguments: the address of the block for the returning
                    260: procedure,\^ and the address of the return value.  Earlier,\^ the
                    261: address of descriptor for the procedure block was calculated and left
                    262: in \*Mr11\fP.  The second word of this descriptor is pushed on
                    263: the stack along with the address of the return value.
                    264: .PP
                    265: \*Mpret\fP ``returns'' the designated
                    266: value by overwriting the procedure's descriptor
                    267: with the descriptor of the return value.  \*Mr11\fP points at the
                    268: descriptor for the procedure and \*M8(ap)\fP still points at the
                    269: descriptor for the return value,\^ so
                    270: .Ds
                    271: movq   8(ap),\^(r11)
                    272: .De
                    273: does the trick.
                    274: .PP
                    275: Everything is set,\^ the actual return must be performed.  The \*Mfp\fP
                    276: saved in the current frame is the procedure frame pointer of the Icon
                    277: procedure and the saved value is loaded into \*Mfp\fP to bring
                    278: the Icon procedure frame to the top of the stack.  \*M_line\fP and
                    279: \*M_file\fP are restored from the Icon procedure frame.
                    280: \*M_boundary\fP is cleared because the return will take execution back
                    281: into an Icon realm.
                    282: .PP
                    283: A \*Mret\fP is executed.  The return goes through the procedure
                    284: frame built by \*Minvoke\fP.  Thus,\^ control is returned to the point
                    285: just after the call to \*Minvoke\fP and it appears as if \*Minvoke\fP
                    286: itself had just returned.
                    287: .NH 3
                    288: \*Mlib/esusp.s\fR
                    289: .SH
                    290: Overview
                    291: .LP
                    292: \*Mesusp\fP suspends a value from an expression.  \*Mesusp\fP is
                    293: called from the interpreter loop and the value to suspend appears
                    294: as an argument.  A generator frame hiding the current expression
                    295: is created.  The surrounding expression frame is duplicated.
                    296: \*Mesusp\fP leaves the value being suspended on the top of the stack.
                    297: .PP
                    298: The \*Mesusp\fP operation arises from the alternation
                    299: (\*M\*(x1\ |\ \^\*(x2\fR) control
                    300: structure.  For example
                    301: .Ds
                    302: p(5 | 10)
                    303: .De
                    304: indicates that the call \*Mp(5)\fP should be made and if it fails,\^ then
                    305: \*Mp(10)\fP should be called. 
                    306: .PP
                    307: The function of \*Mesusp\fP is best explained using an example.
                    308: The following ucode is generated for \*Mp(5 | 10)\fP
                    309: .Ds
                    310: .ta .8i +.8i +.8i +.8i
                    311:        mark    L1
                    312:        var     0       \fR(the variable \*Mp\fR)\*M
                    313:        mark    L2
                    314:        int     0       \fR(constant 5)\*M
                    315:        esusp
                    316:        goto    L3
                    317: lab L2
                    318:        int     1       \fR(constant 10)\*M
                    319: lab L3
                    320:        invoke  1
                    321:        unmark  1
                    322: lab L1
                    323: .De
                    324: When execution reaches \*Mesusp\fP,\^ the stack looks like
                    325: .Ds
                    326: .ft R
                    327: .ta 1i
                    328:        expression marker with \*ML1\fR as failure address
                    329:        descriptor for variable \*Mp\fR
                    330: \*Mefp\fR \*(ar        expression marker with \*ML2\fR as failure address
                    331: \*Msp\fR \*(ar descriptor for constant 5
                    332: .De
                    333: \*Mgfp\fP is zero at this point.
                    334: After the \*Mesusp\fP is performed,\^ the stack is
                    335: .Ds
                    336: .ft R
                    337: .ta 1i
                    338: \*Mefp\fR \*(ar        expression marker with \*ML1\fR as failure address
                    339:        descriptor for variable \*Mp\fR
                    340:        expression marker with \*ML2\fR as failure address
                    341:        descriptor for constant 5
                    342: \*Mgfp\fR \*(ar        generator frame built by \*Mesusp\fR
                    343: .ta 1i 3.3i
                    344:        descriptor for variable \*Mp\fR } duplicated region
                    345: \*Msp\fR \*(ar descriptor for constant 5
                    346: .De
                    347: A branch is taken to \*ML3\fP,\^ where \*Minvoke 1\fP is performed.
                    348: This invokes \*Mp\fP with one argument,\^ the constant 5 on the
                    349: stack.  If \*Mp(5)\fP succeeds,\^ the \*Munmark 1\fP is performed
                    350: and the stack is popped back through the \*ML1\fP expression frame,\^
                    351: the current location of \*Mefp\fP.
                    352: .PP
                    353: Suppose that instead of succeeding,\^ \*Mp(5)\fP fails.
                    354: \*Mp\fP fails by calling \*Mpfail\fP,\^ which removes the
                    355: procedure frame from the stack and then calls \*Mefail\fP.  The
                    356: previous stack picture shows what the stack looks like after the
                    357: procedure frame has been removed.  \*Mefail\fP finds that
                    358: \*Mgfp\fP is not null and restores certain values that are saved
                    359: in the generator frame.  The frame,\^ which was created by \*Mesusp\fP,\^
                    360: contains a return address that points to \*Mefail\fP.  Thus,\^ when
                    361: \*Mefail\fP removes the frame by returning through it,\^ control goes
                    362: back to the start of \*Mefail\fP and the stack is
                    363: .Ds
                    364: .ft R
                    365: .ta 1i
                    366:        expression marker with \*ML1\fR as failure address
                    367:        descriptor for variable \*Mp\fR
                    368: \*Mefp\fR \*(ar        expression marker with \*ML2\fR as failure address
                    369: \*Msp\fR \*(ar descriptor for constant 5
                    370: .De
                    371: This time around,\^ \*Mgfp\fP is zero,\^ so \*Mefail\fP must remove
                    372: the current expression frame and branch to the failure address in
                    373: the frame's marker.  When the expression frame is removed,\^ the
                    374: stack looks like
                    375: .Ds
                    376: .ft R
                    377: .ta 1i
                    378:        expression marker with \*ML1\fR as failure address
                    379: \*Msp\fR \*(ar descriptor for variable \*Mp\fR
                    380: .De
                    381: The failure address in the expression frame was \*ML2\fP,\^ so control
                    382: is transferred to \*Mlabel L2\fP in the ucode.  (Note how much went
                    383: on as the result of the \*Minvoke\fP being executed.)  The
                    384: instruction \*Mint 1\fP is executed and a descriptor for the constant
                    385: 10 is pushed on the stack giving:
                    386: .Ds
                    387: .ft R
                    388: .ta 1i
                    389:        expression marker with \*ML1\fR as failure address
                    390:        descriptor for variable \*Mp\fR
                    391: \*Msp\fR \*(ar descriptor for constant 10
                    392: .De
                    393: \*Minvoke 1\fP is performed again,\^ which does \*Mp(10)\fP.
                    394: .PP
                    395: If \*Mp(10)\fP succeeds,\^ the \*Munmark 1\fP is executed,\^ which
                    396: removes the \*ML1\fP marker and transfers control to \*ML1\fP.
                    397: If \*Mp(10)\fP fails,\^ the same thing happens,\^ but \*Mefail\fP
                    398: does the work rather than \*Munmark\fP.
                    399: .SH
                    400: Generic Operation
                    401: .LP
                    402: .Ls
                    403: .Np
                    404: The procedure frame created by the call to \*Mesusp\fP partially
                    405: forms the generator frame. The frame is completed by pushing
                    406: \*M_boundary\fP,\^ \*M_k_level\fP,\^ \*M_line\fP,\^ and \*M_file\fP.
                    407: The generator frame pointer is set to point at the word of the
                    408: frame which contains the boundary.
                    409: .Np
                    410: The bounds of the expression frame to be duplicated are determined.
                    411: The lower bound is the stack word above the current expression frame
                    412: marker.
                    413: The upper bound is dependent on \*Mefp\fP and \*Mgfp\fP
                    414: values saved in the current expression marker.  If the saved \*Mgfp\fP is
                    415: non-zero,\^ the upper bound is the first word below the generator
                    416: frame marker.  If the saved \*Mgfp\fP is zero,\^ the upper bound is
                    417: the first word below the expression frame marker referenced by the
                    418: saved \*Mefp\fP.  In the example,\^ this region only contains
                    419: the descriptor for the variable \*Mp\fP.
                    420: The region is copied to the top of the stack.  The stack pointer is
                    421: adjusted to point to the new top of stack.
                    422: .Np
                    423: The value being suspended is pushed on the stack.
                    424: .Np
                    425: The return address in the new generator frame is replaced by the address of
                    426: \*Mefail\fP so that when \*Mefail\fP removes the frame by returning through
                    427: it,\^ \*Mefail\fP regains control.  The old return address is
                    428: momentarily retained.  The procedure frame pointer and argument
                    429: pointer are restored.  \*M_boundary\fP is cleared because control is
                    430: returning to Icon code.
                    431: .Np
                    432: \*Mefp\fP in the current expression
                    433: marker replaces the expression frame pointer.  Thus,\^ if an \*Munmark\fP
                    434: is performed,\^ the entire expression frame is removed.  In the example,\^
                    435: this happens if \*Mp(5)\fP or \*Mp(10)\fP succeeds.
                    436: .Np
                    437: The return \*Mpc\fP value which was saved is jumped to.  This is in
                    438: effect a return from \*Mesusp\fP,\^ but the stack is untouched.
                    439: .Le
                    440: .SH
                    441: \*Mesusp\fP on the VAX
                    442: .PP
                    443: When \*Mesusp\fP is entered,\^ the generator frame is partially
                    444: constructed.  \*Mipc\fP,\^ \*Mgfp\fP,\^ and \*Mefp\fP are saved in
                    445: the frame.  \*M_boundary\fP is set to the current \*Mfp\fP value
                    446: and is pushed on the stack.  The generator frame pointer,\^ is pointed at
                    447: the word containing the boundary.
                    448: The frame is completed by pushing \*M_k_level\fP,\^ \*M_line\fP,\^
                    449: and \*M_file\fP on the stack.
                    450: .PP
                    451: The lower bound of the region to copy is the first word above the
                    452: current expression frame marker.  Recall that an expression frame
                    453: looks like
                    454: .Ds
                    455: .ft R
                    456: .St
                    457: \*Mefp\fR \*(ar        0       old expression frame pointer
                    458:        -4      old generator frame pointer
                    459:        -8      failure address
                    460: .De
                    461: Thus,\^
                    462: .Ds
                    463: addl3   $4,\^efp,\^r0
                    464: .De
                    465: points \*Mr0\fP at the lower end of the region to copy.
                    466: .PP
                    467: The upper bound of the region to copy is the low word of the marker
                    468: for the enclosing generator or expression frame.  If \*Mgfp\fP
                    469: is non-zero the generator frame marker is used.
                    470: Otherwise,\^ the expression frame marker is used.  Recall that a
                    471: generator frame looks like
                    472: .Ds
                    473: .ft R
                    474: .St
                    475:                saved registers
                    476:        20      reactivation address (saved \*Mpc\fR)
                    477:        16      saved \*Mfp\fR
                    478:        12      saved \*Map\fR
                    479:        8       \*Mpsw\fR and register mask
                    480:        4       0
                    481: \*Mgfp\fR \*(ar        0       boundary
                    482:        -4      saved \*M_k_level\fR
                    483:        -8      saved \*M_line\fR
                    484:        -12     saved \*M_file\fR
                    485: .De
                    486: So,\^ if the saved \*Mgfp\fP is non-zero,\^ the upper bound of the region
                    487: to copy is
                    488: .Ds
                    489: .ft R
                    490: saved \*Mgfp\fR - 12
                    491: .De
                    492: Otherwise,\^ it is
                    493: .Ds
                    494: .ft R
                    495: saved \*Mefp\fR - 8
                    496: .De
                    497: The appropriate calculation is performed and \*Mr2\fP pointed at the
                    498: bounding word.
                    499: .LP
                    500: At this point,\^ the stack looks something like
                    501: .Ds
                    502: .ft R
                    503: .St
                    504: \*Mr2\fR \*(ar         low word of expression or generator frame marker
                    505:                last word of region to copy
                    506:                \*(El
                    507: \*Mr0\fR \*(ar 4       first word of region to copy
                    508: \*Mefp\fR \*(ar        0       saved expression frame pointer
                    509:        -4      saved generator frame pointer   expression marker
                    510:        -8      failure label
                    511:        8       descriptor for value to suspend
                    512:        4       \*Mnargs\fR (1)
                    513: \*Map\fR \*(ar 0       \*Mnwords\fR (3)
                    514:        -4      saved \*Mr11\fR (\*Mefp\fR)
                    515:                saved \*Mr10\fR (\*Mgfp\fR)
                    516:        24      saved \*Mr9\fR (\*Mipc\fR)
                    517:        20      reactivation address (saved \*Mpc\fR)
                    518:        16      saved \*Mfp\fR
                    519:        12      saved \*Map\fR  generator marker
                    520:        8       \*Mpsw\fR and register mask
                    521:        4       0
                    522:        0       boundary (\*Mfp\fR at entry to \*Mesusp\fR)
                    523:        -4      \*M_k_level\fR
                    524:        -8      \*M_line\fR
                    525: \*Msp\fR \*(ar -12     \*M_file\fR
                    526: .De
                    527: .PP
                    528: The region starting at \*Mr0\fP and extending to \*Mr2\fP is to be
                    529: copied to the top of the stack.  The length of the region in bytes is
                    530: calculated in \*Mr2\fP.
                    531: The value of \*Mr2\fP is subtracted from \*Msp\fP,\^ moving \*Msp\fP
                    532: down to accommodate the region.  The region is then copied using
                    533: .Ds
                    534: movc3   r2,\^(r0),\^(sp)
                    535: .De
                    536: which moves \*Mr2\fP bytes starting at \*M0(r0)\fP to \*M0(sp)\fP.
                    537: .PP
                    538: The descriptor for the value to suspend is at \*M8(ap)\fP and it
                    539: is pushed on the stack using
                    540: .Ds
                    541: movq   8(ap),\^(sp)
                    542: .De
                    543: .LP
                    544: The stack now looks like
                    545: .Ds
                    546: .ft R
                    547: .ta 0.90i
                    548: \*Mr2\fR \*(ar low word of expression or generator frame marker
                    549:        last word of region to copy
                    550:        \*(El
                    551: \*Mr0\fR \*(ar first word of region to copy
                    552: \*Mefp\fR \*(ar        expression frame marker
                    553: \*M8(ap)\fR \*(ar      descriptor for value to suspend
                    554:        \*(El
                    555: \*Mgfp\fR \*(ar        generator frame marker
                    556:        last word of copied region
                    557:        \*(El
                    558:        first word of copied region
                    559: \*Msp\fR \*(ar descriptor for value to suspend
                    560: .De
                    561: .PP
                    562: The reactivation address that is saved in the generator frame is moved
                    563: into \*Mr1\fP for later use.  It is then replaced by the address
                    564: of \*Mefail\fP so that when the frame is returned through,\^ control
                    565: will go to \*Mefail\fP.
                    566: .PP
                    567: \*Mfp\fP and \*Map\fP are restored from the generator frame.  \*M_boundary\fP
                    568: is cleared because control is being returned to Icon code.
                    569: .PP
                    570: \*Mefp\fP is pointed at the previous expression frame.  That is,\^ \*Mefp\fP
                    571: is moved back one step in the expression frame chain.
                    572: .PP
                    573: Control is returned to the interpreter loop by branching to
                    574: \*M0(r1)\fP,\^ the reactivation address originally saved in the generator frame.
                    575: .NH 3
                    576: \*Mlib/lsusp.s\fR
                    577: .SH
                    578: Overview
                    579: .PP
                    580: \*Mlsusp\fP suspends a value from a limited expression.  A limited
                    581: expression arises from a source code expression of the form
                    582: .Ds
                    583: \*(x1\ \e\ \^\*(x2
                    584: .De
                    585: This limits \*(x1 to at most \*(x2 results.  (\*(x2
                    586: must be a non-negative integer.)
                    587: .PP
                    588: \*Mlsusp\fP is just like \*Mesusp\fP except that it has provisions for
                    589: checking and decrementing the limit counter and taking the appropriate
                    590: action when the counter reaches zero.  As a simple example,\^ consider
                    591: .Ds
                    592: p(x\ \e\ \^2)
                    593: .De
                    594: which generates the ucode
                    595: .Ds
                    596: .ta .8i +.8i +.8i
                    597:        mark    L1
                    598:        var     0       \fR(variable \*Mp\fR)\*M
                    599:        int     0       \fR(constant 2)\*M
                    600:        limit
                    601:        mark    L0
                    602:        var     1       \fR(variable \*Mx\fR)\*M
                    603:        lsusp
                    604:        invoke  1
                    605:        unmark  1
                    606:        \*(El
                    607: .De
                    608: When control reaches the \*Mlsusp\fP,\^ the stack looks like
                    609: .Ds
                    610: .ft R
                    611: .S1
                    612:        expression marker with \*ML1\fR as failure label
                    613:        descriptor for variable \*Mp\fR
                    614:        descriptor for integer with value of 2
                    615: \*Mefp\fR \*(ar        expression marker with \*ML0\fR as failure label
                    616: \*Msp\fR \*(ar descriptor for variable \*Mx\fR
                    617: .De
                    618: The \*Mlimit\fP instruction insures that the value on the top of
                    619: the stack (its argument) is a non-negative integer.  After \*Mlsusp\fP,\^ the
                    620: stack is
                    621: .Ds
                    622: .ft R
                    623: .ta 0.75i 3.3i
                    624: \*Mefp\fR \*(ar        expression marker with \*ML1\fR as failure label
                    625:        descriptor for variable \*Mp\fR
                    626:        descriptor for integer with value of 2
                    627:        expression marker with \*ML0\fR as failure label
                    628:        descriptor for variable \*Mx\fR
                    629: \*Mgfp\fR \*(ar        generator frame built by \*Mlsusp\fR
                    630:        descriptor for variable \*Mp\fR } duplicated region
                    631: \*Msp\fR \*(ar descriptor for variable \*Mx\fR
                    632: .De
                    633: This is the same thing that \*Mesusp\fP would do,\^ with the
                    634: exception that the limit counter,\^ the integer descriptor,\^ is not
                    635: part of the duplicated region.
                    636: .SH
                    637: Generic Operation
                    638: .LP
                    639: .Ls
                    640: .Np
                    641: The procedure frame created by the call to \*Mesusp\fP partially
                    642: forms the generator frame.
                    643: .Np
                    644: The limit counter is decremented and if it is zero,\^ no suspension
                    645: is performed.  Instead,\^ the current expression frame is removed
                    646: and the limit counter is replaced by the value that would have been
                    647: suspended had the limitation not been in effect.  \*Mlsusp\fP returns,\^
                    648: leaving the value on the top of the stack.
                    649: .Np
                    650: If the limit counter is not zero,\^ execution proceeds exactly
                    651: as it does for \*Mesusp\fP with the exception that the determination
                    652: of the region to copy takes the limit counter into consideration and
                    653: does not include it in the region that is copied.
                    654: .Le
                    655: .SH
                    656: \*Mlsusp\fP on the VAX
                    657: .PP
                    658: When \*Mlsusp\fP is entered,\^ the generator frame is partially
                    659: constructed.  \*Mipc\fP,\^ \*Mgfp\fP,\^ and \*Mefp\fP are saved in
                    660: the frame.
                    661: .PP
                    662: The expression frame and associated limit counter have the following
                    663: layout:
                    664: .Ds
                    665: .ft R
                    666: .St
                    667:        8       number of results left
                    668: \u                     limit counter\d
                    669: .sp -1
                    670:        4       \*MD_INTEGER\fR (type and flags word)
                    671: \*Mefp\fR \*(ar        0       old expression frame pointer
                    672:        -4      old generator frame pointer     expression frame
                    673:        -8      failure label
                    674: .De
                    675: .PP
                    676: The limit counter is decremented and if it is not zero,\^ control
                    677: passes to \*Mdosusp:\fP and from then on execution proceeds
                    678: exactly as it does in \*Mesusp\fP.  Specifically,\^ 
                    679: the code beginning at \*Mdosusp:\fP
                    680: is an exact duplicate of that in \*Mesusp\fP with the
                    681: exception of the instruction that determines the lower bound of
                    682: the region to be duplicated.  \*Mesusp\fP uses
                    683: .Ds
                    684: addl3 $4,\^efp,\^r0
                    685: .De
                    686: which points \*Mr0\fP at the word immediately above the expression
                    687: frame.  \*Mlsusp\fP uses
                    688: .Ds
                    689: addl3 $12,\^efp,\^r0
                    690: .De
                    691: which points \*Mr0\fP at the word above the limit counter that is
                    692: directly above the expression frame.
                    693: .PP
                    694: If the limit counter is zero,\^ the counter is to be replaced with the
                    695: value which was to be suspended.  The value appears as an argument to
                    696: \*Mlsusp\fP.  This is accomplished with
                    697: .Ds
                    698: movq   8(ap),\^4(efp)
                    699: .De
                    700: .PP
                    701: The value of \*Mgfp\fP that is stored in the
                    702: expression frame is restored.
                    703: .PP
                    704: The saved \*Mpc\fP in \*Mlsusp\fP's frame is moved into \*Mr0\fP for
                    705: later use.
                    706: .PP
                    707: The expression frame is removed by moving \*Mefp\fP into \*Msp\fP,\^
                    708: which leaves the expression frame marker word that contains the old
                    709: \*Mefp\fP on the top of the stack.  This word is popped of the stack
                    710: and moved into \*Mefp\fP,\^ restoring \*Mefp\fP and leaving the
                    711: return (would-be suspended) value on the top of the stack.
                    712: .PP
                    713: \*Map\fP and \*Mfp\fP are restored from the procedure frame made upon
                    714: entry to \*Mlsusp\fP.
                    715: .PP
                    716: \*Mlsusp\fP ``returns'' by jumping to \*M0(r0)\fP,\^ the return point
                    717: that was saved in the frame.  The value that was to be suspended,\^ but
                    718: was not because of the limitation,\^ is left on the top of the stack.
                    719: .NH 3
                    720: \*Mlib/psusp.s\fR
                    721: .SH
                    722: Overview
                    723: .PP
                    724: \*Mpsusp\fP suspends a result from an Icon procedure.  \*Mpsusp\fP is
                    725: called from the interpreter loop and the value to suspend appears
                    726: as an argument to \*Mpsusp\fP.  A generator frame is created and
                    727: the generator or expression frame immediately containing the frame
                    728: for the suspending procedure
                    729: is duplicated on top of the stack.  \*Mpsusp\fP returns through
                    730: the duplicated frame,\^ leaving the suspending value on top
                    731: of the stack.  A return from \*Mpsusp\fP is manifested as a return
                    732: from \*Minvoke\fP.
                    733: .PP
                    734: The \*Mpsusp\fP operation arises from the \*Msuspend \*(xx\fR statement.
                    735: .PP
                    736: \*Mpsusp\fP is conceptually similar to \*Mesusp\fP,\^ the difference
                    737: being that a procedure frame is part of the expression frame
                    738: being duplicated and that requires some extra work.
                    739: To get a feel for what \*Mpsusp\fP does,\^ consider a simple example:
                    740: .PP
                    741: .Ds
                    742: .ta .5i +.5i +.5i +.5i +.5i
                    743: procedure main()
                    744:        f(p(3))
                    745: end
                    746: 
                    747: procedure p(a)
                    748:        suspend a
                    749: end
                    750: .De
                    751: .LP
                    752: The generated ucode for \*Mmain\fP is
                    753: .Ds
                    754: .ta .8i +.8i +.8i +.8i +.8i
                    755:        \*(El
                    756:        mark    L1
                    757:        var     0       \fR(the variable \*Mf\fR)\*M
                    758:        var     1       \fR(the variable \*Mp\fR)\*M
                    759:        int     0       \fR(the constant 3)\*M
                    760:        invoke  1
                    761:        invoke  1
                    762:        \*(El
                    763: lab    L1
                    764: .De
                    765: and the generated code for \*Mp\fP is
                    766: .Ds
                    767:        mark    p.L1
                    768:        mark    L0
                    769:        var     0       \fR(the argument \*Ma\fR)\*M
                    770:        psusp
                    771:        \*(El
                    772: lab    p.L1
                    773: .De
                    774: .LP
                    775: When control reaches the \*Minvoke\fP instruction,\^ the stack resembles
                    776: .Ds
                    777: .ft R
                    778: .S1
                    779: \*Mefp\fR \*(ar        expression marker with \*ML1\fR as failure address
                    780:        descriptor for variable \*Mf\fR
                    781:        descriptor for variable \*Mp\fR
                    782: \*Msp\fR \*(ar descriptor for constant 3
                    783: .De
                    784: after \*Mp\fP has been invoked,\^ just before the \*Mpsusp\fP is
                    785: executed the stack is
                    786: .Ds
                    787: .ft R
                    788: .S1
                    789:        expression marker with \*ML1\fR as failure address
                    790:        descriptor for variable \*Mf\fR
                    791:        descriptor for variable \*Mp\fR
                    792:        descriptor for constant 3 (becomes argument \*Ma\fR)
                    793:        procedure frame for \*Mp\fR (created by \*Minvoke\fR)
                    794:        expression marker with \*Mp.L1\fR as failure address
                    795: \*Mefp\fR \*(ar        expression marker with \*ML0\fR as failure address
                    796: \*Msp\fR \*(ar descriptor for argument \*Ma\fR
                    797: .De
                    798: Just before control returns from \*Mpsusp\fP,\^ the stack is
                    799: .Ds
                    800: .ta 0.75i 3.25i
                    801: .ft R
                    802:        expression marker with \*ML1\fR as failure address
                    803:        descriptor for variable \*Mf\fR
                    804:        descriptor for variable \*Mp\fR
                    805:        descriptor for constant 3
                    806:        procedure frame for \*Mp\fR
                    807:        expression marker with \*Mp.L1\fR as failure address
                    808:        expression marker with \*ML0\fR as failure address
                    809:        descriptor for argument \*Ma\fR (being suspended)
                    810: \*Mgfp\fR \*(ar        generator frame built by \*Mpsusp\fR
                    811:        descriptor for variable \*Mf\fR
                    812:        descriptor for variable \*Mp\fR duplicated region
                    813:        descriptor for constant 3
                    814: \*Msp\fR \*(ar procedure frame for \*Mp\fR
                    815: .De
                    816: After \*Mpsusp\fP returns,\^ the situation is
                    817: .Ds
                    818: \*Mefp\fR \*(ar        expression marker with \*ML1\fR as failure address
                    819:        descriptor for variable \*Mf\fR
                    820:        descriptor for variable \*Mp\fR
                    821:        descriptor for constant 3
                    822:        procedure frame for \*Mp\fR
                    823:        expression marker with \*Mp.L1\fR as failure address
                    824:        expression marker with \*ML0\fR as failure address
                    825:        descriptor for argument \*Ma\fR
                    826: \*Mgfp\fR \*(ar        generator frame built by \*Mpsusp\fR
                    827:        descriptor for variable \*Mf\fR
                    828: \*Msp\fR \*(ar descriptor for constant 3 (the suspended value)
                    829: .De
                    830: .PP
                    831: The return from \*Mpsusp\fP goes to the second \*Minvoke\fP,\^ which
                    832: calls \*Mf\fP with one argument,\^ the constant 3 that was
                    833: suspended.  If \*Mf(3)\fP fails,\^ the procedure frame for
                    834: \*Mf\fP is removed.  \*Mefail\fP takes control and returns through
                    835: the generator frame built by \*Mpsusp\fP.  This leaves the
                    836: descriptor for \*Ma\fP on top of the stack.  Execution continues
                    837: by \*Mp\fP failing,\^ and then \*Mmain\fP failing.
                    838: .SH
                    839: Generic Operation
                    840: .LP
                    841: .Ls
                    842: .Np
                    843: The procedure frame created by the call to \*Mpsusp\fP partially forms
                    844: the generator frame.  \*M_boundary\fP is set as the current location
                    845: of \*Mfp\fP and it is added to the generator frame.
                    846: .Np
                    847: As in \*Mpret\fP,\^ the value being suspended must be dereferenced
                    848: in certain cases.  For example,\^ if the value is a local variable
                    849: or an argument,\^ it is dereferenced.  The same code that handles
                    850: dereferencing in \*Mpret\fP appears in \*Mpsusp\fP as well.
                    851: Note that while suspension leaves the local variables and arguments
                    852: of a procedure intact,\^ if the enclosing expression frame should
                    853: be removed by an \*Munmark\fP,\^ the procedure frame would be destroyed,\^
                    854: leaving undeferenced values pointing at meaningless data.
                    855: .Np
                    856: The generator frame is completed by pointing \*Mgfp\fP at the boundary
                    857: value already in the frame and by adding \*M_k_level\fP,\^ \*M_line\fP,\^
                    858: and \*M_file\fP.
                    859: .Np
                    860: The bounds of the expression frame to be duplicated are determined.
                    861: The lower bound is the low word of the procedure frame for the
                    862: suspending procedure and the upper bound is the marker for the
                    863: expression frame or generator frame which is just prior to the
                    864: procedure frame.  As in \*Mesusp\fP,\^ if \*Mgfp\fP is non-zero,\^
                    865: the marker it points to is used.  Otherwise,\^ the marker referenced
                    866: by \*Mefp\fP is used.  The \*Mgfp\fP and \*Mefp\fP values used
                    867: are those found in the procedure frame of the suspending procedure.
                    868: The region is copied to the top of the stack.
                    869: In the example,\^ the duplicated region contained the procedure
                    870: frame marker for \*Mp\fP,\^ and the descriptors for the constant 3,\^
                    871: and the variables \*Mp\fP and \*Mf\fP.
                    872: .Np
                    873: If \*M&trace\fP is non-zero,\^ \*Mstrace\fP is called to produce
                    874: a trace message noting that the procedure is suspending a value.
                    875: \*Mstrace\fP requires the address of the block for the suspending
                    876: procedure and the address of the descriptor for the value being
                    877: suspended.
                    878: .Np
                    879: \*M_line\fP and \*M_file\fP are restored from the frame of the
                    880: suspending procedure.  This is done because when \*Mpsusp\fP is
                    881: finished,\^ it is as if the Icon procedure had returned.  Thus,\^
                    882: the line number and file name need to be what they were before
                    883: the procedure was called.
                    884: .Np
                    885: The generator frame pointer saved in the duplicated procedure frame
                    886: on the top of the stack is replaced by the current value of
                    887: \*Mgfp\fP,\^ which points to the newly created generator frame.
                    888: When \*Mpsusp\fP returns through the frame on the top of the stack,\^
                    889: \*Mgfp\fP is restored from the value in the frame and \*Mgfp\fP
                    890: then references the new generator frame.
                    891: .Np
                    892: The descriptor for \*(a0 in the argument list of the Icon procedure
                    893: that is suspending is a descriptor for the procedure itself.  This
                    894: descriptor is replaced with the descriptor for the value being
                    895: suspended.  When \*Mpsusp\fP is done,\^ this descriptor is left on the
                    896: top of the stack.
                    897: .Np
                    898: \*M_boundary\fP is cleared because control is returning to Icon code.
                    899: .Np
                    900: \*Mpsusp\fP returns.  The return uses the duplicated procedure frame
                    901: on the top of the stack.  The result is that it appears as if the
                    902: \*Minvoke\fP that originally called the suspending procedure has
                    903: returned.
                    904: .Le
                    905: .SH
                    906: \*Mpsusp\fP on the VAX
                    907: .PP
                    908: When \*Mpsusp\fP is entered,\^ the generator frame is partially
                    909: constructed as a result of the call.  \*M_boundary\fP is set to the
                    910: current value of \*Mfp\fP and this value is pushed on the stack
                    911: as part of the generator frame.
                    912: .PP
                    913: The value being suspended needs to be dereferenced if it is a local
                    914: variable or an argument.  This operation is the same as is done in
                    915: \*Mpret\fP; consult the section on it for details of the actions
                    916: taken.
                    917: .PP
                    918: The generator frame is completed by pointing \*Mgfp\fP at the frame
                    919: word containing the boundary value and by adding \*M_k_level\fP,\^
                    920: \*M_line\fP,\^ and \*M_file\fP to the frame.
                    921: .PP
                    922: The region to be duplicated is determined.  The low word to be copied
                    923: is the low word of the procedure frame of the suspending procedure.
                    924: (The word that contains the 0.)  This is readily accessible as the
                    925: \*Mfp\fP saved the procedure frame of \*Mpsusp\fP and is placed in \*Mr7\fP.
                    926: .PP
                    927: The high word to be copied is dependent upon the expression and generator
                    928: environment of the suspending procedure.  If the \*Mgfp\fP
                    929: in the suspender's environment is not zero,\^ the word just below the
                    930: generator frame marker is the highest word to be copied.  If
                    931: \*Mgfp\fP is zero,\^ the word just below the expression marker pointed at
                    932: by \*Mefp\fP in the suspender's environment is the highest word to
                    933: be copied.
                    934: .PP
                    935: The fact that the saved \*Mefp\fP and \*Mgfp\fP
                    936: appear on the stack just below the \fInwords\fP word (referenced by
                    937: \*M0(ap)\fP) is used to retrieve and test them.  As in \*Mesusp\fP,\^
                    938: if the saved \*Mgfp\fP is non-zero,\^
                    939: .Ds
                    940: .ft R
                    941: saved \*Mgfp\fR - 12
                    942: .De
                    943: is used for the lower bound,\^ otherwise
                    944: .Ds
                    945: .ft R
                    946: saved \*Mefp\fR - 8
                    947: .De
                    948: is the lower bound.  \*Mr4\fP is pointed at the appropriate word on
                    949: the upper end.  As in \*Mesusp\fP,\^ \*Msp\fP is moved down to
                    950: accommodate the region to be duplicated and the region is copied to
                    951: the top of the stack using a \*Mmovc3\fP.
                    952: .PP
                    953: After \*M_k_level\fP is decremented,\^ \*M_k_trace\fP is checked to see
                    954: if a trace message should be produced.  If so,\^ \*Mstrace\fP is called with
                    955: pointers to the descriptors for the suspending procedure and the
                    956: value being suspended.  The address of the value being suspended is
                    957: \*M8(ap)\fP and the address of the descriptor for the procedure is
                    958: determined using the standard
                    959: .Ds
                    960: &\*(a0 = (nargs * 8) + 8 + ap
                    961: .De
                    962: calculation.
                    963: .PP
                    964: The values of \*M_line\fP and \*M_file\fP are restored from the
                    965: suspender's frame.
                    966: .PP
                    967: The saved \*Mgfp\fP in the duplicated procedure frame on the top of
                    968: the stack must be replaced by the current value of \*Mgfp\fP.  Finding the
                    969: location of the saved \*Mgfp\fP is a little tricky.  The distance
                    970: between \*Mfp\fP and \*Map\fP in the duplicated frame is calculated
                    971: by subtracting the value of \*Mfp\fP from the \*Map\fP value and putting
                    972: the result in \*Mr0\fP.  The value in \*Mr0\fP represents the distance
                    973: from the top of the stack to \*M0(ap)\fP.  Adding the
                    974: current \*Msp\fP (which points at the low word of the duplicated
                    975: procedure frame) to \*Mr0\fP points \*Mr0\fP at the \fInwords\fP word
                    976: of the new frame.  \*Map\fP normally points at the \fInwords\fP word,\^
                    977: so \*Mr0\fP serves as a pseudo-\*Map\fP.  It is known that the saved \*Mgfp\fP
                    978: is the second word below the \fInwords\fP word; thus the new \*Mgfp\fP
                    979: is stored in \*M\-8(r0)\fP,\^ replacing the old value.  Thus,\^ when \*Mpsusp\fP
                    980: returns through the duplicated frame,\^ the value just stored is
                    981: the restored value of \*Mgfp\fP.
                    982: .PP
                    983: The descriptor for the suspending procedure must be replaced by the
                    984: descriptor for the return value.  The previous calculation left
                    985: \*Mr0\fP pointing at \*M0(ap)\fP in the duplicated frame.  The
                    986: address of \*(a0 is calculated using
                    987: .Ds
                    988: &\*(a0 = (nwords * 4) + 4 + r0
                    989: .De
                    990: Note that \*M+ 4\fP accounts for the four bytes that the \fInwords\fP
                    991: word itself occupies.  The descriptor for the return value is put in
                    992: place using a \*Mmovq\fP.
                    993: .PP
                    994: \*Msp\fP is moved into \*Mfp\fP so that the pending return uses the
                    995: new frame on the top of the stack.
                    996: .PP
                    997: \*M_boundary\fP is cleared because control is going back into Icon
                    998: code.
                    999: .PP
                   1000: A \*Mret\fP is executed to return from \*Mpsusp\fP.  This return uses
                   1001: the duplicated procedure frame and thus the duplicated frame is
                   1002: removed.  The final result is that it looks like the original call to
                   1003: \*Minvoke\fP that started the Icon procedure has returned and
                   1004: the suspended value is left on the top of the stack.
                   1005: .ne 3v
                   1006: .NH 3
                   1007: \*Mrt/suspend.s\fR
                   1008: .SH
                   1009: Overview
                   1010: .PP
                   1011: \*Msuspend\fP suspends a value from a built-in procedure or operator.
                   1012: \*Msuspend\fP is similar to \*Mpsusp\fP and amounts to little
                   1013: more than a simplified version of it.  Recall that built-in
                   1014: procedures are C functions; thus,\^ \*Msuspend\fP is directly called
                   1015: from C.
                   1016: .PP
                   1017: A generator frame is created and the generator or expression frame
                   1018: immediately containing the frame for the suspending procedure
                   1019: is duplicated on the top of the stack.  \*Msuspend\fP returns through
                   1020: the duplicated frame,\^ leaving the value being suspended on the top
                   1021: of the stack.  When \*Msuspend\fP returns,\^ it appears as a return
                   1022: from the original call to the built-in procedure.
                   1023: .PP
                   1024: Note that \*Msuspend\fP handles the suspension of values from both
                   1025: built-in procedures such as \*Mupto\fP and from operators such as
                   1026: the element generation operator,\^ \*M!\fP.  For built-in procedures,\^
                   1027: the procedure frame is built by \*Minvoke\fP,\^ while for operators,\^
                   1028: the procedure frame is built directly by the call to the appropriate
                   1029: function from the interpreter loop.  
                   1030: The value being suspended by the C function is represented
                   1031: by the \*(a0 descriptor in the argument list.  When
                   1032: \*Msuspend\fP is called,\^ the value to suspend is in place in
                   1033: \*Marg0\fP.
                   1034: .SH
                   1035: Generic Operation
                   1036: .PP
                   1037: \*Msuspend\fP can be considered as a ``subset'' of \*Mpsusp\fP.  The
                   1038: descriptions of operations in this section and the next are excerpts
                   1039: from \*Mpsusp\fP.
                   1040: .LP
                   1041: The actions of \*Mpsusp\fP that are \fInot\fP taken by \*Msuspend\fP are:
                   1042: .Ls
                   1043: .Np
                   1044: The return value does not need to be dereferenced because the
                   1045: suspending function has already taken care of that.
                   1046: .Np
                   1047: No tracing message is produced because tracing is only done
                   1048: for Icon procedures.
                   1049: .Np
                   1050: The return value does not need to be moved into the duplicated
                   1051: procedure frame because it is already in place in the original procedure
                   1052: frame and when the frame is duplicated,\^ the return value is
                   1053: duplicated along with it.
                   1054: .Np
                   1055: \*M_k_level\fP is not decremented because \*M&level\fP keeps track of
                   1056: Icon procedure calls and \*Msuspend\fP is returning from a C routine.
                   1057: \*M_line\fP,\^ and \*M_file\fP are not restored because they are
                   1058: not part of the procedure frame of the built-in procedure.
                   1059: .Le
                   1060: .LP
                   1061: The operations that are performed by \*Msuspend\fP are:
                   1062: .Ls
                   1063: .Np
                   1064: The procedure frame created by the call to \*Msuspend\fP partially forms
                   1065: the generator frame.  \*M_boundary\fP is set as the current location
                   1066: of \*Mfp\fP and it is added to the generator frame.
                   1067: .Np
                   1068: The bounds of the expression frame to be duplicated are determined.
                   1069: The lower bound is the low word of the procedure frame for the
                   1070: suspending procedure and the upper bound is the marker for the
                   1071: expression frame or generator frame which is just prior to the
                   1072: procedure frame.  As in \*Mesusp\fP,\^ if \*Mgfp\fP is non-zero,\^
                   1073: the marker it points to is used.  Otherwise,\^ the marker referenced
                   1074: by \*Mefp\fP is used.  The \*Mgfp\fP and \*Mefp\fP values used
                   1075: are those found in the procedure frame of the suspending procedure.
                   1076: The region is copied to the top of the stack.
                   1077: .Np
                   1078: The generator frame pointer saved in the duplicated procedure frame
                   1079: on the top of the stack is replaced by the current value of
                   1080: \*Mgfp\fP,\^ which points to the newly created generator frame.
                   1081: When \*Msuspend\fP returns through the frame on the top of the stack,\^
                   1082: \*Mgfp\fP is restored from the value in the frame and \*Mgfp\fP
                   1083: then references the new generator frame.
                   1084: .Np
                   1085: \*M_boundary\fP is cleared because control is returning to Icon code.
                   1086: .Np
                   1087: \*Msuspend\fP returns.  The return uses the duplicated procedure frame
                   1088: on the top of the stack.  The result is that it appears as if the
                   1089: original call to the suspending procedure has returned.
                   1090: .Le
                   1091: .SH
                   1092: \*Msuspend\fP on the VAX
                   1093: .PP
                   1094: When \*Msuspend\fP is entered,\^ the generator frame is partially
                   1095: constructed as a result of the call.  \*M_boundary\fP is set to the
                   1096: current value of \*Mfp\fP and this value is pushed on the stack
                   1097: as part of the generator frame.
                   1098: The generator frame is completed by pointing \*Mgfp\fP at the frame
                   1099: word containing the boundary value and by adding \*M_k_level\fP,\^
                   1100: \*M_line\fP,\^ and \*M_file\fP to the frame.
                   1101: .PP
                   1102: The region to be duplicated is determined.  The low word to be copied
                   1103: is the low word of the procedure frame of the suspending function.
                   1104: (The word that contains the 0.)  This is readily accessible as the
                   1105: \*Mfp\fP saved in the procedure frame of \*Msuspend\fP and \*Mr7\fP is
                   1106: pointed at the word containing the saved \*Mfp\fP.
                   1107: .PP
                   1108: The high word to be copied is dependent upon the expression and generator
                   1109: environment of the suspending function.  If the \*Mgfp\fP
                   1110: in the suspender's environment is not zero,\^ the word just below the
                   1111: generator frame marker is the highest word to be copied.  If
                   1112: \*Mgfp\fP is zero,\^ the just word below the expression marker pointed at
                   1113: by \*Mefp\fP in the suspender's environment is the highest word to
                   1114: be copied.
                   1115: .PP
                   1116: The fact that the saved \*Mefp\fP and \*Mgfp\fP
                   1117: appear on the stack just below the \fInwords\fP word (referenced by
                   1118: \*M0(ap)\fP) is used to retrieve and test them.  As in \*Mesusp\fP,\^
                   1119: if the saved \*Mgfp\fP is non-zero,\^
                   1120: .Ds
                   1121: .ft R
                   1122: saved \*Mgfp\fR - 12
                   1123: .De
                   1124: is used for the lower bound,\^ otherwise
                   1125: .Ds
                   1126: .ft R
                   1127: saved \*Mefp\fR - 8
                   1128: .De
                   1129: is the lower bound.  \*Mr4\fP is pointed at the appropriate word on
                   1130: the upper end.  As in \*Mesusp\fP,\^ \*Msp\fP is moved down to
                   1131: accommodate the region to be duplicated and the region is copied to
                   1132: the top of the stack using a \*Mmovc3\fP.
                   1133: .PP
                   1134: The saved \*Mgfp\fP in the duplicated procedure frame on the top of
                   1135: the stack must be replaced by the current value of \*Mgfp\fP.  Finding the
                   1136: location of the saved \*Mgfp\fP is a little tricky.  The distance
                   1137: between \*Mfp\fP and \*Map\fP in the duplicated frame is calculated
                   1138: by subtracting the \*Mfp\fP value from the \*Map\fP value and putting
                   1139: the result in \*Mr0\fP.  The value in \*Mr0\fP represents the distance
                   1140: from the top of the stack to \*M0(ap)\fP.  Adding the
                   1141: current \*Msp\fP (which points at the low word of the duplicated
                   1142: procedure frame) to \*Mr0\fP points \*Mr0\fP at the \fInwords\fP word
                   1143: of the new frame.  \*Map\fP normally points at the \fInwords\fP word,\^
                   1144: so \*Mr0\fP serves as a pseudo-\*Map\fP.  It is known that the saved \*Mgfp\fP
                   1145: is the second word below the \fInwords\fP word and thus the new \*Mgfp\fP
                   1146: is stored in \*M\-8(r0)\fP,\^ replacing the old value.  Thus,\^ when \*Msuspend\fP
                   1147: returns through the duplicated frame,\^ the value just stored is
                   1148: the restored value of \*Mgfp\fP.
                   1149: .PP
                   1150: A \*Mret\fP is executed to return from \*Msuspend\fP.  This return uses
                   1151: the duplicated procedure frame and thus the duplicated frame is
                   1152: removed.  The final result is that it looks like the original call to
                   1153: function has returned and
                   1154: the suspended value is left on the top of the stack.
                   1155: .ne 2i
                   1156: .NH 3
                   1157: \*Mfunctions/display.c\fR
                   1158: .SH
                   1159: Overview
                   1160: .PP
                   1161: \*Mdisplay.c\fP implements the Icon function \*Mdisplay()\fP.
                   1162: \*Mdisplay\fP traces back through Icon procedure frames printing various
                   1163: sorts of information.  Therefore,\^ some of the code in \*Mdisplay\fP
                   1164: is machine dependent.
                   1165: .SH
                   1166: Generic Operation
                   1167: .PP
                   1168: \*Mdisplay\fP makes one calculation that is machine dependent.  The
                   1169: calculation is to take a frame whose address is contained in the
                   1170: variable \*Mfp\fP and calculate the address of the procedure
                   1171: descriptor in the frame that is pointed at by the \*Mfp\fP value
                   1172: saved in the frame that \*Mfp\fP references.
                   1173: .SH
                   1174: \*Mdisplay\fP on the VAX
                   1175: .PP
                   1176: \*Map\fP and \*Mfp\fP are restored from the frame referenced by
                   1177: \*Mfp\fP.  The number of arguments to the procedure is contained in
                   1178: \*Map\^[1]\fP.  This is loaded into the variable \*Mn\fP.  The address
                   1179: of the procedure descriptor (\*(a0) is calculated using:
                   1180: .Ds
                   1181: dp = ap + 2 + 2*n
                   1182: .De
                   1183: Note that this is the same computation that is made at several points
                   1184: in the assembly language routines.  As in \*Msweep\fP,\^ the calculations are
                   1185: being made using \*Mint *\fP variables and thus the constants
                   1186: represent word counts instead of byte counts as they do in the
                   1187: assembly language routines.
                   1188: 
                   1189: .NH 3
                   1190: \*Mrt/gcollect.s\fR
                   1191: .SH
                   1192: Overview
                   1193: .PP
                   1194: \*Mgcollect\fP is a simple routine that insures that garbage
                   1195: collections are done using the stack for the main co-expression.
                   1196: This done by saving certain values in the co-expression block of the
                   1197: current co-expression,\^ restoring values from the co-expression block
                   1198: for \*M&main\fP,\^ calling the garbage collector,\^ and then restoring
                   1199: the original values.
                   1200: \*Mgcollect\fP takes a single argument that is passed directly
                   1201: to \*Mcollect\fP.
                   1202: .PP
                   1203: If co-expressions are not implemented,\^ \*Mgcollect\fP need only
                   1204: consist of a call to \*Mcollect\fP,\^ being sure to pass its argument
                   1205: on through.
                   1206: .SH
                   1207: \*Mgcollect\fP on the VAX
                   1208: .PP
                   1209: \*Mr0\fP is pointed at the heap block for the current co-expression.
                   1210: \*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP are saved in the appropriate
                   1211: words of the block.
                   1212: .PP
                   1213: \*Mr0\fP is pointed at the heap block for \*M&main\fP,\^ the
                   1214: co-expression that is initially active.  \*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP
                   1215: are restored from values saved in the block.
                   1216: .PP
                   1217: The argument to \*Mgcollect\fP is pushed on the stack,\^ and
                   1218: \*Mcollect\fP is called with one argument.
                   1219: .PP
                   1220: \*Mr0\fP is pointed at the heap block for the current co-expression
                   1221: and the \*Msp\fP,\^ \*Map\fP,\^ and \*M_boundary\fP values saved at the
                   1222: start of the routine are restored.
                   1223: .PP
                   1224: \*Mgcollect\fP returns.
                   1225: .NH 3
                   1226: \*Mrt/sweep.c\fR
                   1227: .SH
                   1228: Overview
                   1229: .PP
                   1230: \*Msweep\fP is used during garbage collection to sweep a stack,\^
                   1231: marking all the descriptors in the stack.  \*Msweep\fP begins at
                   1232: the low word (the top) of a stack and moves up through the stack,\^
                   1233: looking for descriptors and marking them.
                   1234: A stack is composed of four kinds of
                   1235: objects: descriptors,\^ and markers for procedure,\^
                   1236: generator,\^ and expression frames.  \*Msweep\fP uses knowledge of
                   1237: frame marker formats to skip over markers and to process the
                   1238: intervening descriptors.
                   1239: .PP
                   1240: Although \*Msweep\fP is written in C,\^ the knowledge of frame formats that it
                   1241: employs requires that it be written on a per-machine basis.
                   1242: .SH
                   1243: Generic Operation
                   1244: .PP
                   1245: There are three places that descriptors can appear on the stack:
                   1246: above an expression marker,\^ in an argument list,\^ and above an
                   1247: argument list.  This can be considered as only two places because
                   1248: descriptors above the argument list can be considered as part of the
                   1249: argument list.
                   1250: .PP
                   1251: \*Msweep\fP is called with a single argument that is the address of
                   1252: the first word of a stack to mark.  For purposes of discussion assume
                   1253: that \*Msp\fP references the stack word of current interest.
                   1254: \*Msweep\fP has a loop and each time through the loop,\^ one of four actions
                   1255: is taken based on the word that \*Msp\fP is pointing at:
                   1256: .Ls
                   1257: .Np
                   1258: If \*Msp\fP is pointing at the low word of a procedure frame marker,\^ \*Msp\fP
                   1259: is moved to point at the low word of the argument list of the
                   1260: procedure.  \*Mefp\fP,\^ \*Mgfp\fP,\^ and \*Mpfp\fP are restored from the
                   1261: procedure frame.  The number of arguments to the procedure is placed
                   1262: in \fInargs\fP.
                   1263: .Np
                   1264: If \*Msp\fP is pointing at the low word of a generator frame marker,\^
                   1265: \*Mfp\fP is restored from the boundary word of the generator frame
                   1266: and \*Msp\fP is pointed at the low word of the frame referenced by \*Mfp\fP.
                   1267: .Np
                   1268: If \*Msp\fP is pointing at the low word of an expression frame
                   1269: marker,\^ \*Mgfp\fP and \*Mefp\fP are restored from the marker and
                   1270: \*Msp\fP is pointed at the word above the marker.
                   1271: .Np
                   1272: If none of the preceding conditions are true,\^ the word that \*Msp\fP
                   1273: points at is assumed to be the low word of a descriptor and that
                   1274: descriptor is marked.  \*Msp\fP is incremented by 2 to move past
                   1275: the descriptor.  If \fInargs\fP is not zero,\^ it is decremented.
                   1276: .Le
                   1277: .PP
                   1278: This process continues as long as \*Mfp\fP and \fInargs\fP are not
                   1279: both zero.  \fInargs\fP is used so that the arguments in the very
                   1280: last frame are processed.  The \*Mfp\fP at that point is 0.
                   1281: .SH
                   1282: \*Msweep\fP on the VAX
                   1283: .PP
                   1284: The routine \*Mgetap\fP is used by \*Msweep\fP.  \*Mgetap\fP
                   1285: takes the address of a frame and returns the address of \*M0(ap)\fP
                   1286: in that frame.  That is,\^ it returns the address of the start of the
                   1287: argument list for the frame.
                   1288: .PP
                   1289: Note that the C code uses \*Mint *\fP variables for the various
                   1290: calculations that are performed.  Thus,\^ a calculation such as
                   1291: \*Mx + 2\fP is actually performing \*Mx + 8\fP.  Similarly,\^
                   1292: \*Mx\^[\-1]\fP would be the address \*Mx \- 4\fP.
                   1293: .PP
                   1294: \*Msweep\fP is called with a single parameter,\^ \*Mfp\fP.  \*Mfp\fP
                   1295: holds the address of the frame with which to start the marking process.  This
                   1296: address is a \*M_boundary\fP value,\^ and thus it
                   1297: points to the 0 (condition handler) word of a procedure frame.
                   1298: .PP
                   1299: \*Msp\fP is set to \*Mfp \- FRAMELIMIT\fP,\^ so that the first time
                   1300: throughout the loop,\^ the procedure frame on the top of the stack
                   1301: is processed.  This gets the ball rolling,\^ so to speak.
                   1302: .PP
                   1303: \*Msweep\fP loops while \*Mfp\fP and \fInargs\fP are not both zero.
                   1304: It should be noted that the variables used in \*Msweep\fP have no
                   1305: connection to actual registers other than having the same name.
                   1306: .PP
                   1307: If \*Msp\fP is equal to \*Mfp \- FRAMELIMIT\fP,\^ it indicates that \*Msp\fP
                   1308: is pointing at a procedure frame marker.
                   1309: \*MFRAMELIMIT\fP is 2 on the VAX because
                   1310: there are two words,\^ the saved values of \*M_line\fP and \*M_file\fP,\^
                   1311: that lie below the word in the frame that \*Mfp\fP points at.
                   1312: .PP
                   1313: When a procedure frame marker is encountered,\^ \*Mefp\fP and \*Mgfp\fP values
                   1314: are restored using negative displacements from \*Map\fP.  \*Map\fP
                   1315: points at the \fInwords\fP word of the frame,\^ and \*Msp\fP is set to
                   1316: \*Map + 2\fP so that it points at the descriptor for the first
                   1317: argument.  \fInargs\fP is loaded from the argument list.  \*Map\fP
                   1318: and \*Mfp\fP are restored from the frame
                   1319: .PP
                   1320: A generator frame is indicated by \*Msp\fP being equal to \*Mgfp \-
                   1321: 3\fP.  This is because there are three words,\^ \*M_line\fP,\^
                   1322: \*M_file\fP,\^ and \*M_k_level\fP in the generator frame below the
                   1323: word that generator frame pointer points at.  \*Mfp\fP is restored
                   1324: from the frame.  A new \*Map\fP value is calculated from \*Mfp\fP
                   1325: using \*Mgetap\fP.  \*Msp\fP is set to \*Mfp \- FRAMELIMIT\fP to cause
                   1326: recognition of a procedure frame the next time around.
                   1327: .PP
                   1328: An expression frame marker is indicated by \*Msp\fP being equal to \*Mefp \-
                   1329: 2\fP.  \*Mefp\fP and \*Mgfp\fP are restored from the marker.
                   1330: \*Msp\fP is incremented by 3 which leaves it pointing at the word
                   1331: above the marker,\^ which may be a descriptor.
                   1332: .PP
                   1333: If \*Msp\fP suits none of the preceding criteria,\^ it is assumed to
                   1334: point at a descriptor.  \*Mmark\fP is called with the value of \*Msp\fP as
                   1335: its argument.  \*Msp\fP is incremented by 2 to move past the
                   1336: descriptor just marked.  If \fInargs\fP is non-zero,\^ it is
                   1337: decremented.
                   1338: .bp
                   1339: .SH
                   1340: Acknowledgements
                   1341: .PP
                   1342: Ralph Griswold patiently suffered through a number of drafts of this
                   1343: document and made innumerable suggestions about grammar,\^ form,\^ and content.
                   1344: Steve Wampler graciously answered a number of questions about the internal
                   1345: workings of Icon and also made a number of comments on a late draft.
                   1346: .SH
                   1347: References
                   1348: .LP
                   1349: .IP 1.
                   1350: R. E. Griswold,\^ R. K. McConeghy,\^ and W. H. Mitchell,\^ \fIA Tour Through the
                   1351: C Implementation of Icon; Version 5.9\fR,\^
                   1352: Technical Report 84-11, Department of Computer Science, The University of
                   1353: Arizona, August 1984.
                   1354: .IP 2.
                   1355: \fIVAX Architecture Handbook\fP,\^ Digital Equipment Corporation,\^
                   1356: Maynard,\^ Massachusetts,\^ 1982.
                   1357: .IP 3.
                   1358: D. M. Ritchie,\^ A Tour Through the UNIX C Compiler,\^ \fIUNIX Programmers
                   1359: Manual,\^ Volume 2B\fP,\^ Bell Telephone Laboratories,\^ Inc.,\^ Murray Hill,\^
                   1360: New Jersey,\^ 1979.
                   1361: .IP 4.
                   1362: S. C. Johnson,\^ A Tour Through the Portable C Compiler,\^ \fIUNIX Programmers
                   1363: Manual,\^ Volume 2B\fP,\^ Bell Telephone Laboratories,\^ Inc.,\^ Murray Hill,\^
                   1364: New Jersey,\^ 1979.
                   1365: .IP 5.
                   1366: R. E. Griswold,\^ \fIAn Overview of the Porting Process for Version 5.9
                   1367: of Icon\fR,
                   1368: Department of Computer Science,\^ The University of Arizona,\^ August 1984.

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.