--- a+++ b/doc/cmucl/internals/fasl.tex@@ -0,0 +1,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}