Previous: , Up: Fasload File Format   [Contents]


45.3 Fasload Language

Each operation in the binary Fasload language is an eight-bit (one-byte) opcode. Each has a name beginning with “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 “⇒ stack” means that the result is pushed onto the stack; “⇒ table” similarly means that the result is added to the table. A construction like “n(1) value(n)” means that first a single byte n is read from the input stream, and this byte specifies how many bytes to read as the operand named 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).

0: 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.)

1: FOP-POP ⇒ table

One item is popped from the stack and added to the table.

2: FOP-PUSH index(4) ⇒ stack

Item number index of the table is pushed onto the stack. The first element of the table is item number zero.

3: FOP-BYTE-PUSH index(1) ⇒ stack

Item number index of the table is pushed onto the stack. The first element of the table is item number zero.

4: FOP-EMPTY-LIST ⇒ stack

The empty list (()) is pushed onto the stack.

5: FOP-TRUTH ⇒ stack

The standard truth value (T) is pushed onto the stack.

6: FOP-SYMBOL-SAVE n(4) name(n)

⇒ stack & table The four-byte operand 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.

7: FOP-SMALL-SYMBOL-SAVE n(1) name(n) ⇒ stack & table

The one-byte operand 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.

8: FOP-SYMBOL-IN-PACKAGE-SAVE index(4)

n(4) name(n) ⇒ stack & table The four-byte index specifies a package stored in the table. The four-byte operand 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.

9: FOP-SMALL-SYMBOL-IN-PACKAGE-SAVE index(4)

n(1) name(n) ⇒ stack & table The four-byte index specifies a package stored in the table. The one-byte operand 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.

10: FOP-SYMBOL-IN-BYTE-PACKAGE-SAVE index(1)

n(4) name(n) ⇒ stack & table The one-byte index specifies a package stored in the table. The four-byte operand 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.

11: FOP-SMALL-SYMBOL-IN-BYTE-PACKAGE-SAVE index(1) n(1) name(n) ⇒ stack & table

The one-byte index specifies a package stored in the table. The one-byte operand 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.

12: FOP-UNINTERNED-SYMBOL-SAVE n(4) name(n) ⇒ stack & table

Like FOP-SYMBOL-SAVE, except that it creates an uninterned symbol.

13: FOP-UNINTERNED-SMALL-SYMBOL-SAVE n(1) name(n) ⇒ stack & table

Like FOP-SMALL-SYMBOL-SAVE, except that it creates an uninterned symbol.

14: FOP-PACKAGE ⇒ 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.

15: FOP-LIST length(1) ⇒ stack

The unsigned operand 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” length times. (Lists of length greater than 255 can be made by using FOP-LIST* repeatedly.)

16: FOP-LIST* length(1) ⇒ stack

This is like FOP-LIST except that the constructed list is terminated not by () (the empty list), but by an item popped from the stack before any others are. Therefore 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” length+1 times.

17-24: FOP-LIST-1, FOP-LIST-2, ..., FOP-LIST-8

FOP-LIST-k is like FOP-LIST with a byte containing k following it. These exist purely to reduce the size of Fasload files. Measurements need to be made to determine the useful values of k.

25-32: FOP-LIST*-1, FOP-LIST*-2, ..., FOP-LIST*-8

FOP-LIST*-k is like FOP-LIST* with a byte containing k following it. These exist purely to reduce the size of Fasload files. Measurements need to be made to determine the useful values of k.

33: FOP-INTEGER n(4) value(n)

⇒ 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.

34: FOP-SMALL-INTEGER n(1) value(n)

⇒ 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.

35: FOP-WORD-INTEGER value(4) ⇒ 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.

36: FOP-BYTE-INTEGER value(1) ⇒ 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.

37: FOP-STRING n(4) name(n)

⇒ stack The four-byte operand 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.

38: FOP-SMALL-STRING n(1) name(n) ⇒ stack

The one-byte operand 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.

39: FOP-VECTOR n(4) ⇒ stack

The four-byte operand 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.

40: FOP-SMALL-VECTOR n(1) ⇒ stack

The one-byte operand 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.

41: FOP-UNIFORM-VECTOR n(4) ⇒ stack

The four-byte operand 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.

42: FOP-SMALL-UNIFORM-VECTOR n(1) ⇒ stack

The one-byte operand 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.

