|
|
1.1 root 1: .de Ip
2: .IP \\$1
3: .br
4: ..
5: .nr $1 3
6: .nr $2 7
7: .nr $3 0
8: .NH 3
9: \*Miconx/start.s\fR
10: .SH
11: Overview
12: .PP
13: The routine \*Mmstart\fP in \*Mstart.s\fP is used to get Icon started.
14: When the Icon interpreter is executed,\^ the C routine \*Mmain\fP passes
15: control to \*Mmstart\fP,\^ and merely serves as a front-end for \*Mmstart\fP.
16: .SH
17: Generic Operation
18: .Ls
19: .Np
20: Call the routine \*Minit\fR with the name of the
21: file to interpret as its argument.
22: .Np
23: Make an Icon list out of the command line arguments using
24: the \*Mllist\fR function.
25: .Np
26: Invoke the main procedure of the Icon program.
27: .Le
28: .SH
29: \*Mstart\fP on the VAX
30: .PP
31: There is a short main program in \*Miconx/main.c\fP that calls \*Mmstart\fP
32: with two arguments:
33: .Ds
34: .S1
35: main(argc, argv)
36: int argc;
37: char **argv;
38: {
39: mstart(argc, argv);
40: }
41: .De
42: .PP
43: The number of command line arguments is in \*Margc\fP, and \*Margv\fP is a
44: pointer to an array of pointers to strings representing the arguments.
45: \*Margv\^[0]\fP is the command used to invoke the interpreter and \*Margv\^[1]\fP
46: is the name of the file being interpreted. Additional command line arguments
47: are passed along to the main procedure of the Icon program. When
48: \*Mmstart\fP gets control, \*M4(ap)\fP is the \*Margc\fP value and
49: \*M8(ap)\fP is the argv value.
50: .PP
51: The first action taken by \*Mmstart\fP is to call \*Minit\fR to initialize the
52: Icon run-time system. \*Minit\fR loads the header and code portions of
53: the interpretable file into memory,\^ so \*Minit\fR needs the
54: name of the interpretable file. The word at \*M8(ap)\fP is loaded into
55: \*Mr9\fP, pointing it at \*Margv\^[0]\fP. Then the name of the file to interpret
56: (\*Margv\^[1]\fP), residing at \*M4(r9)\fP, is pushed on the stack as the
57: argument for \*Minit\fP, which is then called.
58: .PP
59: In order to provide conformity with the usual execution environment
60: of Icon procedures,\^ an expression frame is created for the execution
61: of the main procedure. Both the old expression frame pointer and the
62: old generator frame pointer are set to be 0 in the expression frame
63: for \*Mmain\fP. The failure label must point to an interpreter opcode that
64: will terminate execution of the program. The opcode 0 is used
65: for this purpose. A word of storage,\^ \*Mflab\fR,\^ is declared and
66: initialized to 0. The failure label points to \*Mflab\fR. Thus,\^ if
67: \*Mmain\fP fails,\^ the interpreter executes the \*Mquit\fR opcode.
68: .PP
69: The next task is to push the descriptor for the procedure main
70: on the stack for later use by \*Minvoke\fR. The variable
71: \*M_globals\fR contains the address of the list of global variable
72: descriptors.
73: The first global variable descriptor is always the one for the
74: procedure main; if no main procedure was found when the program
75: was linked,\^ the descriptor
76: will be \*M&null\fR. The value of \*M_globals\fR is loaded into
77: \*Mr0\fR and the word then referenced by \*Mr0\fR is checked to see if it
78: is equal to \*MD_PROC\fR. (The first word of a descriptor for a procedure
79: is always equal to \*MD_PROC\fR.)
80: .\"\^[? not sure if we really need to check for D_PROC,\^
81: .\"I think just checking for ~= 0 will suffice.]
82: If the word is not equal
83: to \*MD_PROC\fR,\^ a branch is made to \*Mnomain\fR which generates
84: the appropriate run-time error. Otherwise,\^ the descriptor
85: for \*Mmain\fP is pushed onto the stack. (The effect of the instruction
86: \*Mmovq\ (r0),\^\-(sp)\fR
87: is to move 8 bytes (the size of a quadword)
88: starting at the address referenced by \*Mr0\fR to the
89: 8 bytes referenced by the \*Msp\fR after subtracting 8 from the
90: \*Msp\fR.)
91: .PP
92: The main procedure is to be invoked with a list consisting of the command
93: line arguments (if any). The Icon run-time routine \*Mllist\fR is used to
94: make the list that is passed to the main procedure. \*Mllist\fR stores
95: the descriptor for the list that it creates in the descriptor above its
96: first argument descriptor,\^ so to accommodate the result,\^ a null descriptor
97: is pushed on the stack using the \*Mclrq\fR instruction. Note that
98: because \*Mllist\fP calls \*Msetbound\fP and \*Mclrbound\fP,\^ it is not
99: possible to execute all of \*Mstart\fP until \*Mrt/setbound.s\fP has been
100: completed.
101: .PP
102: At the beginning of this routine,\^ \*Mr9\fR was set to point
103: at the first word of the argument list.
104: Neither the name of the Icon interpreter nor the name of the interpretable
105: file is desired in the argument list passed to main,\^ so \*Mr9\fR is
106: twice incremented by 4 (the size in bytes of a word)
107: to point it at the first actual program argument.
108: .PP
109: The next step is to construct the argument list for \*Mllist\fR. For
110: each command line argument,\^ the address of the string and then its
111: length are pushed on the stack. The length and address pairs form
112: descriptors that \*Mllist\fP makes an Icon list from.
113: \*Mr8\fR is used to count the arguments.
114: After the addresses and lengths of each argument have been pushed,\^ the
115: number of arguments is pushed on the stack.
116: At this point,\^ the stack looks like this:
117: .Ds
118: .ft R
119: .S1
120: descriptor for main procedure (2 4-byte words)
121: a null descriptor (2 words containing 0)
122: address of first argument to Icon program
123: length of first argument
124: \*(El
125: address of last argument to Icon program
126: length of last argument
127: \*Msp\fR \*(ar number of arguments
128: .De
129: .LP
130: All addresses and lengths are one word in size. The \*Mcalls\fR
131: instruction needs to be told how many words are in its argument list.
132: (This is necessary because when a return is made from the subroutine,\^
133: the specified number of words are removed from the stack.) There
134: are two words for each argument and an additional word for the number
135: of arguments. (Do not confuse the argument count for the \*Mllist\fR
136: subroutine and the argument list size.)
137: \*Mr8*2+1\fP is calculated in \*Mr8\fP. This value is used
138: as the argument list length for the \*Mcalls\fR instruction.
139: When \*Mllist\fR returns,\^ the arguments are stripped from the
140: stack and the stack looks like this:
141: .Ds
142: .ft R
143: .S1
144: descriptor for main procedure
145: \*Msp\fR \*(ar descriptor for list of command line arguments
146: .De
147: .LP
148: Note that the null descriptor pushed earlier received the result of
149: the \*Mllist\fR function.
150: .PP
151: At this point,\^ the main procedure is ready to be invoked. The descriptor for
152: the main procedure is \*(a0 and the descriptor for the list of
153: command line arguments is \*(a1. Before invoking the main procedure,\^
154: the procedure frame pointer and the generator frame pointer are cleared.
155: The main procedure is being invoked with one argument,\^ so a constant
156: 1 is pushed on the stack. The \*Mcalls\fR instruction is given an
157: argument of 3 because a word is used for the number of arguments and
158: two additional words are used for the descriptor for the list of command
159: line arguments.
160: .PP
161: If the main procedure fails,\^ the interpreter will encounter the
162: 0 opcode discussed earlier. If the main procedure returns (this
163: usually isn't done),\^ the return will manifest itself as \f3invoke\fR
164: returning. If this happens,\^ \*M_c_exit\fR is called with an
165: argument of 0. Incidentally,\^ this also happens when the interpreter
166: hits the 0 opcode.
167: .PP
168: There is a block of code labeled \*Mnomain\fR that is executed when
169: no main procedure is found. This calls the routine \*Mrunerr\fR to
170: produce an error message. The actual call made is \*Mrunerr(117,\^0)\fR.
171: The number 117 is looked up in a table of run-time errors. If the second
172: argument to \*Mrunerr\fR is non-zero,\^ it is interpreted as being the
173: address of a descriptor and the descriptor is examined to produce
174: an ``offending value'' to accompany the run-time error.
175: .PP
176: The last portion of executable code in \f3start.s\fR is the subroutine
177: \*M_c_exit\fR. If the variable \*M_monres\fR is non-zero,\^ it indicates
178: that profiling is on,\^ and it must be turned off. This is accomplished
179: by calling \*M_monitor(0)\fR. The routine \*M__cleanup\fR is then
180: called to shut down the i/o system. Finally,\^ \*M_exit\fR is called
181: with the argument of \*M_c_exit\fR to terminate execution of the
182: Icon interpreter.
183: .PP
184: There are several data declarations in \*Mstart.s\fR. The first data
185: declaration is a \*M.space 60\fR. This is an accommodation for the
186: garbage collector. It
187: insures that enough of the start of the data section
188: is used up to force the addresses of other data objects to be
189: greater than the defined constant \*MMAXTYPE\fR in \f3h/rt.h\fR.
190: .PP
191: Some assorted declarations are next. \*Mflab\fR is referenced
192: by the interpreter if the main procedure fails. It must be at
193: least a byte long and contain a 0. \*M_boundary\fR must be a
194: word long and contain a 0. \*M_environ\fR must be a word long;
195: its contents are unimportant as it is written into at the beginning
196: of \*Mstart.s\fR.
197: .PP
198: The \*M_tended\fR array is also used in conjunction with garbage
199: collection. It must declare space for five descriptors (two words
200: per descriptor) that are initialized to 0.
201: .\"\^[?]
202: The label \*M_etended\fR
203: is used to mark the end of the \*M_tended\fR array.
204: .ne 1i
205: .NH 3
206: \*Mrt/setbound.s\fR
207: .SH
208: Overview
209: .PP
210: \*Msetbound.s\fP contains code for \*Msetbound\fP and \*Mclrbound\fP.
211: \*Msetbound\fP sets \*M_boundary\fP under appropriate conditions and
212: \*Mclrbound\fP clears \*M_boundary\fP under appropriate conditions.
213: .SH
214: Generic Operation
215: .PP
216: When a call is made from Icon into C,\^ \*M_boundary\fP must be set to point
217: at the procedure frame on the top of the stack. C routines that can
218: be called from Icon have a call to \*Msetbound\fP as their first
219: operation. If \*Msetbound\fP is called and \*M_boundary\fP is not
220: set,\^ that is,\^ \*M_boundary\fP has a value of zero,\^ \*Mboundary\fP is
221: set to value of the \*Mfp\fP of the calling procedure.
222: .PP
223: When a C routine returns to Icon,\^ \*M_boundary\fP must be cleared.
224: If \*M_boundary\fP has the same value as \*Mfp\fP,\^ the routine was
225: called from Icon and thus when it returns,\^ it returns to Icon.
226: At appropriate return points in routines,\^ a call to \*Mclrbound\fP is
227: made. If the return takes control back to Icon,\^ \*M_boundary\fP
228: is cleared.
229: .SH
230: \*Msetbound\fP on the VAX
231: .PP
232: The value of \*M_boundary\fP is tested. If \*Mboundary\fP is not set,\^
233: that is,\^ if it has a value of zero,\^ it is set to the value of the
234: \*Mfp\fP in the calling procedure. Because the call to
235: \*Msetbound\fP creates a procedure frame,\^ the \*Mfp\fP value saved in
236: the frame is used. If \*M_boundary\fP is already set,\^ it is not
237: changed.
238: .SH
239: \*Mclrbound\fP on the VAX
240: .PP
241: The value of \*M_boundary\fP is compared to the \*Mfp\fP in the
242: calling procedure. If the values are the same,\^ the calling procedure
243: was called from Icon and when it returns it returns to Icon.
244: If this is the case,\^ \*M_boundary\fP is cleared.
245: .SH
246: An Alternative Approach
247: .PP
248: If the C system on the target machine uses calls at the beginning and
249: end of C routines to save and restore registers,\^ it is possible to
250: modify these routines to set and clear the boundary. This approach is
251: used on the PDP-11.
252: .PP
253: The file \*Mrt/csv.s\fP contains replacement
254: routines for \*Mcsv\fP and \*Mcret\fP. When \*Mcsv\fP is called to
255: save registers,\^ if \*M_boundary\fP is 0,\^ \*Msp\fP is saved in
256: \*M_boundary\fP. This insures that the first call from Icon into C
257: leaves \*M_boundary\fP at the top of the stack at that point.
258: When \*Mcret\fP is called to restore registers,\^ if the procedure
259: frame pointer is equal to \*M_boundary\fP,\^ the return is taking
260: control back to Icon code and \*M_boundary\fP is cleared.
261: .PP
262: Note the resemblance between calling \*Msetbound\fP at the start of a
263: C routine and having \*Mcsv\fP set \*M_boundary\fP whenever a C routine
264: is entered. Similarly,\^ there is a resemblance between calling
265: \*Mclrbound\fP at appropriate points and having \*Mcret\fP clear
266: \*M_boundary\fP when necessary.
267: .PP
268: The initial implementation of Icon was on the PDP-11 and the modified
269: \*Mcsv\fP and \*Mcret\fP approach was used. When the system was
270: ported to the VAX,\^ the subsumption of \*Mcsv\fP and \*Mcret\fP by the
271: hardware required that a software approach be taken. The trade-offs
272: are marginal if the target machine uses save and restore routines.
273: Having a distinct \*Msetbound\fP and \*Mclrbound\fP may be easier to
274: implement,\^ but using modified save and restore routines is
275: definitely faster.
276: .PP
277: If this approach is used,\^ then \*MSetBound\fP and \*MClearBound\fP in
278: \*Mrt.h\fP should be defined,\^ but given no value.
279: .NH 3
280: \*Mlib/invoke.s\fR
281: .SH
282: Overview
283: .LP
284: \*Minvoke.s\fP handles four specific tasks. These are
285: .Ds
286: .ft R
287: call a built-in function
288: call an Icon procedure
289: create a record
290: perform mutual evaluation
291: .De
292: .LP
293: Note that all of these operations rise from a source code
294: expression of the form
295: .Ds
296: \*(e0(\*(e1,\^\*(El,\^\*(en)
297: .De
298: where each \*(ai is an expression of some type.
299: Icon has strict left-to-right evaluation and thus,\^ for the preceding
300: expression,\^ \*(e0 is evaluated first,\^ then \*(e1,\^ and so forth
301: through \*(en. As each expression is evaluated,\^ its result
302: is pushed on the stack. After the expressions have been evaluated
303: (and assuming none failed),\^ the stack looks something like
304: .Ds
305: .ft R
306: .S1
307: value from \*(e0
308: value from \*(e1
309: \*(El
310: value from \*(ei
311: \*(El
312: \*Msp\fR \*(ar value from \*(en
313: .De
314: Then,\^ \*(e0 is \fIinvoked\fP.
315: .PP
316: Recall that stacks are represented as growing downward. Thus,\^
317: \*(en is on the ``top'' of the stack. Also note that each
318: ``value'' on the stack is actually a two-word descriptor.
319: .\"The various \*(ei may be referred to as \fIarguments\fP.
320: .SH
321: Generic Operation
322: .PP
323: \*Minvoke\fP is an interpreter opcode that takes a single operand
324: specifying how many \*(ei are present (\*(e0 is not counted).
325: \*Minvoke\fP is also called from \*Mstart.s\fP to invoke the \*Mmain\fP
326: procedure.
327: .Ls
328: .Np
329: \*Minvoke\fP must determine whether it is to call a built-in function,\^
330: call an Icon procedure,\^ create a record,\^ or perform mutual evaluation. If
331: \*(e0 is not something that can be invoked,\^
332: \*Minvoke\fP notes this as a run-time error.
333: .Np
334: If mutual evaluation is to be done,\^ \*Minvoke\fP selects the
335: value of \*(ei that corresponds to the value of \*(e0. That is,\^
336: if \*(e0 is 2,\^ then \*(e2 is selected and returned. If \*(e0
337: references a value that is out of range,\^ \*Minvoke\fP fails.
338: .Np
339: If an Icon procedure or built-in procedure
340: is being called,\^ the argument list is adjusted
341: to conform to the number of arguments that the procedure or function
342: is expecting.
343: This may mean supplying \*M&null\fP for missing values,\^ or discarding
344: the last few \*(ei. Some built-in functions take a variable number of
345: arguments,\^ but all Icon procedures take a fixed number of arguments.
346: If the desired operation is creation of a record,\^ \*Minvoke\fP treats
347: this just like invocation of a built-in procedure.
348: .Le
349: .LP
350: Built-in functions and Icon procedures are handled in very different ways.
351: If a built-in function is being invoked,\^ it is simply called. (The
352: calling sequence is somewhat convoluted on the VAX and is
353: described later.)
354: Calling an Icon procedure is more involved; the following actions
355: are taken.
356: .Ls
357: .Np
358: Each \*(ei in the (adjusted) argument list is dereferenced.
359: .Np
360: If \*M&trace\fP has a non-zero value,\^ the function \*Mctrace\fP is
361: called with appropriate arguments. \*Mctrace\fP produces output
362: that includes the name of the procedure being called and the arguments
363: that are being passed to it.
364: .Np
365: The remainder of the procedure frame (partially constructed by the
366: call itself) is built. This includes pushing values for \*M_file\fP
367: and \*M_line\fP on the stack. \*M_file\fP is a pointer to a string
368: that names the source file from which the code currently being
369: executed came. \*M_line\fP is the number of the source line
370: that is currently being executed. A descriptor for
371: \*M&null\fP is pushed on the
372: stack for each dynamic local of the procedure.
373: .Np
374: The generator frame pointer is cleared (because a new expression
375: context is being entered). \*Mipc\fP
376: is loaded with the entry point of the procedure being called.
377: Control is then passed back to the interpreter using a jump
378: instruction.
379: .Le
380: .SH
381: \*Minvoke\fP on the VAX
382: .PP
383: On the VAX,\^ immediately after \*Minvoke\fP has been entered,\^ the stack is
384: .Ds
385: .ft R
386: .St
387: value from \*(e0
388: value from \*(e1
389: \*(El
390: 8 value from \*(en
391: 4 number of expressions \- 1 (\*Mnargs\fR)
392: \*Map\fR \*(ar 0 number of words in argument list (\*Mnwords\fR)
393: -4 saved \*Mr11\fR
394: -8 saved \*Mr10\fR
395: \*(El
396: saved \*Mr1\fR
397: saved \*Mpc\fR
398: 12 saved \*Mfp\fR
399: 8 saved \*Map\fR
400: 4 program status word and register mask
401: \*Msp\fR,\^ \*Mfp\fR \*(ar 0 0 (condition handler address)
402: .De
403: .PP
404: The first action of \*Minvoke\fP is to set \*M_boundary\fP to the
405: value of \*Mfp\fP. This is done because \*Minvoke\fP may be
406: invoking a built-in procedure.
407: .PP
408: The number of arguments with which \*(e0 is to be invoked is contained
409: in the \fInargs\fP word,\^ which resides at \*M4(ap)\fP. This value
410: is frequently used and is put into \*Mr8\fP.
411: .PP
412: \*Minvoke\fP makes
413: frequent use of \*(e0,\^ but its address is not a fixed distance
414: from any known point. Rather,\^ the address of \*(e0 must be calculated
415: using the address of \*(en and the number of arguments. The VAX
416: \*Mmovaq\fP instruction makes this calculation easy. The desired
417: calculation is
418: .Ds
419: r11 = 8 + ap + (r8 * 8)
420: .De
421: and is performed by
422: .Ds
423: movaq 8(ap)\^[r8],\^r11
424: .De
425: \*(e0 may be a
426: variable and if so,\^ it needs to be dereferenced.
427: \*Mr11\fP,\^ which contains the address of \*(e0 is pushed on
428: the stack and \*Mderef\fP is called. The dereferencing is done
429: ``in place''; the previous value of \*(e0 is replaced with the
430: dereferenced value. The dereferenced value is a descriptor
431: whose first word contains type information and whose second word
432: (in some cases) contains the address of a data block which holds
433: the actual value of the object. Note that \*Mr11\fP points to
434: the first word of this descriptor.
435: .PP
436: Recall that the first task of \*Minvoke\fP is to determine what
437: \*(e0 is and to act accordingly. The simplest case is when \*(e0
438: is a procedure. That is checked for by comparing \*M0(r11)\fP with
439: \*MD_PROC\fP. If \*(e0 is a procedure,\^ a forward jump is made to
440: \*Mdoinvk\fP.
441: .PP
442: It is more interesting if \*(e0 is not a procedure. The first
443: alternative investigated is mutual evaluation. mutual evaluation is similar to a procedure
444: call,\^ but rather than \*(e0 being a procedure,\^ it is an integer
445: that selects one of the \*(ei. The selected \*(ei is the outcome of
446: the mutual evaluation. The routine \*Mcvint\fP is used to
447: try to convert \*(e0 to an integer. If \*(e0 cannot be converted to
448: an integer,\^ a forward branch is taken to \*Mtrystr\fP to explore another
449: possibility.
450: For mutual evaluation,\^ a non-positive value of \*(e0
451: is acceptable and is converted to a positive value using the
452: \*Mcvpos\fP routine. (Expressions in the argument list are indexed
453: the same way that characters in a string are indexed.) If the
454: position is greater than the number of expressions in the list,\^ that
455: is,\^ if the reference is out of range,\^ the mutual evaluation fails by calling
456: the routine \*Mfail\fP. If the position is in range,\^ the selected
457: \*(ei must be returned as the result of the invocation (and the
458: result of the mutual evaluation). The \*(ei to return is selected by multiplying
459: the position by 8 (each \*(ei is a descriptor) and subtracting
460: that from \*Mr11\fP,\^ which points at \*(e0. The descriptor thus
461: referenced is copied into the location of \*(e0. (Recall that \*(e0
462: is used to receive the result of an operation.) \*M_boundary\fP
463: is then cleared and \*Minvoke\fP returns.
464: .PP
465: If \*(e0 is not convertible to an integer,\^ conversion to a
466: procedure is attempted. (Note that this is an experimental extension
467: to Icon.) \*(e0 is first converted to a string
468: using \*Mcvstr\fP. If the conversion is successful,\^ the routine
469: \*Mstrprc\fP is called to see if the string ``names'' a procedure.
470: The conversion performed by \*Mstrprc\fP is ``in place'',\^ i.e.,\^
471: \*(e0 becomes a descriptor for a procedure. If either the
472: conversion in \*Mcvstr\fP or \*Mstrprc\fP fails,\^ \*(e0 is deemed
473: to be uninvocable and this is noted by run-time Error 106.
474: .PP
475: At this point (the label \*Mdoinvk\fP),\^ \*(e0 is a descriptor to a procedure
476: to be invoked and \*Mr11\fP points to \*(e0.
477: .PP
478: The next operation is to make the number of arguments supplied
479: conform to the number of arguments that the procedure is expecting.
480: The number of arguments that a procedure expects is in the fifth
481: word of its procedure block. This value for the procedure being
482: invoked is obtained and placed in \*Mr10\fP.
483: If the value is negative,\^ the number
484: of arguments that the procedure expects is variable. Only built-in
485: procedures can have a variable number of arguments,\^ so if the
486: desired argument count is negative,\^ control passes to the label
487: \*Mbuiltin\fP.
488: .PP
489: \*Mr8\fP contains the number of arguments given and \*Mr10\fP contains
490: the number of arguments desired. The value of \*Mr10\fP is subtracted
491: from \*Mr8\fP,\^ leaving \*Mr8\fP with the difference. If the
492: number of arguments supplied is the same as the number expected,\^
493: no adjustment is needed and a forward jump is made to
494: \*Mdoderef\fP. Otherwise,\^ the stack must be adjusted.
495: .PP
496: First,\^ \fInwords\fR and \fInargs\fR on the stack are adjusted. Recall
497: that \fInargs\fR
498: is used by Icon and is the number of arguments for a procedure.
499: \fInwords\fR is used by the VAX hardware and is the number of words that
500: the argument list for a subroutine occupies. \fInargs\fR resides at
501: \*M4(ap)\fP and is updated by storing \*Mr10\fP in \*M4(ap)\fP.
502: \fInwords\fR is trickier because only the low-order byte of the \fInwords\fR word
503: is to be used for the word count. The low-order byte of \*Mr10\fP is
504: stored in \*M0(ap)\fP,\^ doubled,\^ and then incremented by one. (The
505: increment by one is to allow for the \fInargs\fR word that is part of
506: the argument list.)
507: .PP
508: The deletion of excess arguments or addition of \*M&null\fP for
509: missing arguments is accomplished by moving the lower portion of
510: the stack up or down to overwrite excess arguments or to leave
511: space for missing arguments. Consider the following: A procedure
512: that expects one argument has been invoked with three arguments.
513: The stack is
514: .Ds
515: .ft R
516: .St
517: 128 \*(e0
518: 120 \*(e1
519: 112 \*(e2
520: 104 \*(e3
521: 100 \*Mnargs\fR (3 at call,\^ 1 after adjustment)
522: \*Map\fR \*(ar 96 \*Mnwords\fR (7 at call,\^ 3 after adjustment)
523: 92 \*Mr11\fR
524: \*(El
525: 48 \*Mr1\fR
526: 44 \*Mpc\fR
527: 40 \*Mfp\fR
528: 36 \*Map\fR
529: 32 \*Mpsw\fR
530: \*Msp\fR,\^ \*Mfp\fR \*(ar 28 0
531: .De
532: The situation desired is
533: .Ds
534: .ft R
535: 128 \*(e0
536: 120 \*(e1
537: 116 \*Mnargs\fR (1)
538: \*Map\fR \*(ar 112 \*Mnwords\fR (3)
539: 108 \*Mr11\fR
540: \*(El
541: 64 \*Mr1\fR
542: 60 \*Mpc\fR
543: 56 \*Mfp\fR
544: 52 \*Map\fR
545: 48 \*Mpsw\fR
546: \*Msp\fR,\^ \*Mfp\fR \*(ar 44 0
547: .De
548: Note the address field (which has been arbitrarily assigned).
549: Observe that \*(e0 and \*(e1 are in
550: the same place,\^ but that the lower portion of the stack has moved up.
551: Consider what would be desired if the
552: procedure being invoked requires five arguments and only three are
553: supplied. The desired stack configuration is
554: .Ds
555: .ft R
556: .St
557: 128 \*(e0
558: 120 \*(e1
559: 112 \*(e2
560: 104 \*(e3
561: 96 \*M&null\fP (\*(e4)
562: 88 \*M&null\fP (\*(e5)
563: 84 \*Mnargs\fR (5)
564: \*Map\fR \*(ar 80 \*Mnwords\fR (11)
565: 76 \*Mr11\fR
566: \*(El
567: 32 \*Mr1\fR
568: 28 \*Mpc\fR
569: 24 \*Mfp\fR
570: 20 \*Map\fR
571: 16 \*Mpsw\fR
572: \*Msp\fR,\^ \*Mfp\fR \*(ar 12 0
573: .De
574: As before,\^ the ``good'' arguments are in the same place,\^ but the
575: stack has moved down to make room for \*(e4 and \*(e5 and a value
576: of \*M&null\fP is supplied for them.
577: .PP
578: The VAX hardware makes these stack manipulations easy. Recall that
579: \*Mr8\fP contains
580: .Ds
581: .ft R
582: number of arguments expected \- number of arguments supplied
583: .De
584: Thus,\^ in the first case \*Mr8\fP has a value of 2,\^ while in the second
585: case \*Mr8\fP is \-2. The value of \*Mr8\fP is multiplied by
586: 8 to turn the argument count into a byte count. This byte count
587: is added to \*Msp\fP,\^ effectively moving it to where it should
588: be. Now,\^ a block of memory starting at where \*Mfp\fP points
589: must be moved to where \*Msp\fP points. The size of the
590: block needs to be considered. It starts at the fp and contains
591: the condition handler,\^ the old psw,\^ \*Map\fP,\^ \*Mfp\fP and \*Mpc\fP
592: \(em five words.
593: Eleven saved registers are included; eleven more words. (A constant,\^
594: \*MINVREGS\fP,\^ is used to represent the number of saved registers.)
595: Finally,\^ two words for \fInargs\fR and \fInwords\fR \(em a total of 18
596: words. The VAX
597: instruction that makes the move is
598: .Ds
599: movc3 $(INVREGS+7)*4,\^(fp),\^(sp)
600: .De
601: which moves 18*4 (=72) bytes from where \*Mfp\fP is pointing to
602: where \*Msp\fP pointing. The VAX allows the source and
603: destination fields to overlap without producing ``curious'' results.
604: .PP
605: Some housekeeping must be performed after the move is made.
606: \*Mfp\fP is set to point to the same word \*Msp\fP points to,\^
607: and the boundary is set to point to the same place. \*Map\fP is
608: adjusted to point to the \fInwords\fR word.
609: .PP
610: If arguments were deleted,\^ the adjustment process is done. If
611: arguments were added,\^ \*M&null\fP must be supplied as the value
612: for each argument that was added. Because the descriptor for
613: \*M&null\fP consists of two words containing 0,\^ the task amounts to filling
614: in null bytes in the ``hole'' that was made. \*Mr8\fP contains
615: the number of bytes in the ``hole''. \*Mr8\fP is negative and it
616: is negated to obtain a positive byte count. The instruction
617: .Ds
618: movc5 $0,\^(r0),\^$0,\^r8,\^(INVREGS+7)*4(sp)
619: .De
620: does all the work. Specifically,\^ this instruction moves bytes of zeroes
621: starting at \*M(r0)\fP to a field that starts at \*M72(sp)\fP and
622: extends for \*Mr8\fP bytes. The third operand of the instruction
623: is a ``fill character'' that is used in the event that the destination
624: field is longer than the source field. In this case,\^ the source
625: field is 0 bytes long,\^ and a null-byte fill character is moved into
626: each byte of the destination field. This is the usual way to zero
627: out a block of memory on the VAX.
628: .PP
629: At this point,\^ the correct number of arguments for the procedure
630: are on the stack.
631: .PP
632: For an Icon procedure,\^ all arguments must be dereferenced before
633: the procedure is called. Procedure blocks have a field that tells
634: how many dynamic local variables the procedure has. For built-in
635: procedures this field has a value of \-1. If a built-in procedure
636: is to be invoked,\^ control jumps to the label \*Mbuiltin\fP.
637: If an Icon procedure is to be invoked,\^ but it has no arguments (and
638: thus they do not need to be dereferenced),\^ a forward jump is made
639: to \*Mcktrace\fP.
640: .PP
641: \*Mr11\fP points to the descriptor for \*(e0. The address of \*(e1
642: is used later in \*Minvoke\fP,\^ and its address is calculated using \*Mr11\fP
643: because it's handy. \*Mr10\fP contains the number of arguments and
644: this value is stored in \*Mr5\fP for subsequent use of \*Mr5\fP as a
645: counter. The arguments must be dereferenced,\^ this is done by calling
646: \*Mderef\fP with the address of each argument. The instruction
647: .Ds
648: pushaq -(r11)
649: .De
650: is used to decrement \*Mr11\fP by 8 and then push the value of \*Mr11\fP
651: on the stack. Because \*Mr11\fP initially references \*(e0,\^ the first
652: time through \*Mr11\fP is decremented to point at \*(e1 and
653: \*Mderef\fP is called with the address of \*(e1. \*Mr11\fP is backed
654: down through the expression list,\^ with each \*(ei being dereferenced
655: in turn. Note that the \*Msobgeq\fP instruction is used as a loop
656: controller,\^ decrementing \*Mr5\fP and jumping back to \*Mnxtarg\fP as
657: long as \*Mr5\fP is not 0.
658: .PP
659: At this point,\^ an Icon procedure is being
660: invoked; it has the correct number of arguments and they
661: have been dereferenced.
662: .PP
663: If tracing is on,\^ (indicated by a non-zero value for \*M_k_trace\fP),\^
664: a trace message must be produced at this point.
665: The routine \*Mctrace\fP does all the work. It needs to be called
666: with the appropriate arguments. \*Mctrace\fP requires three
667: arguments: procedure block address,\^ number of arguments,\^ and the
668: address of the first argument. These are pushed on the stack and
669: \*Mctrace\fP is called.
670: .PP
671: The portion of the stack from \*(e0 on down constitutes a partial
672: procedure frame and it must be completed. \*M_line\fP and \*M_file\fP
673: are pushed on the stack. To complete the frame,\^ the local variables
674: must be pushed on the stack. Local variables have an initial value
675: of \*M&null\fP,\^ and the \*Mmovc5\fP idiom used previously is used
676: again to zero out the space required for the local variables.
677: .PP
678: Because an Icon procedure is being invoked,\^ the boundary is cleared and
679: \*M_k_level\fP (the \*M&level\fP keyword) is incremented. The entry
680: point for a procedure is stored in the third word of the procedure
681: block. This value is loaded into \*Mipc\fP.
682: A new expression context is being entered,\^ and both
683: \*Mgfp\fP and \*Mefp\fP are cleared using a \*Mclrq\fP instruction.
684: .PP
685: Control is passed back to the main loop of the interpreter
686: by jumping to \*Minterp\fP.
687: The Icon procedure is now being executed. The procedure
688: eventually terminates by use of \*Mpret\fP or \*Mpfail\fP.
689: .LP
690: The section of code following \*Mbuiltin:\fP
691: handles the case where a built-in procedure is to be invoked.
692: .PP
693: If nothing is changed,\^ when a built-in function returns,\^ it would
694: return to the instruction after the call to \*Minvoke\fP. This
695: is unsatisfactory,\^ since the boundary needs to be cleared because
696: of the transition from the C environment to the Icon environment.
697: Rather than having a call to \*Mclrbound\fP at
698: the end of each built-in procedure,\^ the boundary is cleared at
699: a common return point.
700: .PP
701: The \*Mpc\fP value that is stored at \*M16(fp)\fP is ``hidden''
702: at \*M20(fp)\fP where the value of \*Mr1\fP should be saved.
703: \*M16(fp)\fP is replaced with the address of the forward label
704: \*Mbprtn\fP. Thus,\^ when the built-in procedure returns,\^ it goes
705: right to \*Mbprtn\fP. Because a C environment is being entered,\^
706: the boundary is set to the current value of \*Mfp\fP. The third
707: word of the procedure block contains the entry point of the built-in
708: procedure and it is jumped to. It is important to understand that
709: the procedure is not called because the call frame has already been
710: constructed. Also,\^ the entry point address stored in the procedure
711: block \fImust\fR be past any instructions that are used to establish
712: the stack environment for the routine because this environment
713: should already be on the stack.
714: .PP
715: When the built-in procedure returns,\^ it comes to \*Mbprtn\fP.
716: The boundary is cleared because execution is back in an Icon
717: environment. The procedure return restores \*Mr1\fP,\^ which contains
718: the \*Mpc\fP value that \*Minvoke\fP should return to. Because
719: the return has already swept off the old frame,\^ \*M0(r1)\fP is
720: jumped to and \*Minvoke\fP is finished. Note that the built-in
721: procedure has left its result in \*(e0,\^ which is left on the
722: stack. Thus,\^ the direct result of \*Minvoke\fP is an additional
723: value on the stack.
724: .SH
725: Some Comments on \*Minvoke\fR
726: .PP
727: It is important to understand the purpose of \*Minvoke\fP. Unless
728: mutual evaluation is being performed,\^
729: the task of \*Minvoke\fP is to create a procedure frame for an Icon or
730: built-in procedure and then transfer control to the procedure.
731: .PP
732: On the VAX and the PDP-11,\^ the call to \*Minvoke\fP partially
733: creates the procedure frame. \*Minvoke\fP then completes the
734: frame. For Icon procedures,\^ control eventually passes out of
735: \*Minvoke\fP and goes back to the interpreter loop. However,\^
736: for built-in procedures,\^ after the frame is built,\^ \*Minvoke\fP
737: \fIbranches into\fP the C code for the procedure. Thus,\^ it appears
738: that the built-in procedure was called directly. This scheme is
739: facilitated by the fact that entry points of C routines on the
740: VAX and PDP-11 are a constant distance from the start of the routine.
741: (The \*MEntryPoint\fP macro in \*Mrt.h\fP specifies the distance.)
742: On some machines this may not be practical and other schemes may need
743: to be developed.
744: .PP
745: Another point that needs to be addressed is that of argument removal.
746: When a built-in procedure,\^ Icon procedure,\^ or built-in operation is
747: performed,\^ the net result almost always is
748: simply the addition of a descriptor to the stack. More precisely,\^
749: the new descriptor is actually a replacement for \*(a0,\^ which
750: is the descriptor for the procedure being called,\^ or in the case
751: of a built-in operation is \*M&null\fP. Recall that arguments are below \*(a0
752: on the stack. The \*(a0 word must be on top of the
753: stack when a procedure or operation is complete. The VAX does
754: this via hardware,\^ which manages the stack and removes arguments when
755: a procedure call is complete. The PDP-11 does not have such hardware
756: facilities and thus the arguments must be removed manually. The
757: problem is compounded by the fact that for built-in operations,\^
758: \*Minvoke\fP is never called; rather,\^ the interpreter loop calls the
759: appropriate subroutine directly.
760: .PP
761: The method employed on the PDP-11 uses the \*Mcret\fP routine to
762: remove arguments. \*Mcret\fP is called at the end of each C routine
763: to restore registers. Icon has a replacement for \*Mcret\fP that
764: restores registers but also removes arguments when appropriate.
765: \*Mrt/csv.s\fP contains the replacement routine. When \*Mcret\fP is
766: called,\^ if \*Mr5\fP (the \*Mpfp\fP on the PDP-11) is equal to
767: \*M_boundary\fP,\^ then \*Mcret\fP is returning to Icon code and any
768: arguments on the stack are removed,\^ leaving \*(a0 on the top of the
769: stack.
770: A similar technique may be needed on the target machine.
771: .PP
772: \*Mrt/csv.s\fP also contains a replacement for the \*Mcsv\fP routine
773: which saves registers upon entry to C functions
774: on the PDP-11. Both \*Mcsv\fP and \*Mcret\fP also contain code that
775: is used to set and clear the boundary at appropriate times. See
776: the description of \*Mrt/setbound.s\fP for more details.
777: .NH 3
778: \*Miconx/interp.s\fR
779: .SH
780: Overview
781: .PP
782: \*Minterp.s\fP is the main loop for the interpreter.
783: The execution of an Icon program is stack based.
784: As the interpreter executes an Icon program,\^ it
785: fetches instructions and accompanying operands out of the instruction
786: stream of the interpretable file. Operands for
787: interpreter instructions are pushed on the stack and results
788: accumulate on the stack as operands for other instructions.
789: In addition to simple incremental and decremental stack changes,\^
790: the expression evaluation mechanism may cause portions of the
791: stack to be duplicated and may also cause the top portion of
792: the stack to be removed.
793: .SH
794: Generic Operation
795: .PP
796: An Icon program is executed by interpreting the interpretable file
797: produced by the linker. The interpretation process itself is fairly
798: simple. \*Mipc\fP points at the next
799: instruction to be executed. (Recall that the interpretable file is
800: loaded into memory.) The opcode of the instruction is fetched
801: and the corresponding
802: word in the jump table is taken as the address of a sequence of
803: instructions that perform the desired operations. A branch is
804: taken to the referenced location and the operation is performed.
805: The operation may require operands; if so,\^ they appear in the
806: instruction stream following the opcode. The segment of code that
807: performs a particular operation is responsible for fetching the
808: appropriate operands out of the stream. When the
809: operation is complete,\^ a jump is taken to the top of the interpreter
810: loop and the process continues.
811: .PP
812: Interpreter operations are of two types. Operations of the first type
813: call a routine to perform a task. Operations of the second type are
814: executed entirely by the interpreter; no subroutine call is necessary.
815: .PP
816: Operations that require a call to be made call routines in the
817: \*Moperators\fP or \*Mlib\fP directories. The routine being called
818: may require one or more arguments. If arguments are required,\^ they
819: appear on the stack. When the routine returns,\^ it removes
820: any arguments that it was called with from the stack and leaves its
821: result on the top of the stack.
822: .PP
823: To facilitate the calling of
824: routines,\^ a table known as \*Moptab\fP parallels the jump table.
825: An opcode \fIn\fP references the \fIn\fPth word of the jump table.
826: If the operation designated by the opcode requires a call,\^ the
827: \fIn\fPth word of \*Moptab\fP contains the address of the routine
828: that should be called.
829: .PP
830: The interpreter saves space in its
831: instruction stream by encoding operand information in some opcodes.
832: For example,\^ the \*Mline\fP instruction has one operand that
833: is used to set the value of \*M_line\fP,\^ the current source line
834: number. The \*Mlinex\fP instruction is an alternate form of
835: \*Mline\fP which encodes the line number as the low order bits of the
836: opcode. Specifically,\^ the opcodes from 192 to 256 are \*Mlinex\fP
837: opcodes. For example,\^ opcode 195 is equivalent to a \*Mline\fP
838: opcode with an operand of 3.
839: .SH
840: Implementing the Interpreter Loop
841: .PP
842: \*Minterp.s\fP stands alone among the assembly language files as one that is
843: well suited to coding in a macro fashion. Most of the interpreter loop is
844: written in terms of \fIcpp\fP macros and thus porting it is largely a
845: matter of writing the macros for the target machine.
846: .LP
847: The following \*M#define\fPs must be made.
848: .Ip \*MOp\ \ \ \ \ \fP
849: .br
850: The operand register. Any general purpose register will do. The
851: value of the register need not preserved between instructions; its
852: lifetime is only from the time that an operand is fetched until the
853: next opcode is fetched or a routine is called.
854: .Ip \*MGetOp\fP
855: This must expand into code that fetches the next operand out of
856: the instruction stream and places it in the register \*MOp\fP.
857: Recall that operand size is determined by
858: the \*M#define\fP for \*MOPNDSIZE\fP in the linker.
859: On the VAX,\^ \*MGetOp\fP is merely
860: .Ds
861: .ta 0.6i +0.6i +0.6i +0.6i
862: movl (ipc)+,\^Op
863: .De
864: This is because operands are one word long and can begin on any byte
865: boundary. If the VAX did not support word fetching from arbitrary
866: boundaries,\^ it would be necessary to get the bytes from the
867: instruction stream one at a time and make a word out of them using
868: boolean operations. If such were the case,\^ a reasonable alternative
869: would be to make opcodes one word in size and thus all instruction
870: stream objects (opcodes,\^ operands,\^ and words),\^ would be of the same
871: size and lie on word boundaries.
872: .\".IP \*MGetWord\fP
873: .\"\*MGetWord\fP is similar to \*MGetOp\fP,\^ but rather than loading the
874: .\"next operand,\^ it loads the next \fIword\fP from the instruction stream into
875: .\"the \*MOp\fP register. Recall that the size of a word is defined by
876: .\"the \*MWORDSIZE\fP in the linker. If words are the same size as
877: .\"operands on the target machine,\^ \*MGetWord\fP should be identical to
878: .\"\*MGetOp\fP.
879: .Ip \*MPushOp\fP
880: Push the \*MOp\fP register on the stack. The VAX uses
881: .ta .6i
882: .Ds
883: pushl Op
884: .De
885: .Ip \*MPushNull\fP
886: Push a descriptor for \*M&null\fP on the stack. That is,\^ push two
887: words of zeroes. The VAX \*Mclrq\fP instruction does the trick:
888: .Ds
889: clrq -(sp)
890: .De
891: .Ip \*MPush_R(x)\fP,\^\ \*MPush_S(x)\fP,\^\ \*MPush_K(x)\fP
892: Push the value of \*Mx\fP on the stack. To accommodate machines with
893: non-orthogonal instruction sets,\^ \*MPush_R\fP is used to push a register
894: value,\^ and \*MPush_S\fP is used to push the contents of a storage
895: location. \*MPush_K\fP is used to push a constant value.
896: The VAX uses
897: .Ds
898: pushl x
899: .De
900: for both \*MPush_R(x)\fP and \*MPush_S(x)\fP,\^ while
901: .Ds
902: pushl $x
903: .De
904: is used for \*MPush_K(x)\fP.
905: .Ip \*MPushOpSum_R(x)\fP,\^\ \*MPushOpSum_S(x)\fP
906: \*MPushOpSum_R(x)\fP adds the value
907: of the register \*Mx\fP to \*MOp\fP and pushes the result on the stack.
908: \*MPushOpSum_S(x)\fP is similar,\^ adding the value in the memory
909: location \*Mx\fP to \*MOp\fP and pushing the result. On the VAX,\^
910: .Ds
911: addl3 Op,\^x,\^-(sp)
912: .De
913: is used for both.
914: .Ip \*MNextInst\fP
915: Branch to the top of the interpreter loop. The VAX uses
916: .Ds
917: jmp _interp
918: .De
919: .Ip \*MCallN(n)\fP
920: Call the routine corresponding to the current opcode with \*Mn\fP
921: arguments. On the VAX,\^ the opcode fetching segment loads \*Mr0\fP
922: with a byte offset into the jump table. This same byte offset
923: references the location in \*Moptab\fP which contains the address
924: of the routine which corresponds to the current opcode.
925: \*MCallN(n)\fP expands to
926: .Ds
927: pushl $n
928: calls $((n*2)+1),\^*optab(r0)
929: .De
930: \*Mpushl $n\fP pushes the number of arguments on the stack. This
931: word becomes the \fInargs\fP word of the procedure frame. The
932: first of operand of the \*Mcalls\fP instruction is the length of
933: words in the argument list,\^ since each argument is a two word
934: descriptor and the \fInargs\fP word occupies another word,\^
935: \*Mn*2+1\fP is used as the length of the argument list. The
936: address contained in the \*Moptab\fP word referenced by \*Mr0\fP is
937: the routine to call.
938: .Ip \*MCallNameN(n,\^f)\fP
939: Call the routine named \*Mf\fP with \*Mn\fP arguments. This is very
940: similar to \*MCallN\fP,\^ the only difference being that the routine
941: to call is explicitly named rather than being implicitly determined
942: from the opcode value. The VAX uses
943: .Ds
944: pushl $n
945: calls $((n*2)+1),\^f
946: .De
947: .Ip \*MBitClear(m)\fP
948: The constant value \*Mm\fP designates bits in the \*MOp\fP register
949: to leave on. All other bits in \*MOp\fP should be turned off. That
950: is,\^ the complement of \*Mm\fP is \*MAND\fPed with the contents of
951: \*MOp\fP and the result is placed in \*MOp\fP. This is used to
952: decode opcodes with encoded operands. The VAX uses
953: .Ds
954: bicl2 $0!m,\^Op
955: .De
956: .Ip \*MJump(lab)\fP
957: Branch to the label \*Mlab\fP. The destination label is close to the
958: jump,\^ so a short jump of some type may be used. The VAX uses
959: .Ds
960: jbr lab
961: .De
962: .Ip \*MLongJump(lab)\fP
963: \*MLongJump\fP is like \*MJump\fP with the exception that \*Mlab\fP
964: may be quite distant. The VAX uses
965: .Ds
966: jmp lab
967: .De
968: .Ip \*MLabel(lab)\fP
969: Generate a label declaration for \*Mlab\fP. The VAX uses
970: .Ds
971: lab:
972: .De
973: .SH
974: VAX Specific Sections of \*Minterp\fR
975: .PP
976: Several sections of \*Minterp\fP are machine specific and must be
977: coded on a per-machine basis. The sections in question are explained
978: on an individual basis:
979: .Ip \*M_interp\fP
980: The next opcode is fetched and loaded into \*Mr0\fP. \*Mmovzbl\fP
981: moves a byte and zero extends it to a word value. Because a byte was
982: fetched,\^ \*Mipc\fP is incremented by 1. The opcode is saved in
983: \*MOp\fP in case it contains an encoded operand. \*Mr0\fP is
984: multiplied by 4 to turn it into a byte offset. A jump is made to the
985: address indexed by \*Mr0\fP in \*Mjumptab\fP to perform the desired
986: operation. Eventually,\^ a jump returns control to the label
987: \*M_interp\fP to fetch and execute the next instruction.
988: .Ip \*Mop_bscan\fP
989: A descriptor for \*M_k_subject\fP is pushed on the stack. Then
990: the value of \*M_k_pos\fP is pushed,\^ followed by the constant
991: \*MD_INTEGER\fP. The routine corresponding to \*Mop_bscan\fP,\^
992: \*M_bscan\fP,\^ is called with 0 arguments. (This causes the
993: descriptors for \*M_k_subject\fP and the value of \*M_k_pos\fP to be
994: left on the stack.) When \*M_bscan\fP returns,\^ a branch is made to
995: \*M_interp\fP.
996: .Ip \*Mop_ccase\fP
997: A null descriptor is pushed on the stack. The word immediately
998: above the current expression frame is then pushed on the stack.
999: .Ip \*Mop_chfail\fP
1000: The operand of \*Mchfail\fP is fetched into \*MOp\fP. \*MOp\fP and
1001: \*Mipc\fP are added together and the result replaces the failure
1002: address in the current expression frame.
1003: .Ip \*Mop_dup\fP
1004: A null descriptor is pushed on the stack. The value that was on top
1005: of the stack is now at \*M8(sp)\fP,\^ and it is copied to the top of the
1006: stack using a \*Mmovq\fP.
1007: .Ip \*Mop_eret\fP
1008: \*Meret\fP gets the value on top of the stack,\^ removes the current
1009: expression frame and puts the previous top of stack value back on the
1010: top of the stack. First of all,\^
1011: .Ds
1012: movq (sp)+,\^r0
1013: .De
1014: moves the descriptor on the top of the stack into the \*Mr0\-r1\fP
1015: register pair and increments the stack pointer by 8. The \*Mgfp\fP
1016: is loaded with the \*Mgfp\fP value stored in the expression frame
1017: marker. \*Msp\fP is loaded from \*Mefp\fP,\^ bringing the expression
1018: marker to the top of the stack. The old \*Mefp\fP value from the
1019: marker is loaded into \*Mefp\fP. Finally,\^ the value stored in the
1020: \*Mr0\-r1\fP pair is pushed on the stack.
1021: .Ip \*Mop_file\fP
1022: The operand of \*Mfile\fP is loaded into \*MOp\fP. \*MOp\fP and the
1023: value of \*M_ident\fP are added and the result in placed in
1024: \*M_file\fP.
1025: .Ip \*Mop_goto\fP
1026: The operand is loaded into \*MOp\fP and then added to \*Mipc\fP.
1027: .Ip \*Mop_incres\fP
1028: The eighth word of the co-expression heap block for the current
1029: expression is incremented by one.
1030: .Ip \*Mop_init\fP
1031: This one is tricky. The \*Minit\fP instruction arises from the
1032: \*Minitial\fP statement in Icon and is used to effect one-time
1033: execution of a segment of code. The operand of \*Minit\fP is the
1034: address of the first instruction after the segment that is to be
1035: executed once. The instruction
1036: .Ds
1037: movb $59,\^-(ipc)
1038: .De
1039: decrements \*Mipc\fP by 1 and then stores the constant 59 in the byte
1040: that \*Mipc\fP references,\^ which is the \*Minit\fP opcode. The magic
1041: number 59 is the opcode for \*Mgoto\fP,\^ so in effect,\^ the \*Minit\fP
1042: had been made into a goto that skips a section of code. By adding 5
1043: to \*Mipc\fP,\^ it leaves \*Mipc\fP pointing at the first instruction
1044: of the \*Minitial\fP code. The constant 5 is derived from the
1045: width of the opcode and associated operand,\^ i.e.,\^
1046: \*MOPSIZE+OPNDSIZE\fP.
1047: .Ip \*Mop_invoke\fP
1048: This section has two entry points: \*Mop_invoke\fP gets control if
1049: \*Minvoke\fP has an operand,\^ and \*Mop_invkx\fP gets control if the
1050: operand is encoded in the opcode. If an operand is specified,\^ it is
1051: fetched into \*MOp\fP. If the operand is encoded,\^ \*MBitClear(7)\fP is
1052: used to isolate the operand in \*MOp\fP. Control converges at
1053: \*Mdoinvoke\fP. The operand is the number of arguments to
1054: invoke the procedure with and it is pushed on the stack as
1055: the \fInargs\fP word. (The arguments are already on the stack.)
1056: The \*Mcalls\fP instruction needs the length of the argument list,\^ so
1057: \*MOp\fP is multiplied by 2 and then incremented by 1. \*Minvoke\fP
1058: is called.
1059: .Ip \*Mop_int\fP
1060: As in \*Mop_invoke\fP,\^ \*Mop_int\fP has a secondary entry point,\^
1061: \*Mop_intx\fP,\^ for operands encoded in the opcode. At the \*Mop_int\fP
1062: entry point,\^ a \*MWORDSIZE\fP value is fetched out of the instruction
1063: stream and loaded into \*MOp\fP. At the \*Mop_intx\fP entry point,\^
1064: the \*MOp\fP value is decoded from the operand. The \*MOp\fP value is
1065: pushed on the stack and is followed by a \*MD_INTEGER\fP word,\^ forming
1066: an integer descriptor.
1067: .Ip \*Mop_line\fP
1068: Like \*Mop_invoke\fP and \*Mop_int\fP,\^ \*Mop_line\fP has a secondary
1069: entry point. The operand value is obtained and then moved into \*M_line\fP.
1070: .Ip \*Mop_llist\fP
1071: \*Mllist\fP is similar to \*Minvoke\fP in that it has a number of
1072: arguments already on the stack and that the operand specifies the
1073: number. The operand is fetched into \*MOp\fP and pushed on the
1074: stack to become the \fInargs\fP argument of \*Mllist\fP. \*MOp\fP is
1075: then multiplied by 2 and incremented by 1 to serve as an argument
1076: list size for \*Mcalls\fP.
1077: .Ip \*Mop_mark\fP
1078: The operand is fetched into \*MOp\fP and \*Mipc\fP is added to it.
1079: \*Mefp\fP is pushed on the stack and the new \*Msp\fP value is put in
1080: \*Mefp\fP. \*Mgfp\fP is pushed on the stack and cleared. \*MOp\fP
1081: is pushed on the stack.
1082: .Ip \*Mop_mark0\fP
1083: Like \*Mop_mark\fP,\^ with an implicit operand value of zero.
1084: .Ip \*Mop_pop\fP
1085: The two \*Mtstl\fP instructions serve to add 8 to \*Msp\fP which
1086: removes the top value from the stack.
1087: .Ip \*Mop_sdup\fP
1088: The descriptor on the top of the stack is pushed on the stack,\^
1089: duplicating it.
1090: .Ip \*Mop_unmark\fP
1091: The operand,\^ the number of expression frames to remove from the
1092: stack,\^ is fetched into \*MOp\fP. \*Mefp\fP is
1093: restored from the current expression frame. The instruction
1094: .Ds
1095: sobgtr Op,\^unmkjmp
1096: .De
1097: decrements \*MOp\fP and then branches to \*Mdounmark\fP if \*MOp\fP is not
1098: zero. This chains through the number of expression frames specified
1099: by the operand. \*Mgfp\fP is restored from the current expression
1100: marker. \*Mefp\fP is loaded into \*Msp\fP to move the expression
1101: marker to the top of the stack. Finally,\^ \*Mefp\fP is restored
1102: from the marker and \*Msp\fP is incremented to remove the last word
1103: of the marker.
1104: .Ip \*Mop_unmk1-7\fP
1105: Similar to \*Munmark\fP,\^ but uses successive restorations of
1106: \*Mefp\fP rather than a loop.
1107: .Ip \*Mop_global\fP
1108: Dual entry points are used to deal with possible operand encoding.
1109: The operand,\^ which is a number of a variable in the global region,\^
1110: is multiplied by 8 to provide a byte offset from the start of
1111: the global region. The sum of \*MOp\fP and the value of \*Mglobals\fP
1112: is pushed on the stack to provide a descriptor address. The constant
1113: \*MD_VAR\fP is pushed on the stack to complete the descriptor for the
1114: global variable.
1115: .Ip \*Mop_static\fP
1116: Identical to \*Mop_global\fP except that \*Mstatics\fP is used
1117: instead of \*Mglobals\fP.
1118: .Ip \*Mop_local\fP
1119: The operand value is the number of a local variable for which a
1120: variable descriptor is to be pushed on the stack. Recall that the
1121: local variables lie below the procedure frame and,\^ on the VAX,\^ the
1122: descriptor for the first one is at \*M\-16(fp)\fP. \*MOp\fP is
1123: negated. The instruction
1124: .Ds
1125: pushaq -16(fp)\^[Op]
1126: .De
1127: performs the calculation
1128: .Ds
1129: -16 + fp + (Op * 8)
1130: .De
1131: which computes the address of the descriptor of the desired variable
1132: and pushes it on the stack. The variable descriptor is completed by
1133: pushing \*MD_VAR\fP on the stack.
1134: .Ip \*Mop_arg\fP
1135: Like \*Mop_local\fP,\^ but it uses \*M8(ap)\fP as the base for the
1136: address calculation and the operand value is not negated.
1137: .Ip \*Mquit\ \ \ \ \ \fP
1138: Push a 0 on the stack and call the routine \*M_c_exit\fP to terminate
1139: execution of the Icon program.
1140: .Ip \*Merr\ \ \ \ \ \fP
1141: \*Merr\fP should never be encountered during normal execution.
1142: Reaching it indicates that an invalid opcode was encountered.
1143: It need not do anything more than abort execution. On the VAX,\^
1144: it calls \*Msprintf\fP to create a string containing the invalid
1145: opcode and the \*Mipc\fP where it was encountered and then calls
1146: \*Msyserr\fP with the string as an argument.
1147: .NH 3
1148: \*Mlib/efail.s\fR
1149: .SH
1150: Overview
1151: .PP
1152: \*Mefail\fP handles the failure of an expression. When
1153: Icon evaluates an expression,\^ it tries to produce a result from it.
1154: If at some point in the evaluation of an expression the expression
1155: fails,\^ Icon resumes inactive generators in the expression in
1156: an attempt to make the expression succeed. \*Mefail\fP is at the
1157: heart of this activity.
1158: .LP
1159: \*Mefail\fP has three distinct outcomes:
1160: .Ls
1161: .Np
1162: Resumption of the newest inactive generator in the current
1163: expression frame.
1164: .Np
1165: Failure of the current expression with execution continuing
1166: at the failure address contained in the expression marker.
1167: .Np
1168: Failure of the current expression with propagation of failure
1169: to the enclosing expression frame. This is similar to (2),\^
1170: but occurs when the failure address is 0. After the current
1171: expression fails,\^ \*Mefail\fP loops back to its entry point
1172: to fail again.
1173: .Le
1174: .PP
1175: \*Mefail\fP is branched to rather than being
1176: called. This is because it
1177: serves as a ``back-end'' for several failure
1178: actions that may occur during the course of execution:
1179: .Ls
1180: .Np
1181: When a built-in procedure fails,\^ it calls the routine \*Mfail\fP,\^ which
1182: in turn branches to \*Mefail\fP.
1183: .Np
1184: When an Icon procedure fails via the \*Mpfail\fP routine,\^ \*Mpfail\fP
1185: terminates by branching to \*Mefail\fP.
1186: .Np
1187: When the \*Mefail\fP opcode is executed by the interpreter,\^ \*Mefail\fP
1188: is branched to.
1189: .Np
1190: The generator frames built by \*Mesusp\fP and \*Mlsusp\fP use \*Mefail\fP
1191: as a return address. This is explained in detail later.
1192: .Le
1193: .SH
1194: Generic Operation
1195: .PP
1196: \*Mefail\fP is essentially a simple routine. There are two separate
1197: paths of execution that \*Mefail\fP may take. The first is to
1198: resume an inactive generator. The second is to cause failure of
1199: the expression in lieu of an inactive generator.
1200: .PP
1201: If there is an inactive generator in the current expression frame,\^
1202: it must be resumed.
1203: If the generator is an Icon procedure and tracing is in on,\^
1204: \*Matrace\fP is called with appropriate arguments. \*M_k_level\fP,\^
1205: \*M_line\fP,\^ and \*M_file\fP are restored from the generator frame. A return
1206: is performed and the net result is that the stack is restored to
1207: the state that it was in before the suspension that created the
1208: generator.
1209: .PP
1210: If there are no inactive generators that can be resumed,\^ the
1211: expression being evaluated must fail. This is done by popping
1212: the stack back through the current expression frame and resuming
1213: execution at the point indicated by the failure address in
1214: the expression marker. This is a two-step process. The first
1215: is to pop the frame and the second is to resume execution.
1216: When the frame is popped,\^ the expression has failed. The
1217: failure address in the expression marker is saved before
1218: the frame is popped. If this address is not zero,\^ execution
1219: is continued by branching to the address. If the address is
1220: zero,\^ the failure is propagated to the enclosing expression by
1221: branching to efail.
1222: .PP
1223: Zero failure addresses are generated by the ucode instruction
1224: .Ds
1225: mark L0
1226: .De
1227: Such instructions are used to avoid a special case during code
1228: generation and the only purpose they serve during program execution
1229: is to create an expression marker for the corresponding
1230: \*Munmark\fP instruction to remove. (\*Mmark\fP and \*Munmark\fP
1231: instructions are paired.)
1232: Thus,\^ whenever \*Mefail\fP pops an expression whose marker has a
1233: zero failure address,\^ \*Mefail\fP causes failure in the enclosing
1234: expression.
1235: .SH
1236: \*Mefail\fP on the VAX
1237: .PP
1238: The first action is to determine if there is an inactive generator
1239: that can be reactivated. If the generator frame pointer
1240: is non-zero,\^ it points to the newest inactive generator.
1241: Note that whenever a new expression frame is created,\^ the generator
1242: frame pointer is zeroed. Thus,\^ if \*Mgfp\fP is non-zero,\^ the
1243: generator frame that it points to belongs to a generator in the
1244: current expression frame.
1245: .PP
1246: If an inactive generator is available,\^ it must be reactivated.
1247: First,\^ \*M_boundary\fP is restored from the generator frame.
1248: The stack is popped back to the generator frame by loading
1249: \*Mfp\fP from \*Mgfp\fP. But,\^ before \*Mfp\fP is loaded,\^
1250: its value is saved in \*Mr0\fP. \*Mfp\fP now points at
1251: word 0 of the generator frame,\^ but that is a word below the
1252: actual stack frame that it should be pointing at,\^ so \*Mfp\fP is
1253: incremented by 4 using a \*Mtstl\fP.
1254: .LP
1255: There are three types of generators that may be encountered
1256: by \*Mefail\fP.
1257: .Ls
1258: .Np
1259: An Icon procedure that did a \*Msuspend\fP. In such cases,\^ the
1260: routine \*Mpsusp\fP handled the suspension.
1261: .Np
1262: A built-in procedure that called the C function \*Msuspend()\fP.
1263: .Np
1264: A generator created by an \*Mesusp\fP or \*Mlsusp\fP instruction.
1265: Such generators
1266: arise from source code constructs like \*M\*(x1 |\ \^\*(x2\fP,\^ \*M|\*(xx\fR,\^ and
1267: \*M\*(x1 \e\ \^\*(x2\fR,\^ which are referred to as \fIcontrol regimes\fP.
1268: .Le
1269: .PP
1270: The generators may be treated the same way as far as resumption goes.
1271: However,\^ if an Icon procedure is being resumed,\^ a tracing message must
1272: be generated if \*M_k_trace\fP is not 0.
1273: .PP
1274: If the value of \*M_boundary\fP is not the same as \*Mfp\fP,\^ the
1275: generator is a built-in procedure and tracing is not done.
1276: If the \*Mfp\fP saved in the current frame is the same as the
1277: \*Mfp\fP was upon entry to \*Mefail\fP (the value was saved in
1278: \*Mr0\fP),\^ the generator was made by an \*Mesusp\fP or an \*Mlsusp\fP
1279: and tracing is not done.
1280: .PP
1281: Otherwise,\^ the generator is an Icon procedure,\^ and \*Matrace\fP must
1282: be called. \*Matrace\fP takes one argument,\^ the address of the
1283: procedure block for the procedure being resumed. Recall that \*(e0 on the
1284: stack is a descriptor for the procedure block. The address of
1285: \*(e0 is calculated using
1286: .Ds
1287: &\*(e0 = ap + 8 + (8 * nargs)
1288: .De
1289: The resulting address is used as the single argument for \*Matrace\fP.
1290: .PP
1291: The generator is now ready to be resumed.
1292: \*M_k_level\fP,\^ \*M_line\fP,\^ and \*M_file\fP are restored by popping them
1293: from the generator frame. If the generator is a built-in procedure,\^
1294: \*M_boundary\fP is cleared. A return is performed to activate the
1295: generator.
1296: .PP
1297: The return has different effects depending on the type of generator
1298: being resumed.
1299: .PP
1300: If the generator is a built-in procedure,\^ the return
1301: restores the stack to the state it was in before \*Msuspend\fP was
1302: called,\^ and execution proceeds at the point just after \*Msuspend()\fP.
1303: In this case the \*Mpc\fP value being returned to references an instruction
1304: in the built-in procedure.
1305: .PP
1306: If the generator is an Icon procedure,\^ the stack is restored to
1307: the state it was in before the \*Mpsusp\fP ucode instruction
1308: was executed. The \*Mpc\fP value being returned to references an
1309: instruction in the interpreter loop. Execution of the program
1310: continues with the interpreter instruction following the \*Mpsusp\fP.
1311: .PP
1312: If the generator is a control regime,\^ the stack is restored to
1313: the state it was in before the \*Mesusp\fP or \*Mlsusp\fP that
1314: created the generator was performed. The
1315: return \*Mpc\fP points to \*Mefail\fP itself. Thus,\^ when the
1316: return is done,\^ the stack is cleared,\^ and an \*Mefail\fP is performed.
1317: This has the effect of transferring control to the failure label
1318: in the expression marker of the bounding expression frame.
1319: .\"(The failure label lies at the start of code for the alternative.)
1320: .PP
1321: If there is no generator to reactivate,\^ the expression must fail.
1322: This is handled at the label \*Mnogen\fP. \*Mefp\fP points to the
1323: expression frame marker. \*Mipc\fP is loaded
1324: from \*M\-8(efp)\fP which contains the address to go to in the
1325: event that the current expression fails. (As it has.)
1326: \*Mgfp\fP is restored from the expression marker.
1327: \*Mefp\fP is restored from the marker and the marker is popped off the stack.
1328: .PP
1329: If the failure address in \*Mipc\fP is non-zero,\^ control is passed
1330: back to the interpreter via a branch and execution of the ucode
1331: resumes at the failure address. If \*Mipc\fP is zero,\^ the expression
1332: failure is transmitted to the surrounding expression frame
1333: by a branch to \*Mefail\fP. (Recall that a zero failure address
1334: comes from a \*Mmark L0\fP instruction and that a failure that
1335: reaches a \*Mmark L0\fP marker must be propagated to the next
1336: expression marker.)
1337: .NH 3
1338: \*Mlib/pfail.s\fR
1339: .SH
1340: Overview
1341: .LP
1342: \*Mpfail\fP handles the failure of an Icon procedure. An Icon
1343: procedure can fail by
1344: .Ds
1345: .ft R
1346: executing a \*Mfail\fP expression
1347: executing \*Mreturn \fIexpr\fR when \fIexpr\fR fails
1348: allowing the flow of control to reach the end of a procedure
1349: .De
1350: \*Mpfail\fP is entered via a branch when
1351: the interpreter encounters the \*Mpfail\fP instruction.
1352: .SH
1353: Generic Operation
1354: .PP
1355: The task of \*Mpfail\fP is to signal failure in the expression that
1356: contains the procedure call being evaluated. This is done
1357: by removing the Icon procedure frame from the stack,\^ restoring
1358: appropriate registers and values,\^ and calling \*Mefail\fP. The key is that
1359: all \*Mpfail\fP needs to do is to remove the procedure frame
1360: from the stack and from then on things can be handled just like expression
1361: failure.
1362: Thus,\^ \*Mefail\fP does most of the work.
1363: .PP
1364: \*Mpfail\fP calls \*Mftrace\fP to produce a trace message if
1365: tracing is on. \*Mpfail\fP also decrements \*M_k_level\fP because
1366: a procedure is being exited.
1367: .PP
1368: Note that the procedure frame on the stack is a frame that
1369: was created by \*Minvoke\fP.
1370: .SH
1371: \*Mpfail\fP on the VAX
1372: .PP
1373: After \*M_k_level\fP is decremented,\^ \*M_k_trace\fP is checked to
1374: see if a trace message should be produced. If tracing is on,\^
1375: \*Mftrace\fP must be called. \*Mftrace\fP takes one argument,\^
1376: the address of the procedure block for the failing procedure.
1377: \*(e0 is the descriptor for the procedure block,\^ and the address
1378: of \*(e0 is calculated using
1379: .Ds
1380: &\*(e0 = (\fInargs\fP * 8) + 8 + ap
1381: .De
1382: The resulting address is pushed on the stack and \*Mftrace\fP is
1383: called.
1384: .PP
1385: Execution continues at \*Mdofail\fP to remove the procedure frame
1386: from the stack. The frame cannot be merely popped because it
1387: contains state information that must be restored. \*M_line\fP and
1388: \*M_file\fP are extracted from the frame. \*Mefp\fP,\^ \*Mgfp\fP,\^ and
1389: \*Mipc\fP are restored from the frame using addresses
1390: relative to \*Map\fP. Note that this works because \*Minvoke\fP saves
1391: these registers and their location is known.
1392: .PP
1393: \*Map\fP and \*Mfp\fP are restored from the frame. When \*Mfp\fP is
1394: restored,\^ it serves to remove the procedure frame (made by
1395: \*Minvoke\fP) from the stack. At this point,\^ the stack is the
1396: same state it was in before the interpreter performed the
1397: \*Minvoke\fP instruction. A branch is made to \*Mefail\fP to
1398: cause failure in the enclosing expression.
1399: .NH 2
1400: Testing the Basis
1401: .PP
1402: At this point,\^ enough of the system has been written to run some
1403: very simple Icon
1404: programs. \*Mtest/hello.icn\fP should be functional
1405: and more complete testing is in order. Refer to \fITesting the
1406: Basis\fP in \^[5].
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.