[a530bb]: doc / cmucl / internals / fasl.tex Maximize Restore History

Download this file

fasl.tex    585 lines (489 with data), 31.6 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
\chapter{Fasload File Format}% -*- Dictionary: design -*-
\section{General}
The purpose of Fasload files is to allow concise storage and rapid
loading of Lisp data, particularly function definitions. The intent
is that loading a Fasload file has the same effect as loading the
ASCII file from which the Fasload file was compiled, but accomplishes
the tasks more efficiently. One noticeable difference, of course, is
that function definitions may be in compiled form rather than
S-expression form. Another is that Fasload files may specify in what
parts of memory the Lisp data should be allocated. For example,
constant lists used by compiled code may be regarded as read-only.
In some Lisp implementations, Fasload file formats are designed to
allow sharing of code parts of the file, possibly by direct mapping
of pages of the file into the address space of a process. This
technique produces great performance improvements in a paged
time-sharing system. Since the Mach project is to produce a
distributed personal-computer network system rather than a
time-sharing system, efficiencies of this type are explicitly {\it not}
a goal for the CMU Common Lisp Fasload file format.
On the other hand, CMU Common Lisp is intended to be portable, as it will
eventually run on a variety of machines. Therefore an explicit goal
is that Fasload files shall be transportable among various
implementations, to permit efficient distribution of programs in
compiled form. The representations of data objects in Fasload files
shall be relatively independent of such considerations as word
length, number of type bits, and so on. If two implementations
interpret the same macrocode (compiled code format), then Fasload
files should be completely compatible. If they do not, then files
not containing compiled code (so-called "Fasdump" data files) should
still be compatible. While this may lead to a format which is not
maximally efficient for a particular implementation, the sacrifice of
a small amount of performance is deemed a worthwhile price to pay to
achieve portability.
The primary assumption about data format compatibility is that all
implementations can support I/O on finite streams of eight-bit bytes.
By "finite" we mean that a definite end-of-file point can be detected
irrespective of the content of the data stream. A Fasload file will
be regarded as such a byte stream.
\section{Strategy}
A Fasload file may be regarded as a human-readable prefix followed by
code in a funny little language. When interpreted, this code will
cause the construction of the encoded data structures. The virtual
machine which interprets this code has a {\it stack} and a {\it table},
both initially empty. The table may be thought of as an expandable
register file; it is used to remember quantities which are needed
more than once. The elements of both the stack and the table are
Lisp data objects. Operators of the funny language may take as
operands following bytes of the data stream, or items popped from the
stack. Results may be pushed back onto the stack or pushed onto the
table. The table is an indexable stack that is never popped; it is
indexed relative to the base, not the top, so that an item once
pushed always has the same index.
More precisely, a Fasload file has the following macroscopic
organization. It is a sequence of zero or more groups concatenated
together. End-of-file must occur at the end of the last group. Each
group begins with a series of seven-bit ASCII characters terminated
by one or more bytes of all ones \verb|#xFF|; this is called the
{\it header}. Following the bytes which terminate the header is the
{\it body}, a stream of bytes in the funny binary language. The body
of necessity begins with a byte other than \verb|#xFF|. The body is
terminated by the operation {\tt FOP-END-GROUP}.
The first nine characters of the header must be "{\tt FASL FILE}" in
upper-case letters. The rest may be any ASCII text, but by
convention it is formatted in a certain way. The header is divided
into lines, which are grouped into paragraphs. A paragraph begins
with a line which does {\it not} begin with a space or tab character,
and contains all lines up to, but not including, the next such line.
The first word of a paragraph, defined to be all characters up to but
not including the first space, tab, or end-of-line character, is the
{\it name} of the paragraph. A Fasload file header might look something like
this:
\begin{verbatim}
FASL FILE >SteelesPerq>User>Guy>IoHacks>Pretty-Print.Slisp
Package Pretty-Print
Compiled 31-Mar-1988 09:01:32 by some random luser
Compiler Version 1.6, Lisp Version 3.0.
Functions: INITIALIZE DRIVER HACK HACK1 MUNGE MUNGE1 GAZORCH
MINGLE MUDDLE PERTURB OVERDRIVE GOBBLE-KEYBOARD
FRY-USER DROP-DEAD HELP CLEAR-MICROCODE
%AOS-TRIANGLE %HARASS-READTABLE-MAYBE
Macros: PUSH POP FROB TWIDDLE
\end{verbatim}
{\it one or more bytes of \verb|#xFF|}
The particular paragraph names and contents shown here are only intended as
suggestions.
\section{Fasload Language}
Each operation in the binary Fasload language is an eight-bit
(one-byte) opcode. Each has a name beginning with "{\tt FOP-}". In
the following descriptions, the name is followed by operand
descriptors. Each descriptor denotes operands that follow the opcode
in the input stream. A quantity in parentheses indicates the number
of bytes of data from the stream making up the operand. Operands
which implicitly come from the stack are noted in the text. The
notation "$\Rightarrow$ stack" means that the result is pushed onto the
stack; "$\Rightarrow$ table" similarly means that the result is added to the
table. A construction like "{\it n}(1) {\it value}({\it n})" means that
first a single byte {\it n} is read from the input stream, and this
byte specifies how many bytes to read as the operand named {\it value}.
All numeric values are unsigned binary integers unless otherwise
specified. Values described as "signed" are in two's-complement form
unless otherwise specified. When an integer read from the stream
occupies more than one byte, the first byte read is the least
significant byte, and the last byte read is the most significant (and
contains the sign bit as its high-order bit if the entire integer is
signed).
Some of the operations are not necessary, but are rather special
cases of or combinations of others. These are included to reduce the
size of the file or to speed up important cases. As an example,
nearly all strings are less than 256 bytes long, and so a special
form of string operation might take a one-byte length rather than a
four-byte length. As another example, some implementations may
choose to store bits in an array in a left-to-right format within
each word, rather than right-to-left. The Fasload file format may
support both formats, with one being significantly more efficient
than the other for a given implementation. The compiler for any
implementation may generate the more efficient form for that
implementation, and yet compatibility can be maintained by requiring
all implementations to support both formats in Fasload files.
Measurements are to be made to determine which operation codes are
worthwhile; little-used operations may be discarded and new ones
added. After a point the definition will be "frozen", meaning that
existing operations may not be deleted (though new ones may be added;
some operations codes will be reserved for that purpose).
\begin{description}
\item[0:] \hspace{2em} {\tt FOP-NOP} \\
No operation. (This is included because it is recognized
that some implementations may benefit from alignment of operands to some
operations, for example to 32-bit boundaries. This operation can be used
to pad the instruction stream to a desired boundary.)
\item[1:] \hspace{2em} {\tt FOP-POP} \hspace{2em} $\Rightarrow$ \hspace{2em} table \\
One item is popped from the stack and added to the table.
\item[2:] \hspace{2em} {\tt FOP-PUSH} \hspace{2em} {\it index}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
Item number {\it index} of the table is pushed onto the stack.
The first element of the table is item number zero.
\item[3:] \hspace{2em} {\tt FOP-BYTE-PUSH} \hspace{2em} {\it index}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
Item number {\it index} of the table is pushed onto the stack.
The first element of the table is item number zero.
\item[4:] \hspace{2em} {\tt FOP-EMPTY-LIST} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The empty list ({\tt ()}) is pushed onto the stack.
\item[5:] \hspace{2em} {\tt FOP-TRUTH} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The standard truth value ({\tt T}) is pushed onto the stack.
\item[6:] \hspace{2em} {\tt FOP-SYMBOL-SAVE} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
The four-byte operand {\it n} specifies the length of the print name
of a symbol. The name follows, one character per byte,
with the first byte of the print name being the first read.
The name is interned in the default package,
and the resulting symbol is both pushed onto the stack and added to the table.
\item[7:] \hspace{2em} {\tt FOP-SMALL-SYMBOL-SAVE} \hspace{2em} {\it n}(1) \hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
The one-byte operand {\it n} specifies the length of the print name
of a symbol. The name follows, one character per byte,
with the first byte of the print name being the first read.
The name is interned in the default package,
and the resulting symbol is both pushed onto the stack and added to the table.
\item[8:] \hspace{2em} {\tt FOP-SYMBOL-IN-PACKAGE-SAVE} \hspace{2em} {\it index}(4)
\hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
The four-byte {\it index} specifies a package stored in the table.
The four-byte operand {\it n} specifies the length of the print name
of a symbol. The name follows, one character per byte,
with the first byte of the print name being the first read.
The name is interned in the specified package,
and the resulting symbol is both pushed onto the stack and added to the table.
\item[9:] \hspace{2em} {\tt FOP-SMALL-SYMBOL-IN-PACKAGE-SAVE} \hspace{2em} {\it index}(4)
\hspace{2em} {\it n}(1) \hspace{2em} {\it name}({\it n}) \hspace{2em}
$\Rightarrow$ \hspace{2em} stack \& table\\
The four-byte {\it index} specifies a package stored in the table.
The one-byte operand {\it n} specifies the length of the print name
of a symbol. The name follows, one character per byte,
with the first byte of the print name being the first read.
The name is interned in the specified package,
and the resulting symbol is both pushed onto the stack and added to the table.
\item[10:] \hspace{2em} {\tt FOP-SYMBOL-IN-BYTE-PACKAGE-SAVE} \hspace{2em} {\it index}(1)
\hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
The one-byte {\it index} specifies a package stored in the table.
The four-byte operand {\it n} specifies the length of the print name
of a symbol. The name follows, one character per byte,
with the first byte of the print name being the first read.
The name is interned in the specified package,
and the resulting symbol is both pushed onto the stack and added to the table.
\item[11:]\hspace{2em} {\tt FOP-SMALL-SYMBOL-IN-BYTE-PACKAGE-SAVE} \hspace{2em} {\it index}(1)
\hspace{2em} {\it n}(1) \hspace{2em} {\it name}({\it n}) \hspace{2em}
$\Rightarrow$ \hspace{2em} stack \& table\\
The one-byte {\it index} specifies a package stored in the table.
The one-byte operand {\it n} specifies the length of the print name
of a symbol. The name follows, one character per byte,
with the first byte of the print name being the first read.
The name is interned in the specified package,
and the resulting symbol is both pushed onto the stack and added to the table.
\item[12:] \hspace{2em} {\tt FOP-UNINTERNED-SYMBOL-SAVE} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
Like {\tt FOP-SYMBOL-SAVE}, except that it creates an uninterned symbol.
\item[13:] \hspace{2em} {\tt FOP-UNINTERNED-SMALL-SYMBOL-SAVE} \hspace{2em} {\it n}(1)
\hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack
\& table\\
Like {\tt FOP-SMALL-SYMBOL-SAVE}, except that it creates an uninterned symbol.
\item[14:] \hspace{2em} {\tt FOP-PACKAGE} \hspace{2em} $\Rightarrow$ \hspace{2em} table \\
An item is popped from the stack; it must be a symbol. The package of
that name is located and pushed onto the table.
\item[15:] \hspace{2em} {\tt FOP-LIST} \hspace{2em} {\it length}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The unsigned operand {\it length} specifies a number of
operands to be popped from the stack. These are made into a list
of that length, and the list is pushed onto the stack.
The first item popped from the stack becomes the last element of
the list, and so on. Hence an iterative loop can start with
the empty list and perform "pop an item and cons it onto the list"
{\it length} times.
(Lists of length greater than 255 can be made by using {\tt FOP-LIST*}
repeatedly.)
\item[16:] \hspace{2em} {\tt FOP-LIST*} \hspace{2em} {\it length}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
This is like {\tt FOP-LIST} except that the constructed list is terminated
not by {\tt ()} (the empty list), but by an item popped from the stack
before any others are. Therefore {\it length}+1 items are popped in all.
Hence an iterative loop can start with
a popped item and perform "pop an item and cons it onto the list"
{\it length}+1 times.
\item[17-24:] \hspace{2em} {\tt FOP-LIST-1}, {\tt FOP-LIST-2}, ..., {\tt FOP-LIST-8} \\
{\tt FOP-LIST-{\it k}} is like {\tt FOP-LIST} with a byte containing {\it k}
following it. These exist purely to reduce the size of Fasload files.
Measurements need to be made to determine the useful values of {\it k}.
\item[25-32:] \hspace{2em} {\tt FOP-LIST*-1}, {\tt FOP-LIST*-2}, ..., {\tt FOP-LIST*-8} \\
{\tt FOP-LIST*-{\it k}} is like {\tt FOP-LIST*} with a byte containing {\it k}
following it. These exist purely to reduce the size of Fasload files.
Measurements need to be made to determine the useful values of {\it k}.
\item[33:] \hspace{2em} {\tt FOP-INTEGER} \hspace{2em} {\it n}(4) \hspace{2em} {\it value}({\it n}) \hspace{2em}
$\Rightarrow$ \hspace{2em} stack \\
A four-byte unsigned operand specifies the number of following
bytes. These bytes define the value of a signed integer in two's-complement
form. The first byte of the value is the least significant byte.
\item[34:] \hspace{2em} {\tt FOP-SMALL-INTEGER} \hspace{2em} {\it n}(1) \hspace{2em} {\it value}({\it n})
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
A one-byte unsigned operand specifies the number of following
bytes. These bytes define the value of a signed integer in two's-complement
form. The first byte of the value is the least significant byte.
\item[35:] \hspace{2em} {\tt FOP-WORD-INTEGER} \hspace{2em} {\it value}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
A four-byte signed integer (in the range $-2^{31}$ to $2^{31}-1$) follows the
operation code. A LISP integer (fixnum or bignum) with that value
is constructed and pushed onto the stack.
\item[36:] \hspace{2em} {\tt FOP-BYTE-INTEGER} \hspace{2em} {\it value}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
A one-byte signed integer (in the range -128 to 127) follows the
operation code. A LISP integer (fixnum or bignum) with that value
is constructed and pushed onto the stack.
\item[37:] \hspace{2em} {\tt FOP-STRING} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The four-byte operand {\it n} specifies the length of a string to
construct. The characters of the string follow, one per byte.
The constructed string is pushed onto the stack.
\item[38:] \hspace{2em} {\tt FOP-SMALL-STRING} \hspace{2em} {\it n}(1) \hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The one-byte operand {\it n} specifies the length of a string to
construct. The characters of the string follow, one per byte.
The constructed string is pushed onto the stack.
\item[39:] \hspace{2em} {\tt FOP-VECTOR} \hspace{2em} {\it n}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The four-byte operand {\it n} specifies the length of a vector of LISP objects
to construct. The elements of the vector are popped off the stack;
the first one popped becomes the last element of the vector.
The constructed vector is pushed onto the stack.
\item[40:] \hspace{2em} {\tt FOP-SMALL-VECTOR} \hspace{2em} {\it n}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The one-byte operand {\it n} specifies the length of a vector of LISP objects
to construct. The elements of the vector are popped off the stack;
the first one popped becomes the last element of the vector.
The constructed vector is pushed onto the stack.
\item[41:] \hspace{2em} {\tt FOP-UNIFORM-VECTOR} \hspace{2em} {\it n}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The four-byte operand {\it n} specifies the length of a vector of LISP objects
to construct. A single item is popped from the stack and used to initialize
all elements of the vector. The constructed vector is pushed onto the stack.
\item[42:] \hspace{2em} {\tt FOP-SMALL-UNIFORM-VECTOR} \hspace{2em} {\it n}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The one-byte operand {\it n} specifies the length of a vector of LISP objects
to construct. A single item is popped from the stack and used to initialize
all elements of the vector. The constructed vector is pushed onto the stack.
\item[43:] \hspace{2em} {\tt FOP-INT-VECTOR} \hspace{2em} {\it len}(4) \hspace{2em}
{\it size}(1) \hspace{2em} {\it data}($\left\lceil len*count/8\right\rceil$)
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The four-byte operand {\it n} specifies the length of a vector of
unsigned integers to be constructed. Each integer is {\it size}
bits long, and is packed according to the machine's native byte ordering.
{\it size} must be a directly supported i-vector element size. Currently
supported values are 1,2,4,8,16 and 32.
\item[44:] \hspace{2em} {\tt FOP-UNIFORM-INT-VECTOR} \hspace{2em} {\it n}(4) \hspace{2em} {\it size}(1) \hspace{2em}
{\it value}(@ceiling<{\it size}/8>) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The four-byte operand {\it n} specifies the length of a vector of unsigned
integers to construct.
Each integer is {\it size} bits big, and is initialized to the value
of the operand {\it value}.
The constructed vector is pushed onto the stack.
\item[45:] Unused
\item[46:] \hspace{2em} {\tt FOP-SINGLE-FLOAT} \hspace{2em} {\it data}(4) \hspace{2em}
$\Rightarrow$ \hspace{2em} stack \\
The {\it data} bytes are read as an integer, then turned into an IEEE single
float (as though by {\tt make-single-float}).
\item[47:] \hspace{2em} {\tt FOP-DOUBLE-FLOAT} \hspace{2em} {\it data}(8) \hspace{2em}
$\Rightarrow$ \hspace{2em} stack \\
The {\it data} bytes are read as an integer, then turned into an IEEE double
float (as though by {\tt make-double-float}).
\item[48:] \hspace{2em} {\tt FOP-STRUCT} \hspace{2em} {\it n}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The four-byte operand {\it n} specifies the length structure to construct. The
elements of the vector are popped off the stack; the first one popped becomes
the last element of the structure. The constructed vector is pushed onto the
stack.
\item[49:] \hspace{2em} {\tt FOP-SMALL-STRUCT} \hspace{2em} {\it n}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The one-byte operand {\it n} specifies the length structure to construct. The
elements of the vector are popped off the stack; the first one popped becomes
the last element of the structure. The constructed vector is pushed onto the
stack.
\item[50-52:] Unused
\item[53:] \hspace{2em} {\tt FOP-EVAL} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
Pop an item from the stack and evaluate it (give it to {\tt EVAL}).
Push the result back onto the stack.
\item[54:] \hspace{2em} {\tt FOP-EVAL-FOR-EFFECT} \\
Pop an item from the stack and evaluate it (give it to {\tt EVAL}).
The result is ignored.
\item[55:] \hspace{2em} {\tt FOP-FUNCALL} \hspace{2em} {\it nargs}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
Pop {\it nargs}+1 items from the stack and apply the last one popped
as a function to
all the rest as arguments (the first one popped being the last argument).
Push the result back onto the stack.
\item[56:] \hspace{2em} {\tt FOP-FUNCALL-FOR-EFFECT} \hspace{2em} {\it nargs}(1) \\
Pop {\it nargs}+1 items from the stack and apply the last one popped
as a function to
all the rest as arguments (the first one popped being the last argument).
The result is ignored.
\item[57:] \hspace{2em} {\tt FOP-CODE-FORMAT} \hspace{2em} {\it implementation}(1)
\hspace{2em} {\it version}(1) \\
This FOP specifiers the code format for following code objects. The operations
{\tt FOP-CODE} and its relatives may not occur in a group until after {\tt
FOP-CODE-FORMAT} has appeared; there is no default format. The {\it
implementation} is an integer indicating the target hardware and environment.
See {\tt compiler/generic/vm-macs.lisp} for the currently defined
implementations. {\it version} for an implementation is increased whenever
there is a change that renders old fasl files unusable.
\item[58:] \hspace{2em} {\tt FOP-CODE} \hspace{2em} {\it nitems}(4) \hspace{2em} {\it size}(4) \hspace{2em}
{\it code}({\it size}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
A compiled function is constructed and pushed onto the stack.
This object is in the format specified by the most recent
occurrence of {\tt FOP-CODE-FORMAT}.
The operand {\it nitems} specifies a number of items to pop off
the stack to use in the "boxed storage" section. The operand {\it code}
is a string of bytes constituting the compiled executable code.
\item[59:] \hspace{2em} {\tt FOP-SMALL-CODE} \hspace{2em} {\it nitems}(1) \hspace{2em} {\it size}(2) \hspace{2em}
{\it code}({\it size}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
A compiled function is constructed and pushed onto the stack.
This object is in the format specified by the most recent
occurrence of {\tt FOP-CODE-FORMAT}.
The operand {\it nitems} specifies a number of items to pop off
the stack to use in the "boxed storage" section. The operand {\it code}
is a string of bytes constituting the compiled executable code.
\item[60-61:] Unused
\item[62:] \hspace{2em} {\tt FOP-VERIFY-TABLE-SIZE} \hspace{2em} {\it size}(4) \\
If the current size of the table is not equal to {\it size},
then an inconsistency has been detected. This operation
is inserted into a Fasload file purely for error-checking purposes.
It is good practice for a compiler to output this at least at the
end of every group, if not more often.
\item[63:] \hspace{2em} {\tt FOP-VERIFY-EMPTY-STACK} \\
If the stack is not currently empty,
then an inconsistency has been detected. This operation
is inserted into a Fasload file purely for error-checking purposes.
It is good practice for a compiler to output this at least at the
end of every group, if not more often.
\item[64:] \hspace{2em} {\tt FOP-END-GROUP} \\
This is the last operation of a group. If this is not the
last byte of the file, then a new group follows; the next
nine bytes must be "{\tt FASL FILE}".
\item[65:] \hspace{2em} {\tt FOP-POP-FOR-EFFECT} \hspace{2em} stack \hspace{2em} $\Rightarrow$ \hspace{2em} \\
One item is popped from the stack.
\item[66:] \hspace{2em} {\tt FOP-MISC-TRAP} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
A trap object is pushed onto the stack.
\item[67:] Unused
\item[68:] \hspace{2em} {\tt FOP-CHARACTER} \hspace{2em} {\it character}(3) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
The three bytes are read as an integer then converted to a character. This FOP
is currently rather useless, as extended characters are not supported.
\item[69:] \hspace{2em} {\tt FOP-SHORT-CHARACTER} \hspace{2em} {\it character}(1) \hspace{2em}
$\Rightarrow$ \hspace{2em} stack \\
The one byte specifies the code of a Common Lisp character object. A character
is constructed and pushed onto the stack.
\item[70:] \hspace{2em} {\tt FOP-RATIO} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
Creates a ratio from two integers popped from the stack.
The denominator is popped first, the numerator second.
\item[71:] \hspace{2em} {\tt FOP-COMPLEX} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
Creates a complex number from two numbers popped from the stack.
The imaginary part is popped first, the real part second.
\item[72-73:] Unused
\item[74:] \hspace{2em} {\tt FOP-FSET} \hspace{2em} \\
Except in the cold loader (Genesis), this is a no-op with two stack arguments.
In the initial core this is used to make DEFUN functions defined at cold-load
time so that global functions can be called before top-level forms are run
(which normally installs definitions.) Genesis pops the top two things off of
the stack and effectively does (SETF SYMBOL-FUNCTION).
\item[75:] \hspace{2em} {\tt FOP-LISP-SYMBOL-SAVE} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
Like {\tt FOP-SYMBOL-SAVE}, except that it creates a symbol in the LISP
package.
\item[76:] \hspace{2em} {\tt FOP-LISP-SMALL-SYMBOL-SAVE} \hspace{2em} {\it n}(1)
\hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack
\& table\\
Like {\tt FOP-SMALL-SYMBOL-SAVE}, except that it creates a symbol in the LISP
package.
\item[77:] \hspace{2em} {\tt FOP-KEYWORD-SYMBOL-SAVE} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
Like {\tt FOP-SYMBOL-SAVE}, except that it creates a symbol in the
KEYWORD package.
\item[78:] \hspace{2em} {\tt FOP-KEYWORD-SMALL-SYMBOL-SAVE} \hspace{2em} {\it n}(1)
\hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack
\& table\\
Like {\tt FOP-SMALL-SYMBOL-SAVE}, except that it creates a symbol in the
KEYWORD package.
\item[79-80:] Unused
\item[81:] \hspace{2em} {\tt FOP-NORMAL-LOAD}\\
This FOP is used in conjunction with the cold loader (Genesis) to read
top-level package manipulation forms. These forms are to be read as though by
the normal loaded, so that they can be evaluated at cold load time, instead of
being dumped into the initial core image. A no-op in normal loading.
\item[82:] \hspace{2em} {\tt FOP-MAYBE-COLD-LOAD}\\
Undoes the effect of {\tt FOP-NORMAL-LOAD}.
\item[83:] \hspace{2em} {\tt FOP-ARRAY} \hspace{2em} {\it rank}(4)
\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
This operation creates a simple array header (used for simple-arrays with rank
/= 1). The data vector is popped off of the stack, and then {\it rank}
dimensions are popped off of the stack (the highest dimensions is on top.)
\item[84-139:] Unused
\item[140:] \hspace{2em} {\tt FOP-ALTER-CODE} \hspace{2em} {\it index}(4)\\
This operation modifies the constants part of a code object (necessary for
creating certain circular function references.) It pops the new value and code
object are off of the stack, storing the new value at the specified index.
\item[141:] \hspace{2em} {\tt FOP-BYTE-ALTER-CODE} \hspace{2em} {\it index}(1)\\
Like {\tt FOP-ALTER-CODE}, but has only a one byte offset.
\item[142:] \hspace{2em} {\tt FOP-FUNCTION-ENTRY} \hspace{2em} {\it index}(4)
\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
Initializes a function-entry header inside of a pre-existing code object, and
returns the corresponding function descriptor. {\it index} is the byte offset
inside of the code object where the header should be plunked down. The stack
arguments to this operation are the code object, function name, function debug
arglist and function type.
\item[143:] Unused
\item[144:] \hspace{2em} {\tt FOP-ASSEMBLER-CODE} \hspace{2em} {\it length}(4)
\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
This operation creates a code object holding assembly routines. {\it length}
bytes of code are read and placed in the code object, and the code object
descriptor is pushed on the stack. This FOP is only recognized by the cold
loader (Genesis.)
\item[145:] \hspace{2em} {\tt FOP-ASSEMBLER-ROUTINE} \hspace{2em} {\it offset}(4)
\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
This operation records an entry point into an assembler code object (for use
with {\tt FOP-ASSEMBLER-FIXUP}). The routine name (a symbol) is on stack top.
The code object is underneath. The entry point is defined at {\it offset}
bytes inside the code area of the code object, and the code object is left on
stack top (allowing multiple uses of this FOP to be chained.) This FOP is only
recognized by the cold loader (Genesis.)
\item[146:] Unused
\item[147:] \hspace{2em} {\tt FOP-FOREIGN-FIXUP} \hspace{2em} {\it len}(1)
\hspace{2em} {\it name}({\it len})
\hspace{2em} {\it offset}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
This operation resolves a reference to a foreign (C) symbol. {\it len} bytes
are read and interpreted as the symbol {\it name}. First the {\it kind} and the
code-object to patch are popped from the stack. The kind is a target-dependent
symbol indicating the instruction format of the patch target (at {\it offset}
bytes from the start of the code area.) The code object is left on
stack top (allowing multiple uses of this FOP to be chained.)
\item[148:] \hspace{2em} {\tt FOP-ASSEMBLER-FIXUP} \hspace{2em} {\it offset}(4)
\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
This operation resolves a reference to an assembler routine. The stack args
are ({\it routine-name}, {\it kind} and {\it code-object}). The kind is a
target-dependent symbol indicating the instruction format of the patch target
(at {\it offset} bytes from the start of the code area.) The code object is
left on stack top (allowing multiple uses of this FOP to be chained.)
\item[149-199:] Unused
\item[200:] \hspace{2em} {\tt FOP-RPLACA} \hspace{2em} {\it table-idx}(4)
\hspace{2em} {\it cdr-offset}(4)\\
\item[201:] \hspace{2em} {\tt FOP-RPLACD} \hspace{2em} {\it table-idx}(4)
\hspace{2em} {\it cdr-offset}(4)\\
These operations destructively modify a list entered in the table. {\it
table-idx} is the table entry holding the list, and {\it cdr-offset} designates
the cons in the list to modify (like the argument to {\tt nthcdr}.) The new
value is popped off of the stack, and stored in the {\tt car} or {\tt cdr},
respectively.
\item[202:] \hspace{2em} {\tt FOP-SVSET} \hspace{2em} {\it table-idx}(4)
\hspace{2em} {\it vector-idx}(4)\\
Destructively modifies a {\tt simple-vector} entered in the table. Pops the
new value off of the stack, and stores it in the {\it vector-idx} element of
the contents of the table entry {\it table-idx.}
\item[203:] \hspace{2em} {\tt FOP-NTHCDR} \hspace{2em} {\it cdr-offset}(4)
\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
Does {\tt nthcdr} on the top-of stack, leaving the result there.
\item[204:] \hspace{2em} {\tt FOP-STRUCTSET} \hspace{2em} {\it table-idx}(4)
\hspace{2em} {\it vector-idx}(4)\\
Like {\tt FOP-SVSET}, except it alters structure slots.
\item[255:] \hspace{2em} {\tt FOP-END-HEADER} \\ Indicates the end of a group header,
as described above.
\end{description}