43: FOP-INT-VECTOR len(4) size(1) data(\left\lceil len*count/8\right\rceil ⇒ stack

The four-byte operand n specifies the length of a vector of unsigned integers to be constructed. Each integer is size bits long, and is packed according to the machine’s native byte ordering. size must be a directly supported i-vector element size. Currently supported values are 1,2,4,8,16 and 32.

44: FOP-UNIFORM-INT-VECTOR n(4) size(1) value(\lceil size/8\rceil) ⇒ stack

The four-byte operand n specifies the length of a vector of unsigned integers to construct. Each integer is size bits big, and is initialized to the value of the operand value. The constructed vector is pushed onto the stack.

45: FOP-LAYOUT

Pops the stack four times to get the name, length, inheritance and depth for a layout object.

46: FOP-SINGLE-FLOAT data(4)

⇒ stack The data bytes are read as an integer, then turned into an IEEE single float (as though by make-single-float).

47: FOP-DOUBLE-FLOAT data(8)

⇒ stack The data bytes are read as an integer, then turned into an IEEE double float (as though by make-double-float).

48: FOP-STRUCT n(4) ⇒ stack

The four-byte operand 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.

49: FOP-SMALL-STRUCT n(1) ⇒ stack

The one-byte operand 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.

50-52: Unused
53: FOP-EVAL ⇒ stack

Pop an item from the stack and evaluate it (give it to EVAL). Push the result back onto the stack.

54: FOP-EVAL-FOR-EFFECT

Pop an item from the stack and evaluate it (give it to EVAL). The result is ignored.

55: FOP-FUNCALL nargs(1) ⇒ stack

Pop 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.

56: FOP-FUNCALL-FOR-EFFECT nargs(1)

Pop 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.

57: FOP-CODE-FORMAT implementation(1)

version(1) This FOP specifiers the code format for following code objects. The operations FOP-CODE and its relatives may not occur in a group until after FOP-CODE-FORMAT has appeared; there is no default format. The implementation is an integer indicating the target hardware and environment. See compiler/generic/vm-macs.lisp for the currently defined implementations. version for an implementation is increased whenever there is a change that renders old fasl files unusable.

58: FOP-CODE nitems(4) size(4)

code(size) ⇒ stack A compiled function is constructed and pushed onto the stack. This object is in the format specified by the most recent occurrence of FOP-CODE-FORMAT. The operand nitems specifies a number of items to pop off the stack to use in the “boxed storage” section. The operand code is a string of bytes constituting the compiled executable code.

59: FOP-SMALL-CODE nitems(1) size(2)

code(size) ⇒ stack A compiled function is constructed and pushed onto the stack. This object is in the format specified by the most recent occurrence of FOP-CODE-FORMAT. The operand nitems specifies a number of items to pop off the stack to use in the “boxed storage” section. The operand code is a string of bytes constituting the compiled executable code.

60 FOP-FDEFINITION

Pops the stack to get an fdefinition.

61 FOP-SANCTIFY-FOR-EXECUTION

A code component is popped from the stack, and the necessary magic is applied to the code so that it can be executed.

62: FOP-VERIFY-TABLE-SIZE size(4)

If the current size of the table is not equal to 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.

63: 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.

64: 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 “FASL FILE”.

65: FOP-POP-FOR-EFFECT stack ⇒

One item is popped from the stack.

66: FOP-MISC-TRAP ⇒ stack

A trap object is pushed onto the stack.

67: FOP-DOUBLE-DOUBLE-FLOAT double-double-float(8) ⇒ stack

The next 8 bytes are read, and a double-double-float number is constructed.

68: FOP-CHARACTER character(3) ⇒ 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.

69: FOP-SHORT-CHARACTER character(1)

⇒ stack The one byte specifies the code of a Common Lisp character object. A character is constructed and pushed onto the stack.

70: FOP-RATIO ⇒ stack

Creates a ratio from two integers popped from the stack. The denominator is popped first, the numerator second.

71: FOP-COMPLEX ⇒ stack

Creates a complex number from two numbers popped from the stack. The imaginary part is popped first, the real part second.

72 FOP-COMPLEX-SINGLE-FLOAT real(4) imag(4) ⇒ stack

Creates a complex single-float number from the following 8 bytes.

73 FOP-COMPLEX-DOUBLE-FLOAT real(8) imag(8) ⇒ stack

Creates a complex double-float number from the following 16 bytes.

74: FOP-FSET

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).

75: FOP-LISP-SYMBOL-SAVE n(4) name(n)

⇒ stack & table Like FOP-SYMBOL-SAVE, except that it creates a symbol in the LISP package.

76: FOP-LISP-SMALL-SYMBOL-SAVE n(1)

name(n) ⇒ stack & table Like FOP-SMALL-SYMBOL-SAVE, except that it creates a symbol in the LISP package.

77: FOP-KEYWORD-SYMBOL-SAVE n(4) name(n)

⇒ stack & table Like FOP-SYMBOL-SAVE, except that it creates a symbol in the KEYWORD package.

