rename goto/args and friends to tail-call, tail-apply, etc
[bpt/guile.git] / doc / ref / vm.texi
index 5048edb..b64c2a6 100644 (file)
@@ -1,6 +1,6 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
-@c Copyright (C)  2008,2009
+@c Copyright (C)  2008,2009,2010
 @c   Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
@@ -8,13 +8,13 @@
 @section A Virtual Machine for Guile
 
 Guile has both an interpreter and a compiler. To a user, the
-difference is largely transparent -- interpreted and compiled
+difference is largely transparent---interpreted and compiled
 procedures can call each other as they please.
 
 The difference is that the compiler creates and interprets bytecode
 for a custom virtual machine, instead of interpreting the
-S-expressions directly. Running compiled code is faster than running
-interpreted code.
+S-expressions directly. Loading and running compiled code is faster
+than loading and running source code.
 
 The virtual machine that does the bytecode interpretation is a part of
 Guile itself. This section describes the nature of Guile's virtual
@@ -32,22 +32,24 @@ machine.
 @node Why a VM?
 @subsection Why a VM?
 
-For a long time, Guile only had an interpreter, called the evaluator.
-Guile's evaluator operates directly on the S-expression representation
-of Scheme source code.
+@cindex interpreter
+@cindex evaluator
+For a long time, Guile only had an interpreter, called the
+@dfn{evaluator}. Guile's evaluator operates directly on the
+S-expression representation of Scheme source code.
 
 But while the evaluator is highly optimized and hand-tuned, and
-contains some extensive speed trickery (REFFIXME memoization), it
-still performs many needless computations during the course of
-evaluating an expression. For example, application of a function to
-arguments needlessly conses up the arguments in a list. Evaluation of
-an expression always has to figure out what the car of the expression
-is -- a procedure, a memoized form, or something else. All values have
-to be allocated on the heap. Et cetera.
+contains some extensive speed trickery (@pxref{Memoization}), it still
+performs many needless computations during the course of evaluating an
+expression. For example, application of a function to arguments
+needlessly conses up the arguments in a list. Evaluation of an
+expression always has to figure out what the car of the expression is
+-- a procedure, a memoized form, or something else. All values have to
+be allocated on the heap. Et cetera.
 
 The solution to this problem is to compile the higher-level language,
 Scheme, into a lower-level language for which all of the checks and
-dispatching have already been done -- the code is instead stripped to
+dispatching have already been done---the code is instead stripped to
 the bare minimum needed to ``do the job''.
 
 The question becomes then, what low-level language to choose? There
@@ -63,8 +65,8 @@ present on all Guile installations.
 The easiest (and most fun) way to depend on a virtual machine is to
 implement the virtual machine within Guile itself. This way the
 virtual machine provides what Scheme needs (tail calls, multiple
-values, call/cc) and can provide optimized inline instructions for
-Guile (cons, struct-ref, etc.).
+values, @code{call/cc}) and can provide optimized inline instructions
+for Guile (@code{cons}, @code{struct-ref}, etc.).
 
 So this is what Guile does. The rest of this section describes that VM
 that Guile implements, and the compiled procedures that run on it.
@@ -72,7 +74,7 @@ that Guile implements, and the compiled procedures that run on it.
 Note that this decision to implement a bytecode compiler does not
 preclude native compilation. We can compile from bytecode to native
 code at runtime, or even do ahead of time compilation. More
-possibilities are discussed in REFFIXME.
+possibilities are discussed in @ref{Extending the Compiler}.
 
 @node VM Concepts
 @subsection VM Concepts
@@ -84,7 +86,7 @@ virtual machine per thread. When a VM-compiled procedure is run, Guile
 looks up the virtual machine for the current thread and executes the
 procedure using that VM.
 
-Guile's virtual machine is a stack machine -- that is, it has few
+Guile's virtual machine is a stack machine---that is, it has few
 registers, and the instructions defined in the VM operate by pushing
 and popping values from a stack.
 
@@ -109,27 +111,30 @@ The registers that a VM has are as follows:
 In other architectures, the instruction pointer is sometimes called
 the ``program counter'' (pc). This set of registers is pretty typical
 for stack machines; their exact meanings in the context of Guile's VM
-is described below REFFIXME.
+are described in the next section.
 
 A virtual machine executes by loading a compiled procedure, and
 executing the object code associated with that procedure. Of course,
 that procedure may call other procedures, tail-call others, ad
-infinitum -- indeed, within a guile whose modules have all been
+infinitum---indeed, within a guile whose modules have all been
 compiled to object code, one might never leave the virtual machine.
 
-@c wingo: I wish the following were true, but currently we just use
-@c the one engine. This kind of thing is possible tho.
+@c wingo: The following is true, but I don't know in what context to
+@c describe it. A documentation FIXME.
 
 @c A VM may have one of three engines: reckless, regular, or debugging.
 @c Reckless engine is fastest but dangerous.  Regular engine is normally
 @c fail-safe and reasonably fast.  Debugging engine is safest and
 @c functional but very slow.
 
