|
|
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.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.