78: FOP-KEYWORD-SMALL-SYMBOL-SAVE n(1)

name(n) ⇒ stack & table Like FOP-SMALL-SYMBOL-SAVE, except that it creates a symbol in the KEYWORD package.

79-80: Unused
81: 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.

82: FOP-MAYBE-COLD-LOAD

Undoes the effect of FOP-NORMAL-LOAD.

83: FOP-ARRAY rank(4) ⇒ 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 rank dimensions are popped off of the stack (the highest dimensions is on top.)

84: FOP-SINGLE-FLOAT-VECTOR length(4) data(n) ⇒ stack

Creates a (simple-array single-float (*)) object. The number of single-floats is length.

85: FOP-DOUBLE-FLOAT-VECTOR length(4) data(n) ⇒ stack

Creates a (simple-array double-float (*)) object. The number of double-floats is length.

86: FOP-COMPLEX-SINGLE-FLOAT-VECTOR length(4) data(n) ⇒ stack

Creates a (simple-array (complex single-float) (*)) object. The number of complex single-floats is length.

87: FOP-COMPLEX-DOUBLE-FLOAT-VECTOR length(4) data(n) ⇒ stack

Creates a (simple-array (complex double-float) (*)) object. The number of complex double-floats is length.

88: FOP-DOUBLE-DOUBLE-FLOAT-VECTOR length(4) data(n) ⇒ stack

Creates a (simple-array double-double-float (*)) object. The number of double-double-floats is length.

89: FOP-COMPLEX-DOUBLE-DOUBLE-FLOAT data(32) ⇒ stack

Creates a (complex double-double-float) object from the following 32 bytes of data.

90: FOP-COMPLEX-DOUBLE-DOUBLE-FLOAT-VECTOR length(4) data(n) ⇒ stack

Creates a (simple-arra (complex double-double-float) (*)) object. The number of complex double-double-floats is length.

91-139: Unused
140: FOP-ALTER-CODE 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.

141: FOP-BYTE-ALTER-CODE index(1)

Like FOP-ALTER-CODE, but has only a one byte offset.

142: FOP-FUNCTION-ENTRY index(4) ⇒ stack

Initializes a function-entry header inside of a pre-existing code object, and returns the corresponding function descriptor. 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.

143: FOP-MAKE-BYTE-COMPILED-FUNCTION size(1) ⇒ stack

Create a byte-compiled function. FIXME: describe what’s on the stack.

144: FOP-ASSEMBLER-CODE length(4) ⇒ stack

This operation creates a code object holding assembly routines. 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.)

145: FOP-ASSEMBLER-ROUTINE offset(4) ⇒ stack

This operation records an entry point into an assembler code object (for use with FOP-ASSEMBLER-FIXUP). The routine name (a symbol) is on stack top. The code object is underneath. The entry point is defined at 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.)

146: Unused
147: FOP-FOREIGN-FIXUP len(1) name(len) offset(4) ⇒ stack

This operation resolves a reference to a foreign (C) symbol. len bytes are read and interpreted as the symbol name. First the 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 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.)

148: FOP-ASSEMBLER-FIXUP offset(4) ⇒ stack

This operation resolves a reference to an assembler routine. The stack args are (routine-name, kind and code-object). The kind is a target-dependent symbol indicating the instruction format of the patch target (at 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.)

149: FOP-CODE-OBJECT-FIXUP ⇒ stack

FIXME: Describe what this does!

150: FOP-FOREIGN-DATA-FIXUP ⇒ stack

FIXME: Describe what this does!

151-156: Unused
157: FOP-LONG-CODE-FORMAT implementation(1) version(4)

Like FOP-CODE-FORMAT, except that the version is 32 bits long.

158-199: Unused
200: FOP-RPLACA table-idx(4) cdr-offset(4)
201: FOP-RPLACD table-idx(4) cdr-offset(4)

These operations destructively modify a list entered in the table. table-idx is the table entry holding the list, and cdr-offset designates the cons in the list to modify (like the argument to nthcdr.) The new value is popped off of the stack, and stored in the car or cdr, respectively.

202: FOP-SVSET table-idx(4) vector-idx(4)

Destructively modifies a simple-vector entered in the table. Pops the new value off of the stack, and stores it in the vector-idx element of the contents of the table entry table-idx.

203: FOP-NTHCDR cdr-offset(4) ⇒ stack

Does nthcdr on the top-of stack, leaving the result there.

204: FOP-STRUCTSET table-idx(4) vector-idx(4)

Like FOP-SVSET, except it alters structure slots.

205-254: Unused
255: FOP-END-HEADER

Indicates the end of a group header, as described above.


Previous: Strategy, Up: Fasload File Format   [Contents]