+@c (Actually we have just a regular and a debugging engine; normally
+@c we use the latter, it's almost as fast as the ``regular'' engine.)
+
 @node Stack Layout
 @subsection Stack Layout
 
 While not strictly necessary to understand how to work with the VM, it
-is instructive and sometimes entertaining to consider the struture of
+is instructive and sometimes entertaining to consider the structure of
 the VM stack.
 
 Logically speaking, a VM stack is composed of ``frames''. Each frame
@@ -154,25 +159,26 @@ The structure of the fixed part of an application frame is as follows:
 
 @example
              Stack
-   |                  | <- fp + bp->nargs + bp->nlocs + 4
-   +------------------+    = SCM_FRAME_UPPER_ADDRESS (fp)
-   | Return address   |
-   | MV return address|
-   | Dynamic link     |
-   | External link    | <- fp + bp->nargs + bp->nlocs
-   | Local variable 1 |    = SCM_FRAME_DATA_ADDRESS (fp)
+   | ...              |
+   | Intermed. val. 0 | <- fp + bp->nargs + bp->nlocs = SCM_FRAME_UPPER_ADDRESS (fp)
+   +==================+
+   | Local variable 1 |
    | Local variable 0 | <- fp + bp->nargs
    | Argument 1       |
    | Argument 0       | <- fp
    | Program          | <- fp - 1
-   +------------------+    = SCM_FRAME_LOWER_ADDRESS (fp)
+   +------------------+    
+   | Return address   |
+   | MV return address|
+   | Dynamic link     | <- fp - 4 = SCM_FRAME_DATA_ADDRESS (fp) = SCM_FRAME_LOWER_ADDRESS (fp)
+   +==================+
    |                  |
 @end example
 
 In the above drawing, the stack grows upward. The intermediate values
 stored in the application of this frame are stored above
 @code{SCM_FRAME_UPPER_ADDRESS (fp)}. @code{bp} refers to the
-@code{struct scm_program*} data associated with the program at
+@code{struct scm_objcode} data associated with the program at
 @code{fp - 1}. @code{nargs} and @code{nlocs} are properties of the
 compiled procedure, which will be discussed later.
 
@@ -189,74 +195,78 @@ The @code{ip} to return to if this application returns multiple
 values. For continuations that only accept one value, this value will
 be @code{NULL}; for others, it will be an @code{ip} that points to a
 multiple-value return address in the calling code. That code will
-expect the top value on the stack to be an integer -- the number of
-values being returned -- and that below that integer there are the
+expect the top value on the stack to be an integer---the number of
+values being returned---and that below that integer there are the
 values being returned.
 
 @item Dynamic link
 This is the @code{fp} in effect before this program was applied. In
 effect, this and the return address are the registers that are always
-``saved''.
-
-@item External link
-This field is a reference to the list of heap-allocated variables
-associated with this frame. A discussion of heap versus stack
-allocation can be found in REFFIXME.
+``saved''. The dynamic link links the current frame to the previous
+frame; computing a stack trace involves traversing these frames.
 
 @item Local variable @var{n}
-Lambda-local variables that are allocated on the stack are all
-allocated as part of the frame. This makes access to non-captured,
-non-mutated variables very cheap.
+Lambda-local variables that are all allocated as part of the frame.
+This makes access to variables very cheap.
 
 @item Argument @var{n}
 The calling convention of the VM requires arguments of a function
-application to be pushed on the stack, and here they are. Normally
-references to arguments dispatch to these locations on the stack.
-However if an argument has to be stored on the heap, it will be copied
-from its initial value here onto a location in the heap, and
-thereafter only referenced on the heap.
+application to be pushed on the stack, and here they are. References
+to arguments dispatch to these locations on the stack.
 
 @item Program
-This is the program being applied. Programs are discussed in REFFIXME!
+This is the program being applied. For more information on how
+programs are implemented, @xref{VM Programs}.
 @end table
 
 @node Variables and the VM
 @subsection Variables and the VM
 
-Let's think about the following Scheme code as an example:
+Consider the following Scheme code as an example:
 
 @example
   (define (foo a)
     (lambda (b) (list foo a b)))
 @end example
 
-Within the lambda expression, "foo" is a top-level variable, "a" is a
-lexically captured variable, and "b" is a local variable.
-
-That is to say: @code{b} may safely be allocated on the stack, as
-there is no enclosed procedure that references it, nor is it ever
-mutated.
-
-@code{a}, on the other hand, is referenced by an enclosed procedure,
-that of the lambda. Thus it must be allocated on the heap, as it may
-(and will) outlive the dynamic extent of the invocation of @code{foo}.
-
-@code{foo} is a toplevel variable, as mandated by Scheme's semantics:
-
-@example
-  (define proc (foo 'bar)) ; assuming prev. definition of @code{foo}
-  (define foo 42)          ; redefinition
-  (proc 'baz)
-  @result{} (42 bar baz)
-@end example
-
-Note that variables that are mutated (via @code{set!}) must be
-allocated on the heap, even if they are local variables. This is
-because any called subprocedure might capture the continuation, which
-would need to capture locations instead of values. Thus perhaps
-counterintuitively, what would seem ``closer to the metal'', viz
-@code{set!}, actually forces heap allocation instead of stack
-allocation.
+Within the lambda expression, @code{foo} is a top-level variable, @code{a} is a
+lexically captured variable, and @code{b} is a local variable.
+
+Another way to refer to @code{a} and @code{b} is to say that @code{a}
+is a ``free'' variable, since it is not defined within the lambda, and
+@code{b} is a ``bound'' variable. These are the terms used in the
+@dfn{lambda calculus}, a mathematical notation for describing
+functions. The lambda calculus is useful because it allows one to
+prove statements about functions. It is especially good at describing
+scope relations, and it is for that reason that we mention it here.
+
+Guile allocates all variables on the stack. When a lexically enclosed
+procedure with free variables---a @dfn{closure}---is created, it
+copies those variables its free variable vector. References to free
+variables are then redirected through the free variable vector.
+
+If a variable is ever @code{set!}, however, it will need to be
+heap-allocated instead of stack-allocated, so that different closures
+that capture the same variable can see the same value. Also, this
+allows continuations to capture a reference to the variable, instead
+of to its value at one point in time. For these reasons, @code{set!}
+variables are allocated in ``boxes''---actually, in variable cells.
+@xref{Variables}, for more information. References to @code{set!}
+variables are indirected through the boxes.
+
+Thus perhaps counterintuitively, what would seem ``closer to the
+metal'', viz @code{set!}, actually forces an extra memory allocation
+and indirection.
+
+Going back to our example, @code{b} may be allocated on the stack, as
+it is never mutated.
+
+@code{a} may also be allocated on the stack, as it too is never
+mutated. Within the enclosed lambda, its value will be copied into
+(and referenced from) the free variables vector.
+
+@code{foo} is a top-level variable, because @code{foo} is not
+lexically bound in this example.
 
 @node VM Programs
 @subsection Compiled Procedures are VM Programs
@@ -270,14 +280,16 @@ A compiled procedure is a compound object, consisting of its bytecode,
 a reference to any captured lexical variables, an object array, and
 some metadata such as the procedure's arity, name, and documentation.
 You can pick apart these pieces with the accessors in @code{(system vm
-program)}. REFFIXME, for a full API reference.
+program)}. @xref{Compiled Procedures}, for a full API reference.
 
 @cindex object table
+@cindex object array
 The object array of a compiled procedure, also known as the
 @dfn{object table}, holds all Scheme objects whose values are known
 not to change across invocations of the procedure: constant strings,
 symbols, etc. The object table of a program is initialized right
-before a program is loaded with @code{load-program} REFFIXME.
+before a program is loaded with @code{load-program}.
+@xref{Loading Instructions}, for more information.
 
 Variable objects are one such type of constant object: when a global
 binding is defined, a variable object is associated to it and that
@@ -289,56 +301,52 @@ instruction, which uses the object vector, and are almost as fast as
 local variable references.
 
 We can see how these concepts tie together by disassembling the
-@code{foo} function to see what is going on:
+@code{foo} function we defined earlier to see what is going on:
 
 @smallexample
 scheme@@(guile-user)> (define (foo a) (lambda (b) (list foo a b)))
 scheme@@(guile-user)> ,x foo
 Disassembly of #<program foo (a)>:
 
-Bytecode:
-
-   0    (local-ref 0)                   ;; `a' (arg)
-   2    (external-set 0)                ;; `a' (arg)
-   4    (object-ref 0)                  ;; #<program #(0 28 #f) (b)>
-   6    (make-closure)                                        at (unknown file):0:16
-   7    (return)                        
+   0    (object-ref 1)          ;; #<program b7e478b0 at <unknown port>:0:16 (b)>
+   2    (local-ref 0)           ;; `a' (arg)
+   4    (vector 0 1)            ;; 1 element
+   7    (make-closure)                  
+   8    (return)                        
 
 ----------------------------------------
-Disassembly of #<program #(0 28 #f) (b)>:
+Disassembly of #<program b7e478b0 at <unknown port>:0:16 (b)>:
 
-Bytecode:
-
-   0    (toplevel-ref 0)                ;; `list'
-   2    (toplevel-ref 1)                ;; `foo'
-   4    (external-ref 0)                ;; (closure variable)
-   6    (local-ref 0)                   ;; `b' (arg)
-   8    (goto/args 3)                                         at (unknown file):0:28
+   0    (toplevel-ref 1)        ;; `foo'
+   2    (free-ref 0)            ;; (closure variable)
+   4    (local-ref 0)           ;; `b' (arg)
+   6    (list 0 3)              ;; 3 elements         at (unknown file):0:28
+   9    (return)                        
 @end smallexample
 
-At @code{ip} 0 and 2, we do the copy from argument to heap for
-@code{a}. @code{Ip} 4 loads up the compiled lambda, and then at
-@code{ip} 6 we make a closure -- binding code (from the compiled
-lambda) with data (the heap-allocated variables). Finally we return
-the closure.
+At @code{ip} 0, we load up the compiled lambda. @code{Ip} 2 and 4
+create the free variables vector, and @code{ip} 7 makes the
+closure---binding code (from the compiled lambda) with data (the
+free-variable vector). Finally we return the closure.
 
 The second stanza disassembles the compiled lambda. Toplevel variables
 are resolved relative to the module that was current when the
 procedure was created. This lookup occurs lazily, at the first time
 the variable is actually referenced, and the location of the lookup is
-cached so that future references are very cheap. REFFIXME xref
-toplevel-ref, for more details.
+cached so that future references are very cheap. @xref{Environment
+Control Instructions}, for more details.
 
 Then we see a reference to an external variable, corresponding to
 @code{a}. The disassembler doesn't have enough information to give a
 name to that variable, so it just marks it as being a ``closure
-variable''. Finally we see the reference to @code{b}, then a tail call
-(@code{goto/args}) with three arguments.
+variable''. Finally we see the reference to @code{b}, then the
+@code{list} opcode, an inline implementation of the @code{list} scheme
+routine.
 
 @node Instruction Set
 @subsection Instruction Set
 
-There are about 100 instructions in Guile's virtual machine. These
+There are about 150 instructions in Guile's virtual machine. These
 instructions represent atomic units of a program's execution. Ideally,
 they perform one task without conditional branches, then dispatch to
 the next instruction in the stream.
@@ -361,7 +369,8 @@ their own test-and-branch instructions:
 @end example
 
 In addition, some Scheme primitives have their own inline
-implementations, e.g. @code{cons}.
+implementations, e.g. @code{cons}, and @code{list}, as we saw in the
+previous section.
 
 So Guile's instruction set is a @emph{complete} instruction set, in
 that it provides the instructions that are suited to the problem, and
@@ -377,55 +386,92 @@ instructions. More instructions may be added over time.
 * Miscellaneous Instructions::  
 * Inlined Scheme Instructions::  
 * Inlined Mathematical Instructions::  
+* Inlined Bytevector Instructions::  
 @end menu
 
 @node Environment Control Instructions
 @subsubsection Environment Control Instructions
 
 These instructions access and mutate the environment of a compiled
-procedure -- the local bindings, the ``external'' bindings, and the
+procedure---the local bindings, the free (captured) bindings, and the
 toplevel bindings.
 
-@deffn Instruction local-ref offset
+Some of these instructions have @code{long-} variants, the difference
+being that they take 16-bit arguments, encoded in big-endianness,
+instead of the normal 8-bit range.
+
+@deffn Instruction local-ref index
+@deffnx Instruction long-local-ref index
 Push onto the stack the value of the local variable located at
-@var{offset} within the current stack frame.
+@var{index} within the current stack frame.
 
 Note that arguments and local variables are all in one block. Thus the
-first argument, if any, is at offset 0, and local bindings follow the
+first argument, if any, is at index 0, and local bindings follow the
 arguments.
 @end deffn
 
-@deffn Instruction local-set offset
+@deffn Instruction local-set index
+@deffnx Instruction long-local-ref index
 Pop the Scheme object located on top of the stack and make it the new
-value of the local variable located at @var{offset} within the current
+value of the local variable located at @var{index} within the current
 stack frame.
 @end deffn
 
-@deffn Instruction external-ref offset
-Push the value of the closure variable located at position
-@var{offset} within the program's list of external variables.
+@deffn Instruction free-ref index
+Push the value of the captured variable located at position
+@var{index} within the program's vector of captured variables.
 @end deffn
 
-@deffn Instruction external-set offset
-Pop the Scheme object located on top of the stack and make it the new
-value of the closure variable located at @var{offset} within the
-program's list of external variables.
+@deffn Instruction free-boxed-ref index
+@deffnx Instruction free-boxed-set index
+Get or set a boxed free variable. Note that there is no free-set
+instruction, as variables that are @code{set!} must be boxed.
+
+These instructions assume that the value at position @var{index} in
+the free variables vector is a variable.
 @end deffn
 
-The external variable lookup algorithm should probably be made more
-efficient in the future via addressing by frame and offset. Currently,
-external variables are all consed onto a list, which results in O(N)
-lookup time.
+@deffn Instruction make-closure
+Pop a vector and a program object off the stack, in that order, and
+push a new program object with the given free variables vector. The
+new program object shares state with the original program.
+
+At the time of this writing, the space overhead of closures is 4 words
+per closure.
+@end deffn
+
+@deffn Instruction fix-closure index
+Pop a vector off the stack, and set it as the @var{index}th local
+variable's free variable vector. The @var{index}th local variable is
+assumed to be a procedure.
+
+This instruction is part of a hack for allocating mutually recursive
+procedures. The hack is to first perform a @code{local-set} for all of
+the recursive procedures, then fix up the procedures' free variable
+bindings in place. This allows most @code{letrec}-bound procedures to
+be allocated unboxed on the stack.
+
+One could of course do a @code{local-ref}, then @code{make-closure},
+then @code{local-set}, but this macroinstruction helps to speed up the
+common case.
+@end deffn
+
+@deffn Instruction box index
+Pop a value off the stack, and set the @var{index}nth local variable
+to a box containing that value. A shortcut for @code{make-variable}
+then @code{local-set}, used when binding boxed variables.
+@end deffn
 
-@deffn Instruction externals
-Pushes the current list of external variables onto the stack. This
-instruction is used in the implementation of
-@code{compile-time-environment}.
+@deffn Instruction empty-box index
+Set the @var{indext}h local variable to a box containing a variable
+whose value is unbound. Used when compiling some @code{letrec}
+expressions.
 @end deffn
 
-@deffn Instruction toplevel-ref offset
+@deffn Instruction toplevel-ref index
+@deffnx Instruction long-toplevel-ref index
 Push the value of the toplevel binding whose location is stored in at
-position @var{offset} in the object table.
+position @var{index} in the object table.
 
 Initially, a cell in the object table that is used by
 @code{toplevel-ref} is initialized to one of two forms. The normal
@@ -436,11 +482,11 @@ created.
 Alternately, the lookup may be performed relative to a particular
 module, determined at compile-time (e.g. via @code{@@} or
 @code{@@@@}). In that case, the cell in the object table holds a list:
-@code{(@var{modname} @var{sym} @var{interface?})}. The symbol
-@var{sym} will be looked up in the module named @var{modname} (a list
-of symbols). The lookup will be performed against the module's public
-interface, unless @var{interface?} is @code{#f}, which it is for
-example when compiling @code{@@@@}.
+@code{(@var{modname} @var{sym} @var{public?})}. The symbol @var{sym}
+will be looked up in the module named @var{modname} (a list of
+symbols). The lookup will be performed against the module's public
+interface, unless @var{public?} is @code{#f}, which it is for example
+when compiling @code{@@@@}.
 
 In any case, if the symbol is unbound, an error is signalled.
 Otherwise the initial form is replaced with the looked-up variable, an
@@ -451,13 +497,20 @@ variable has been successfully resolved.
 This instruction pushes the value of the variable onto the stack.
 @end deffn
 
-@deffn Instruction toplevel-ref offset
+@deffn Instruction toplevel-set index
+@deffnx Instruction long-toplevel-set index
 Pop a value off the stack, and set it as the value of the toplevel
-variable stored at @var{offset} in the object table. If the variable
+variable stored at @var{index} in the object table. If the variable
 has not yet been looked up, we do the lookup as in
 @code{toplevel-ref}.
 @end deffn
 
+@deffn Instruction define
+Pop a symbol and a value from the stack, in that order. Look up its
+binding in the current toplevel environment, creating the binding if
+necessary. Set the variable to the value.
+@end deffn
+
 @deffn Instruction link-now
 Pop a value, @var{x}, from the stack. Look up the binding for @var{x},
 according to the rules for @code{toplevel-ref}, and push that variable
@@ -477,8 +530,15 @@ Pop off two objects from the stack, a variable and a value, and set
 the variable to the value.
 @end deffn
 
+@deffn Instruction make-variable
+Replace the top object on the stack with a variable containing it.
+Used in some circumstances when compiling @code{letrec} expressions.
+@end deffn
+
 @deffn Instruction object-ref n
-Push @var{n}th value from the current program's object vector.
+@deffnx Instruction long-object-ref n
+Push @var{n}th value from the current program's object vector. The
+``long'' variant has a 16-bit index instead of an 8-bit index.
 @end deffn
 
 @node Branch Instructions
@@ -488,19 +548,20 @@ All the conditional branch instructions described below work in the
 same way:
 
 @itemize
-@item They take the Scheme object located on the stack and use it as
+@item They pop off the Scheme object located on the stack and use it as
 the branch condition;
-@item If the condition is false, then program execution continues with
-the next instruction;
 @item If the condition is true, then the instruction pointer is
 increased by the offset passed as an argument to the branch
 instruction;
-@item Finally, when the instruction finished, the condition object is
-removed from the stack.
+@item Program execution proceeds with the next instruction (that is,
+the one to which the instruction pointer points).
 @end itemize
 
 Note that the offset passed to the instruction is encoded on two 8-bit
-integers which are then combined by the VM as one 16-bit integer.
+integers which are then combined by the VM as one 16-bit integer. Note
+also that jump targets in Guile are aligned on 8-byte boundaries, and
+that the offset refers to the @var{n}th 8-byte boundary, effectively
+giving Guile a 19-bit relative address space.
 
 @deffn Instruction br offset
 Jump to @var{offset}.
@@ -544,118 +605,85 @@ the instruction pointer to the next VM instruction.
 
 All of these loading instructions have a @code{length} parameter,
 indicating the size of the embedded data, in bytes. The length itself
-may be encoded in 1, 2, or 4 bytes.
+is encoded in 3 bytes.
 
-@deffn Instruction load-integer length
-Load a 32-bit integer from the instruction stream.
-@end deffn
 @deffn Instruction load-number length
 Load an arbitrary number from the instruction stream. The number is
 embedded in the stream as a string.
 @end deffn
 @deffn Instruction load-string length
-Load a string from the instruction stream.
+Load a string from the instruction stream. The string is assumed to be
+encoded in the ``latin1'' locale.
 @end deffn
-@deffn Instruction load-symbol length
-Load a symbol from the instruction stream.
+@deffn Instruction load-wide-string length
+Load a UTF-32 string from the instruction stream. @var{length} is the
+length in bytes, not in codepoints
 @end deffn
-@deffn Instruction load-keyword length
-Load a keyword from the instruction stream.
+@deffn Instruction load-symbol length
+Load a symbol from the instruction stream. The symbol is assumed to be
+encoded in the ``latin1'' locale. Symbols backed by wide strings may
+be loaded via @code{load-wide-string} then @code{make-symbol}.
 @end deffn
-
-@deffn Instruction define length
-Load a symbol from the instruction stream, and look up its binding in
-the current toplevel environment, creating the binding if necessary.
-Push the variable corresponding to the binding.
+@deffn Instruction load-array length
+Load a uniform array from the instruction stream. The shape and type
+of the array are popped off the stack, in that order.
 @end deffn
 
-@deffn Instruction load-program length
+@deffn Instruction load-program
 Load bytecode from the instruction stream, and push a compiled
-procedure. This instruction pops the following values from the stack:
+procedure.
 
-@itemize
-@item Optionally, a thunk, which when called should return metadata
-associated with this program -- for example its name, the names of its
-arguments, its documentation string, debugging information, etc.
-
-Normally, this thunk its itself a compiled procedure (with no
-metadata). Metadata is represented this way so that the initial load
-of a procedure is fast: the VM just mmap's the thunk and goes. The
-symbols and pairs associated with the metadata are only created if the
-user asks for them.
-
-The format of the thunk's return value is specified in REFFIXME.
-@item Optionally, the program's object table, as a vector.
-
-A program that does not reference toplevel bindings and does not use
-@code{object-ref} does not need an object table.
-@item Finally, either one immediate integer or four immediate integers
-representing the arity of the program.
-
-In the four-fixnum case, the values are respectively the number of
-arguments taken by the function (@var{nargs}), the number of @dfn{rest
-arguments} (@var{nrest}, 0 or 1), the number of local variables
-(@var{nlocs}) and the number of external variables (@var{nexts})
-(@pxref{Environment Control Instructions}).
-
-The common single-fixnum case represents all of these values within a
-16-bit bitmask.
-@end itemize
+This instruction pops one value from the stack: the program's object
+table, as a vector, or @code{#f} in the case that the program has no
+object table. A program that does not reference toplevel bindings and
+does not use @code{object-ref} does not need an object table.
 
-The resulting compiled procedure will not have any ``external''
-variables captured, so it will be loaded only once but may be used
-many times to create closures.
-@end deffn
+This instruction is unlike the rest of the loading instructions,
+because instead of parsing its data, it directly maps the instruction
+stream onto a C structure, @code{struct scm_objcode}. @xref{Bytecode
+and Objcode}, for more information.
 
-Finally, while this instruction is not strictly a ``loading''
-instruction, it's useful to wind up the @code{load-program} discussion
-here:
-
-@deffn Instruction make-closure
-Pop the program object from the stack, capture the current set of
-``external'' variables, and assign those external variables to a copy
-of the program. Push the new program object, which shares state with
-the original program. Also captures the current module.
+The resulting compiled procedure will not have any free variables
+captured, so it may be loaded only once but used many times to create
+closures.
 @end deffn
 
 @node Procedural Instructions
 @subsubsection Procedural Instructions
 
-@deffn Instruction return
-Free the program's frame, returning the top value from the stack to
-the current continuation. (The stack should have exactly one value on
-it.)
-
-Specifically, the @code{sp} is decremented to one below the current
-@code{fp}, the @code{ip} is reset to the current return address, the
-@code{fp} is reset to the value of the current dynamic link, and then
-the top item on the stack (formerly the procedure being applied) is
-set to the returned value.
+@deffn Instructions new-frame
+Push a new frame on the stack, reserving space for the dynamic link,
+return address, and the multiple-values return address. The frame
+pointer is not yet updated, because the frame is not yet active -- it
+has to be patched by a @code{call} instruction to get the return
+address.
 @end deffn
 
 @deffn Instruction call nargs
 Call the procedure located at @code{sp[-nargs]} with the @var{nargs}
-arguments located from @code{sp[0]} to @code{sp[-nargs + 1]}.
+arguments located from @code{sp[-nargs + 1]} to @code{sp[0]}.
+
+This instruction requires that a new frame be pushed on the stack
+before the procedure, via @code{new-frame}. @xref{Stack Layout}, for
+more information. It patches up that frame with the current @code{ip}
+as the return address, then dispatches to the first instruction in the
+called procedure, relying on the called procedure to return one value
+to the newly-created continuation. Because the new frame pointer will
+point to sp[-nargs + 1], the arguments don't have to be shuffled
+around -- they are already in place.
 
 For non-compiled procedures (continuations, primitives, and
-interpreted procedures), @code{call} will pop the procedure and
-arguments off the stack, and push the result of calling
+interpreted procedures), @code{call} will pop the frame, procedure,
+and arguments off the stack, and push the result of calling
 @code{scm_apply}.
-
-For compiled procedures, this instruction sets up a new stack frame,
-as described in REFFIXME, and then dispatches to the first instruction
-in the called procedure, relying on the called procedure to return one
-value to the newly-created continuation.
 @end deffn
 
-@deffn Instruction goto/args nargs
+@deffn Instruction tail-call nargs
 Like @code{call}, but reusing the current continuation. This
-instruction implements tail calling as required by RnRS.
+instruction implements tail calls as required by RnRS.
 
-For compiled procedures, that means that @code{goto/args} reuses the
-current frame instead of building a new one. The @code{goto/*}
-instruction family is named as it is because tail calls are equivalent
-to @code{goto}, along with relabeled variables.
+For compiled procedures, that means that @code{tail-call} simply
+shuffles down the procedure and arguments to the current stack frame.
 
 For non-VM procedures, the result is the same, but the current VM
 invocation remains on the C stack. True tail calls are not currently
@@ -663,40 +691,43 @@ possible between compiled and non-compiled procedures.
 @end deffn
 
 @deffn Instruction apply nargs
-@deffnx Instruction goto/apply nargs
-Like @code{call} and @code{goto/args}, except that the top item on the
+@deffnx Instruction tail-apply nargs
+Like @code{call} and @code{tail-call}, except that the top item on the
 stack must be a list. The elements of that list are then pushed on the
 stack and treated as additional arguments, replacing the list itself,
 then the procedure is invoked as usual.
 @end deffn
 
 @deffn Instruction call/nargs
-@deffnx Instruction goto/nargs
-These are like @code{call} and @code{goto/args}, except they take the
+@deffnx Instruction tail-call/nargs
+These are like @code{call} and @code{tail-call}, except they take the
 number of arguments from the stack instead of the instruction stream.
 These instructions are used in the implementation of multiple value
 returns, where the actual number of values is pushed on the stack.
 @end deffn
 
-@deffn Instruction call/cc
-@deffnx Instruction goto/cc
-Capture the current continuation, and then call (or tail-call) the
-procedure on the top of the stack, with the continuation as the
-argument.
-
-Both the VM continuation and the C continuation are captured.
-@end deffn
-
 @deffn Instruction mv-call nargs offset
 Like @code{call}, except that a multiple-value continuation is created
 in addition to a single-value continuation.
 
 The offset (a two-byte value) is an offset within the instruction
-stream; the multiple-value return address in the new frame (see
-frames REFFIXME) will be set to the normal return address plus this
-offset. Instructions at that offset will expect the top value of the
-stack to be the number of values, and below that values themselves,
-pushed separately.
+stream; the multiple-value return address in the new frame
+(@pxref{Stack Layout}) will be set to the normal return address plus
+this offset. Instructions at that offset will expect the top value of
+the stack to be the number of values, and below that values
+themselves, pushed separately.
+@end deffn
+
+@deffn Instruction return
+Free the program's frame, returning the top value from the stack to
+the current continuation. (The stack should have exactly one value on
+it.)
+
+Specifically, the @code{sp} is decremented to one below the current
+@code{fp}, the @code{ip} is reset to the current return address, the
+@code{fp} is reset to the value of the current dynamic link, and then
+the top item on the stack (formerly the procedure being applied) is
+set to the returned value.
 @end deffn
 
 @deffn Instruction return/values nvalues
@@ -721,18 +752,31 @@ values. This is an optimization for the common @code{(apply values
 
 @deffn Instruction truncate-values nbinds nrest
 Used in multiple-value continuations, this instruction takes the
-values that are on the stack (including the number-of-value marker)
+values that are on the stack (including the number-of-values marker)
 and truncates them for a binding construct.
 
 For example, a call to @code{(receive (x y . z) (foo) ...)} would,
 logically speaking, pop off the values returned from @code{(foo)} and
 push them as three values, corresponding to @code{x}, @code{y}, and
 @code{z}. In that case, @var{nbinds} would be 3, and @var{nrest} would
-be 1 (to indicate that one of the bindings was a rest arguments).
+be 1 (to indicate that one of the bindings was a rest argument).
 
 Signals an error if there is an insufficient number of values.
 @end deffn
 
+@deffn Instruction call/cc
+@deffnx Instruction tail-call/cc
+Capture the current continuation, and then call (or tail-call) the
+procedure on the top of the stack, with the continuation as the
+argument.
+
+@code{call/cc} does not require a @code{new-frame} to be pushed on the
+stack, as @code{call} does, because it needs to capture the stack
+before the frame is pushed.
+
+Both the VM continuation and the C continuation are captured.
+@end deffn
+
 @node Data Control Instructions
 @subsubsection Data Control Instructions
 
@@ -755,6 +799,17 @@ Push the immediate value @code{1} onto the stack.
 Push @var{value}, a 16-bit integer, onto the stack.
 @end deffn
 
+@deffn Instruction make-uint64 value
+Push @var{value}, an unsigned 64-bit integer, onto the stack. The
+value is encoded in 8 bytes, most significant byte first (big-endian).
+@end deffn
+
+@deffn Instruction make-int64 value
+Push @var{value}, a signed 64-bit integer, onto the stack. The value
+is encoded in 8 bytes, most significant byte first (big-endian), in
+twos-complement arithmetic.
+@end deffn
+
 @deffn Instruction make-false
 Push @code{#f} onto the stack.
 @end deffn
@@ -763,6 +818,10 @@ Push @code{#f} onto the stack.
 Push @code{#t} onto the stack.
 @end deffn
 
+@deffn Instruction make-nil
+Push @code{%nil} onto the stack.
+@end deffn
+
 @deffn Instruction make-eol
 Push @code{'()} onto the stack.
 @end deffn
@@ -771,48 +830,38 @@ Push @code{'()} onto the stack.
 Push @var{value}, an 8-bit character, onto the stack.
 @end deffn
 
-@deffn Instruction list n
-Pops off the top @var{n} values off of the stack, consing them up into
-a list, then pushes that list on the stack. What was the topmost value
-will be the last element in the list.
-@end deffn
-
-@deffn Instruction vector n
-Create and fill a vector with the top @var{n} values from the stack,
-popping off those values and pushing on the resulting vector.
+@deffn Instruction make-char32 value
+Push @var{value}, an 32-bit character, onto the stack. The value is
+encoded in big-endian order.
 @end deffn
 
-@deffn Instruction mark
-Pushes a special value onto the stack that other stack instructions
-like @code{list-mark} can use.
+@deffn Instruction make-symbol
+Pops a string off the stack, and pushes a symbol.
 @end deffn
 
-@deffn Instruction list-mark
-Create a list from values from the stack, as in @code{list}, but
-instead of knowing beforehand how many there will be, keep going until
-we see a @code{mark} value.
+@deffn Instruction make-keyword value
+Pops a symbol off the stack, and pushes a keyword.
 @end deffn
 
-@deffn Instruction cons-mark
-As the scheme procedure @code{cons*} is to the scheme procedure
-@code{list}, so the instruction @code{cons-mark} is to the instruction
-@code{list-mark}.
-@end deffn
-
-@deffn Instruction vector-mark
-Like @code{list-mark}, but makes a vector instead of a list.
+@deffn Instruction list n
+Pops off the top @var{n} values off of the stack, consing them up into
+a list, then pushes that list on the stack. What was the topmost value
+will be the last element in the list. @var{n} is a two-byte value,
+most significant byte first.
 @end deffn
 
-@deffn Instruction list-break
-The opposite of @code{list}: pops a value, which should be a list, and
-pushes its elements on the stack.
+@deffn Instruction vector n
+Create and fill a vector with the top @var{n} values from the stack,
+popping off those values and pushing on the resulting vector. @var{n}
+is a two-byte value, like in @code{vector}.
 @end deffn
 
 @node Miscellaneous Instructions
 @subsubsection Miscellaneous Instructions
 
 @deffn Instruction nop
-Does nothing!
+Does nothing! Used for padding other instructions to certain
+alignments.
 @end deffn
 
 @deffn Instruction halt
@@ -822,7 +871,7 @@ machine is first entered; compiled Scheme procedures will not contain
 this instruction.
 
 If multiple values have been returned, the SCM value will be a
-multiple-values object (REFFIXME scm_values).
+multiple-values object (@pxref{Multiple Values}).
 @end deffn
 
 @deffn Instruction break
@@ -845,13 +894,12 @@ Pushes ``the unspecified value'' onto the stack.
 @subsubsection Inlined Scheme Instructions
 
 The Scheme compiler can recognize the application of standard Scheme
-procedures, or unbound variables that look like they are bound to
-standard Scheme procedures. It tries to inline these small operations
-to avoid the overhead of creating new stack frames.
+procedures. It tries to inline these small operations to avoid the
+overhead of creating new stack frames.
 
 Since most of these operations are historically implemented as C
 primitives, not inlining them would entail constantly calling out from
-the VM to the interpreter, which has some costs -- registers must be
+the VM to the interpreter, which has some costs---registers must be
 saved, the interpreter has to dispatch, called procedures have to do
 much typechecking, etc. It's much more efficient to inline these
 operations in the virtual machine itself.
@@ -871,14 +919,16 @@ stream.
 @deffnx Instruction eqv? x y
 @deffnx Instruction equal? x y
 @deffnx Instruction pair? x y
-@deffnx Instruction list? x y
+@deffnx Instruction list? x
 @deffnx Instruction set-car! pair x
 @deffnx Instruction set-cdr! pair x
 @deffnx Instruction slot-ref struct n
 @deffnx Instruction slot-set struct n x
-@deffnx Instruction cons x
+@deffnx Instruction cons x y
 @deffnx Instruction car x
 @deffnx Instruction cdr x
+@deffnx Instruction vector-ref x y
+@deffnx Instruction vector-set x n y
 Inlined implementations of their Scheme equivalents.
 @end deffn
 
@@ -899,7 +949,9 @@ As in the previous section, the definitions below show stack
 parameters instead of instruction stream parameters.
 
 @deffn Instruction add x y
+@deffnx Instruction add1 x
 @deffnx Instruction sub x y
+@deffnx Instruction sub1 x
 @deffnx Instruction mul x y
 @deffnx Instruction div x y
 @deffnx Instruction quo x y
@@ -912,3 +964,58 @@ parameters instead of instruction stream parameters.
 @deffnx Instruction ge? x y
 Inlined implementations of the corresponding mathematical operations.
 @end deffn
+
+@node Inlined Bytevector Instructions
+@subsubsection Inlined Bytevector Instructions
+
+Bytevector operations correspond closely to what the current hardware
+can do, so it makes sense to inline them to VM instructions, providing
+a clear path for eventual native compilation. Without this, Scheme
+programs would need other primitives for accessing raw bytes -- but
+these primitives are as good as any.
+
+As in the previous section, the definitions below show stack
+parameters instead of instruction stream parameters.
+
+The multibyte formats (@code{u16}, @code{f64}, etc) take an extra
+endianness argument. Only aligned native accesses are currently
+fast-pathed in Guile's VM.
+
+@deffn Instruction bv-u8-ref bv n
+@deffnx Instruction bv-s8-ref bv n
+@deffnx Instruction bv-u16-native-ref bv n
+@deffnx Instruction bv-s16-native-ref bv n
+@deffnx Instruction bv-u32-native-ref bv n
+@deffnx Instruction bv-s32-native-ref bv n
+@deffnx Instruction bv-u64-native-ref bv n
+@deffnx Instruction bv-s64-native-ref bv n
+@deffnx Instruction bv-f32-native-ref bv n
+@deffnx Instruction bv-f64-native-ref bv n
+@deffnx Instruction bv-u16-ref bv n endianness
+@deffnx Instruction bv-s16-ref bv n endianness
+@deffnx Instruction bv-u32-ref bv n endianness
+@deffnx Instruction bv-s32-ref bv n endianness
+@deffnx Instruction bv-u64-ref bv n endianness
+@deffnx Instruction bv-s64-ref bv n endianness
+@deffnx Instruction bv-f32-ref bv n endianness
+@deffnx Instruction bv-f64-ref bv n endianness
+@deffnx Instruction bv-u8-set bv n val
+@deffnx Instruction bv-s8-set bv n val
+@deffnx Instruction bv-u16-native-set bv n val
+@deffnx Instruction bv-s16-native-set bv n val
+@deffnx Instruction bv-u32-native-set bv n val
+@deffnx Instruction bv-s32-native-set bv n val
+@deffnx Instruction bv-u64-native-set bv n val
+@deffnx Instruction bv-s64-native-set bv n val
+@deffnx Instruction bv-f32-native-set bv n val
+@deffnx Instruction bv-f64-native-set bv n val
+@deffnx Instruction bv-u16-set bv n val endianness
+@deffnx Instruction bv-s16-set bv n val endianness
+@deffnx Instruction bv-u32-set bv n val endianness
+@deffnx Instruction bv-s32-set bv n val endianness
+@deffnx Instruction bv-u64-set bv n val endianness
+@deffnx Instruction bv-s64-set bv n val endianness
+@deffnx Instruction bv-f32-set bv n val endianness
+@deffnx Instruction bv-f64-set bv n val endianness
+Inlined implementations of the corresponding bytevector operations.
+@end deffn