guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, master, updated. v2.1.0-521-g69aecc6


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, master, updated. v2.1.0-521-g69aecc6
Date: Sat, 30 Nov 2013 17:47:21 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=69aecc6abb1a6579f5b1f9787d0fd000ae9ce26f

The branch, master has been updated
       via  69aecc6abb1a6579f5b1f9787d0fd000ae9ce26f (commit)
       via  ddf0d7bb2e1ad05e2bd23744b94b0a92509a83dd (commit)
       via  2b6659e438f0cecb056c1ffe8a2004aedb22fa46 (commit)
       via  4d6a7ac6ad5ea51927aec92f85b8526340a73270 (commit)
       via  23e2e78067787da3dabfded1b3a3f7a10905b4a8 (commit)
       via  02f9d49614f16adc418f8f9b47202fa3234dcedd (commit)
       via  1b1c9125446fc1386042e0bba1a2da6caec5334d (commit)
       via  321c32dc9d4799afed4783f82d3cbb50a561dee0 (commit)
       via  f5729276a9e7ef66a115969684193e5cf66fc945 (commit)
       via  0d1788039a00ccacb6ff36191f25f3577704883c (commit)
      from  d511a2e160ae808336d94683fe515a34247d3e4f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 69aecc6abb1a6579f5b1f9787d0fd000ae9ce26f
Author: Andy Wingo <address@hidden>
Date:   Sat Nov 30 18:45:55 2013 +0100

    Update vm.texi's "Instruction Set" section.
    
    * doc/ref/vm.texi (Instruction Set): Update.

commit ddf0d7bb2e1ad05e2bd23744b94b0a92509a83dd
Author: Andy Wingo <address@hidden>
Date:   Sat Nov 30 18:00:26 2013 +0100

    Fix more vm-engine comments
    
    * libguile/vm-engine.c: Fix more comments.

commit 2b6659e438f0cecb056c1ffe8a2004aedb22fa46
Author: Andy Wingo <address@hidden>
Date:   Sat Nov 30 16:43:28 2013 +0100

    Remove slot-ref and slot-set! ops
    
    * libguile/vm-engine.c: Remove slot-ref and slot-set! ops.

commit 4d6a7ac6ad5ea51927aec92f85b8526340a73270
Author: Andy Wingo <address@hidden>
Date:   Sat Nov 30 16:40:17 2013 +0100

    Remove GOOPS-internal @slot-ref and @slot-set!
    
    * module/oop/goops.scm: Remove definitions of @slot-ref and @slot-set!.
      They are equivalent to struct-ref and struct-set!.
      (define-standard-accessor-method): Reimplement using syntax-case.
      (bound-check-get, standard-get, standard-set): Replace @slot-ref and
      @slot-set! uses with struct-ref and struct-set!.
    
    * module/language/cps/reify-primitives.scm (primitive-module): Remove
      @slot-set! and @slot-ref references.

commit 23e2e78067787da3dabfded1b3a3f7a10905b4a8
Author: Andy Wingo <address@hidden>
Date:   Fri Nov 29 23:24:17 2013 +0100

    Beginning vm.texi updates
    
    * doc/ref/vm.texi: Updates.

commit 02f9d49614f16adc418f8f9b47202fa3234dcedd
Author: Andy Wingo <address@hidden>
Date:   Fri Nov 29 23:23:28 2013 +0100

    Fix vm-engine.c comments
    
    * libguile/vm-engine.c: Fix some comments.

commit 1b1c9125446fc1386042e0bba1a2da6caec5334d
Author: Andy Wingo <address@hidden>
Date:   Fri Nov 29 17:59:00 2013 +0100

    Unknown files print as (unknown file) in disassembler
    
    * module/system/vm/disassembler.scm (disassemble-buffer): Print unknown
      files as "(unknown file)".

commit 321c32dc9d4799afed4783f82d3cbb50a561dee0
Author: Andy Wingo <address@hidden>
Date:   Fri Nov 29 17:52:11 2013 +0100

    ,x disassembles nested programs too
    
    * module/system/vm/disassembler.scm (code-annotation):
      (disassemble-buffer, disassemble-addr, disassemble-program): Arrange
      to disassemble nested procedures.
      (disassemble-image): Adapt.

commit f5729276a9e7ef66a115969684193e5cf66fc945
Author: Andy Wingo <address@hidden>
Date:   Fri Nov 29 12:29:12 2013 +0100

    Update history.texi
    
    * doc/ref/history.texi (A Timeline of Selected Guile Releases, Status):
      Update.

commit 0d1788039a00ccacb6ff36191f25f3577704883c
Author: Andy Wingo <address@hidden>
Date:   Fri Nov 29 12:28:53 2013 +0100

    Remove outdated section of api-memory.texi
    
    * doc/ref/api-memory.texi (Memory Blocks): Remove section documenting
      scm_must_malloc and friends.

-----------------------------------------------------------------------

Summary of changes:
 doc/ref/api-memory.texi                  |   65 +-
 doc/ref/history.texi                     |   53 +-
 doc/ref/vm.texi                          | 1932 ++++++++++++++----------------
 libguile/vm-engine.c                     |   56 +-
 module/language/cps/reify-primitives.scm |    2 +-
 module/oop/goops.scm                     |   56 +-
 module/system/vm/disassembler.scm        |   61 +-
 7 files changed, 998 insertions(+), 1227 deletions(-)

diff --git a/doc/ref/api-memory.texi b/doc/ref/api-memory.texi
index ff202e0..6512650 100644
--- a/doc/ref/api-memory.texi
+++ b/doc/ref/api-memory.texi
@@ -1,6 +1,6 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
address@hidden Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009, 
2010, 2012
address@hidden Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009, 
2010, 2012, 2013
 @c   Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
@@ -248,69 +248,6 @@ preprocessor macro was defined when Guile was compiled.
 @end deffn
 
 
address@hidden Upgrading from scm_must_malloc et al.
-
-Version 1.6 of Guile and earlier did not have the functions from the
-previous section.  In their place, it had the functions
address@hidden, @code{scm_must_realloc} and
address@hidden  This section explains why we want you to stop
-using them, and how to do this.
-
address@hidden scm_must_malloc
address@hidden scm_must_realloc
address@hidden scm_must_calloc
address@hidden scm_must_free
-The functions @code{scm_must_malloc} and @code{scm_must_realloc}
-behaved like @code{scm_gc_malloc} and @code{scm_gc_realloc} do now,
-respectively.  They would inform the GC about the newly allocated
-memory via the internal equivalent of
address@hidden  However,
address@hidden did not unregister the memory it was about to
-free.  The usual way to unregister memory was to return its size from
-a smob free function.
-
-This disconnectedness of the actual freeing of memory and reporting
-this to the GC proved to be bad in practice.  It was easy to make
-mistakes and report the wrong size because allocating and freeing was
-not done with symmetric code, and because it is cumbersome to compute
-the total size of nested data structures that were freed with multiple
-calls to @code{scm_must_free}.  Additionally, there was no equivalent
-to @code{scm_malloc}, and it was tempting to just use
address@hidden and never to tell the GC that the memory has
-been freed.
-
-The effect was that the internal statistics kept by the GC drifted out
-of sync with reality and could even overflow in long running programs.
-When this happened, the result was a dramatic increase in (senseless)
-GC activity which would effectively stop the program dead.
-
address@hidden scm_done_malloc
address@hidden scm_done_free
-The functions @code{scm_done_malloc} and @code{scm_done_free} were
-introduced to help restore balance to the force, but existing bugs did
-not magically disappear, of course.
-
-Therefore we decided to force everybody to review their code by
-deprecating the existing functions and introducing new ones in their
-place that are hopefully easier to use correctly.
-
-For every use of @code{scm_must_malloc} you need to decide whether to
-use @code{scm_malloc} or @code{scm_gc_malloc} in its place.  When the
-memory block is not part of a smob or some other Scheme object whose
-lifetime is ultimately managed by the garbage collector, use
address@hidden and @code{free}.  When it is part of a smob, use
address@hidden and change the smob free function to use
address@hidden instead of @code{scm_must_free} or @code{free} and
-make it return zero.
-
-The important thing is to always pair @code{scm_malloc} with
address@hidden; and to always pair @code{scm_gc_malloc} with
address@hidden
-
-The same reasoning applies to @code{scm_must_realloc} and
address@hidden versus @code{scm_gc_realloc}.
-
-
 @node Weak References
 @subsection Weak References
 
diff --git a/doc/ref/history.texi b/doc/ref/history.texi
index a617cf7..f7fc4cb 100644
--- a/doc/ref/history.texi
+++ b/doc/ref/history.texi
@@ -1,6 +1,6 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
address@hidden Copyright (C)  2008, 2010, 2011
address@hidden Copyright (C)  2008, 2010, 2011, 2013
 @c   Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
@@ -211,6 +211,13 @@ via Geiser. Guile caught up to features found in a number 
of other
 Schemes: SRFI-18 threads, module-hygienic macros, a profiler, tracer,
 and debugger, SSAX XML integration, bytevectors, a dynamic FFI,
 delimited continuations, module versions, and partial support for R6RS.
+
address@hidden 2.2 --- mid-2014
+The virtual machine and introduced in 2.0 was completely rewritten,
+along with much of the compiler and toolchain.  This speeds up many
+Guile programs as well as reducing startup time and memory usage.  A PEG
+parser toolkit was added, making it easier to write other language
+frontends.
 @end table
 
 @node Status
@@ -250,19 +257,13 @@ than in other languages.
 These days it is possible to write extensible applications almost
 entirely from high-level languages, through byte-code and native
 compilation, speed gains in the underlying hardware, and foreign call
-interfaces in the high-level language. Smalltalk systems are like
-this, as are Common Lisp-based systems. While there already are a
-number of pure-Guile applications out there, users still need to drop
-down to C for some tasks: interfacing to system libraries that don't
-have prebuilt Guile interfaces, and for some tasks requiring high
-performance.
-
-The addition of the virtual machine in Guile 2.0, together with the
-compiler infrastructure, should go a long way to addressing the speed
-issues. But there is much optimization to be done. Interested
-contributors will find lots of delightful low-hanging fruit, from
-simple profile-driven optimization to hacking a just-in-time compiler
-from VM bytecode to native code.
+interfaces in the high-level language.  Smalltalk systems are like this,
+as are Common Lisp-based systems.  While there already are a number of
+pure-Guile applications out there, users still need to drop down to C
+for some tasks: interfacing to system libraries that don't have prebuilt
+Guile interfaces, and for some tasks requiring high performance.  Native
+ahead-of-time compilation, planned for Guile 3.0, should help with
+this.
 
 Still, even with an all-Guile application, sometimes you want to
 provide an opportunity for users to extend your program from a
@@ -270,19 +271,17 @@ language with a syntax that is closer to C, or to Python. 
Another
 interesting idea to consider is compiling e.g.@: Python to Guile. It's
 not that far-fetched of an idea: see for example IronPython or JRuby.
 
-And then there's Emacs itself. Though there is a somewhat-working Emacs
-Lisp language frontend for Guile, it cannot yet execute all of Emacs
-Lisp. A serious integration of Guile with Emacs would replace the Elisp
-virtual machine with Guile, and provide the necessary C shims so that
-Guile could emulate Emacs' C API. This would give lots of exciting
-things to Emacs: native threads, a real object system, more
-sophisticated types, cleaner syntax, and access to all of the Guile
-extensions.
+And then there's Emacs itself.  Guile's Emacs Lisp support has reached
+an excellent level of correctness, robustness, and speed.  However there
+is still work to do to finish its integration into Emacs itself.  This
+will give lots of exciting things to Emacs: native threads, a real
+object system, more sophisticated types, cleaner syntax, and access to
+all of the Guile extensions.
 
 Finally, there is another axis of crystallization, the axis between
-different Scheme implementations. Guile does not yet support the
-latest Scheme standard, R6RS, and should do so. Like all standards,
-R6RS is imperfect, but supporting it will allow more code to run on
-Guile without modification, and will allow Guile hackers to produce
-code compatible with other schemes. Help in this regard would be much
+different Scheme implementations. Guile does not yet support the latest
+Scheme standard, R7RS, and should do so. Like all standards, R7RS is
+imperfect, but supporting it will allow more code to run on Guile
+without modification, and will allow Guile hackers to produce code
+compatible with other schemes. Help in this regard would be much
 appreciated.
diff --git a/doc/ref/vm.texi b/doc/ref/vm.texi
index 1e10eb0..a4f47e2 100644
--- a/doc/ref/vm.texi
+++ b/doc/ref/vm.texi
@@ -79,9 +79,11 @@ but it is not normally used at runtime.)
 
 The upside of implementing the interpreter in Scheme is that we preserve
 tail calls and multiple-value handling between interpreted and compiled
-code. The downside is that the interpreter in Guile address@hidden is slower
+code. The downside is that the interpreter in Guile 2.2 is still slower
 than the interpreter in 1.8. We hope the that the compiler's speed makes
-up for the loss!
+up for the loss.  In any case, once we have native compilation for
+Scheme code, we expect the new self-hosted interpreter to beat the old
+hand-tuned C implementation.
 
 Also note that this decision to implement a bytecode compiler does not
 preclude native compilation. We can compile from bytecode to native
@@ -91,23 +93,24 @@ possibilities are discussed in @ref{Extending the Compiler}.
 @node VM Concepts
 @subsection VM Concepts
 
-Compiled code is run by a virtual machine (VM). Each thread has its own
-VM. When a compiled procedure is run, Guile looks up the virtual machine
-for the current thread and executes the procedure using that VM.
+Compiled code is run by a virtual machine (VM).  Each thread has its own
+VM.  The virtual machine executes the sequence of instructions in a
+procedure.
 
-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.
+Each VM instruction starts by indicating which operation it is, and then
+follows by encoding its source and destination operands.  Each procedure
+declares that it has some number of local variables, including the
+function arguments.  These local variables form the available operands
+of the procedure, and are accessed by index.
 
-Stack memory is exclusive to the virtual machine that owns it. In
-addition to their stacks, virtual machines also have access to the
-global memory (modules, global bindings, etc) that is shared among
-other parts of Guile, including other VMs.
+The local variables for a procedure are stored on a stack.  Calling a
+procedure typically enlarges the stack, and returning from a procedure
+shrinks it.  Stack memory is exclusive to the virtual machine that owns
+it.
 
-A VM has generic instructions, such as those to reference local
-variables, and instructions designed to support Guile's languages --
-mathematical instructions that support the entire numerical tower, an
-inlined implementation of @code{cons}, etc.
+In addition to their stacks, virtual machines also have access to the
+global memory (modules, global bindings, etc) that is shared among other
+parts of Guile, including other VMs.
 
 The registers that a VM has are as follows:
 
@@ -117,110 +120,59 @@ The registers that a VM has are as follows:
 @item fp - Frame pointer
 @end itemize
 
-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
-are described in the next section.
-
address@hidden wingo: The following is true, but I don't know in what context to
address@hidden describe it. A documentation FIXME.
-
address@hidden A VM may have one of three engines: reckless, regular, or 
debugging.
address@hidden Reckless engine is fastest but dangerous.  Regular engine is 
normally
address@hidden fail-safe and reasonably fast.  Debugging engine is safest and
address@hidden functional but very slow.
-
address@hidden (Actually we have just a regular and a debugging engine; normally
address@hidden we use the latter, it's almost as fast as the ``regular'' 
engine.)
+In other architectures, the instruction pointer is sometimes called the
+``program counter'' (pc). This set of registers is pretty typical for
+virtual machines; their exact meanings in the context of Guile's VM are
+described in the next section.
 
 @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 structure of
-the VM stack.
-
-Logically speaking, a VM stack is composed of ``frames''. Each frame
-corresponds to the application of one compiled procedure, and contains
-storage space for arguments, local variables, intermediate values, and
-some bookkeeping information (such as what to do after the frame
-computes its value).
+The stack of Guile's virtual machine is composed of @dfn{frames}. Each
+frame corresponds to the application of one compiled procedure, and
+contains storage space for arguments, local variables, and some
+bookkeeping information (such as what to do after the frame is
+finished).
 
 While the compiler is free to do whatever it wants to, as long as the
 semantics of a computation are preserved, in practice every time you
 call a function, a new frame is created. (The notable exception of
 course is the tail call case, @pxref{Tail Calls}.)
 
-Within a frame, you have the data associated with the function
-application itself, which is of a fixed size, and the stack space for
-intermediate values. Sometimes only the former is referred to as the
-``frame'', and the latter is the ``stack'', although all pending
-application frames can have some intermediate computations interleaved
-on the stack.
-
-The structure of the fixed part of an application frame is as follows:
+The structure of the top stack frame is as follows:
 
 @example
-             Stack
+   /------------------\ <- top of stack
+   | Local N-1        | <- sp
    | ...              |
-   | Intermed. val. 0 | <- fp + bp->nargs + bp->nlocs = 
SCM_FRAME_UPPER_ADDRESS (fp)
+   | Local 1          |
+   | Local 0          | <- fp = SCM_FRAME_LOCALS_ADDRESS (fp)
    +==================+
-   | Local variable 1 |
-   | Local variable 0 | <- fp + bp->nargs
-   | Argument 1       |
-   | Argument 0       | <- fp
-   | Program          | <- fp - 1
-   +------------------+    
    | Return address   |
-   | MV return address|
-   | Dynamic link     | <- fp - 4 = SCM_FRAME_DATA_ADDRESS (fp) = 
SCM_FRAME_LOWER_ADDRESS (fp)
+   | Dynamic link     | <- fp - 2 = SCM_FRAME_LOWER_ADDRESS (fp)
    +==================+
-   |                  |
+   |                  | <- fp - 3 = SCM_FRAME_PREVIOUS_SP (fp)
 @end example
 
-In the above drawing, the stack grows upward. The intermediate values
-stored in the application of this frame are stored above
address@hidden (fp)}. @code{bp} refers to the
address@hidden scm_objcode} data associated with the program at
address@hidden - 1}. @code{nargs} and @code{nlocs} are properties of the
-compiled procedure, which will be discussed later.
-
-The individual fields of the frame are as follows:
-
address@hidden @asis
address@hidden Return address
-The @code{ip} that was in effect before this program was applied. When
-we return from this activation frame, we will jump back to this
address@hidden
-
address@hidden MV return address
-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
-values being returned.
-
address@hidden 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''. The dynamic link links the current frame to the previous
-frame; computing a stack trace involves traversing these frames.
-
address@hidden Local variable @var{n}
-Lambda-local variables that are all allocated as part of the frame.
-This makes access to variables very cheap.
-
address@hidden 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. References
-to arguments dispatch to these locations on the stack.
-
address@hidden Program
-This is the program being applied. For more information on how
-programs are implemented, @xref{VM Programs}.
address@hidden table
+In the above drawing, the stack grows upward.  Usually the procedure
+being applied is in local 0, followed by the arguments from local 1.
+After that are enough slots to store the various lexically-bound and
+temporary values that are needed in the function's application.
+
+The @dfn{return address} is the @code{ip} that was in effect before this
+program was applied.  When we return from this activation frame, we will
+jump back to this @code{ip}.  Likewise, the @dfn{dynamic link} is the
address@hidden in effect before this program was applied.
+
+To prepare for a non-tail application, Guile's VM will emit code that
+shuffles the function to apply and its arguments into appropriate stack
+slots, with two free slots below them.  The call then initializes those
+free slots with the current @code{ip} and @code{fp}, and updates
address@hidden to point to the function entry, and @code{fp} to point to the
+new call frame.
+
+In this way, the dynamic link links the current frame to the previous
+frame.  Computing a stack trace involves traversing these frames.
 
 @node Variables and the VM
 @subsection Variables and the VM
@@ -232,16 +184,18 @@ Consider the following Scheme code as an example:
     (lambda (b) (list foo a b)))
 @end example
 
-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.
+Within the lambda expression, @code{foo} is a top-level variable,
address@hidden 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
+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
address@hidden 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.
address@hidden calculus}, a mathematical notation for describing functions.
+The lambda calculus is useful because it is a language in which to
+reason precisely about functions and variables.  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
@@ -275,33 +229,30 @@ lexically bound in this example.
 @subsection Compiled Procedures are VM Programs
 
 By default, when you enter in expressions at Guile's REPL, they are
-first compiled to VM object code, then that VM object code is executed
-to produce a value. If the expression evaluates to a procedure, the
-result of this process is a compiled procedure.
-
-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)}. @xref{Compiled Procedures}, for a full API reference.
-
address@hidden object table
address@hidden object array
-The object array of a compiled procedure, also known as the
address@hidden 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}.
address@hidden 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
-object will remain constant over time, even if the value bound to it
-changes. Therefore, toplevel bindings only need to be looked up once.
-Thereafter, references to the corresponding toplevel variables from
-within the program are then performed via the @code{toplevel-ref}
-instruction, which uses the object vector, and are almost as fast as
-local variable references.
+first compiled to bytecode.  Then that bytecode is executed to produce a
+value.  If the expression evaluates to a procedure, the result of this
+process is a compiled procedure.
+
+A compiled procedure is a compound object consisting of its bytecode and
+a reference to any captured lexical variables.  In addition, when a
+procedure is compiled, it has associated metadata written to side
+tables, for instance a line number mapping, or its docstring.  You can
+pick apart these pieces with the accessors in @code{(system vm
+program)}.  @xref{Compiled Procedures}, for a full API reference.
+
+A procedure may reference data that was statically allocated when the
+procedure was compiled.  For example, a pair of immediate objects
+(@pxref{Immediate objects}) can be allocated directly in the memory
+segment that contains the compiled bytecode, and accessed directly by
+the bytecode.
+
+Another use for statically allocated data is to serve as a cache for a
+bytecode.  Top-level variable lookups are handled in this way.  If the
address@hidden instruction finds that it does not have a cached
+variable for a top-level reference, it accesses other static data to
+resolve the reference, and fills in the cache slot.  Thereafter all
+access to the variable goes through the cache cell.  The variable's
+value may change in the future, but the variable itself will not.
 
 We can see how these concepts tie together by disassembling the
 @code{foo} function we defined earlier to see what is going on:
@@ -309,53 +260,124 @@ We can see how these concepts tie together by 
disassembling the
 @smallexample
 scheme@@(guile-user)> (define (foo a) (lambda (b) (list foo a b)))
 scheme@@(guile-user)> ,x foo
-   0    (assert-nargs-ee/locals 1)      
-   2    (object-ref 1)                  ;; #<procedure 8ebec20 at <current 
input>:0:17 (b)>
-   4    (local-ref 0)                   ;; `a'
-   6    (make-closure 0 1)              
-   9    (return)                        
+Disassembly of #<procedure foo (a)> at #x203be34:
+
+   0    (assert-nargs-ee/locals 2 1)    ;; 1 arg, 1 local     at (unknown 
file):1:0
+   1    (make-closure 2 6 1)            ;; anonymous procedure at #x203be50 (1 
free var)
+   4    (free-set! 2 1 0)               ;; free var 0
+   6    (return 2)
 
 ----------------------------------------
-Disassembly of #<procedure 8ebec20 at <current input>:0:17 (b)>:
-
-   0    (assert-nargs-ee/locals 1)      
-   2    (toplevel-ref 1)                ;; `foo'
-   4    (free-ref 0)                    ;; (closure variable)
-   6    (local-ref 0)                   ;; `b'
-   8    (list 0 3)                      ;; 3 elements         at (unknown 
file):0:29
-  11    (return)                        
+Disassembly of anonymous procedure at #x203be50:
+
+   0    (assert-nargs-ee/locals 2 3)    ;; 1 arg, 3 locals    at (unknown 
file):1:0
+   1    (toplevel-box 2 73 57 71 #t)    ;; `foo'
+   6    (box-ref 2 2)
+   7    (make-short-immediate 3 772)    ;; ()
+   8    (cons 3 1 3)
+   9    (free-ref 4 0 0)                ;; free var 0
+  11    (cons 3 4 3)
+  12    (cons 2 2 3)
+  13    (return 2)
 @end smallexample
 
-First there's some prelude, where @code{foo} checks that it was called with 
only
-1 argument. Then at @code{ip} 2, we load up the compiled lambda. @code{Ip} 4
-loads up `a', so that it can be captured into a closure by at @code{ip}
-6---binding code (from the compiled lambda) with data (the free-variable
-vector). Finally we return the closure.
-
-The second stanza disassembles the compiled lambda. After the prelude, we note
-that 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. @xref{Top-Level Environment 
Instructions},
-for more details.
-
-Then we see a reference to a free 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 the @code{list} opcode, an inline implementation of the
address@hidden scheme routine.
+First there's some prelude, where @code{foo} checks that it was called
+with only 1 argument.  Then at @code{ip} 1, we allocate a new closure
+and store it in slot 2.  The `6' in the @code{(make-closure 2 6 1)} is a
+relative offset from the instruction pointer of the code for the
+closure.
+
+A closure is code with data.  We already have the code part initialized;
+what remains is to set the data.  @code{Ip} 4 initializes free variable
+0 in the new closure with the value from local variable 1, which
+corresponds to the first argument of @code{foo}: `a'.  Finally we return
+the closure.
+
+The second stanza disassembles the code for the closure.  After the
+prelude, we load the variable for the toplevel variable @code{foo} into
+local variable 2.  This lookup occurs lazily, the first time the
+variable is actually referenced, and the location of the lookup is
+cached so that future references are very cheap.  @xref{Top-Level
+Environment Instructions}, for more details.  The @code{box-ref}
+dereferences the variable cell, replacing the contents of local 2.
+
+What follows is a sequence of conses to build up the result list.
address@hidden 7 makes the tail of the list.  @code{Ip} 8 conses on the value
+in local 1, corresponding to the first argument to the closure: `b'.
address@hidden 9 loads free variable 0 of local 0 -- the procedure being
+called -- into slot 4, then @code{ip} 11 conses it onto the list.
+Finally we cons local 2, containing the @code{foo} toplevel, onto the
+front of the list, and we return it.
 
 @node Instruction Set
 @subsection Instruction Set
 
-There are about 180 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.
+There are currently about 130 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.
+
+Instructions themselves are composed of 1 or more 32-bit units.  The low
+8 bits of the first word indicate the opcode, and the rest of
+instruction describe the operands.  There are a number of different ways
+operands can be encoded.
+
address@hidden @code
address@hidden address@hidden
+An unsigned @var{n}-bit integer.  Usually indicates the index of a local
+variable, but some instructions interpret these operands as immediate
+values.
address@hidden l24
+An offset from the current @code{ip}, in 32-bit units, as a signed
+24-bit value.  Indicates a bytecode address, for a relative jump.
address@hidden i16
address@hidden i32
+An immediate Scheme value (@pxref{Immediate objects}), encoded directly
+in 16 or 32 bits.
address@hidden a32
address@hidden b32
+An immediate Scheme value, encoded as a pair of 32-bit words.
address@hidden and @code{b32} values always go together on the same opcode,
+and indicate the high and low bits, respectively.  Normally only used on
+64-bit systems.
address@hidden n32
+A statically allocated non-immediate.  The address of the non-immediate
+is encoded as a signed 32-bit integer, and indicates a relative offset
+in 32-bit units.  Think of it as @code{SCM x = ip + offset}.
address@hidden s32
+Indirect scheme value, like @code{n32} but indirected.  Think of it as
address@hidden *x = ip + offset}.
address@hidden l32
address@hidden lo32
+An ip-relative address, as a signed 32-bit integer.  Could indicate a
+bytecode address, as in @code{make-closure}, or a non-immediate address,
+as with @code{static-patch!}.
+
address@hidden and @code{lo32} are the same from the perspective of the
+virtual machine.  The difference is that an assembler might want to
+allow an @code{lo32} address to be specified as a label and then some
+number of words offset from that label, for example when patching a
+field of a statically allocated object.
address@hidden b1
+A boolean value: 1 for true, otherwise 0.
address@hidden address@hidden
+An ignored sequence of @var{n} bits.
address@hidden table
+
+An instruction is specified by giving its name, then describing its
+operands.  The operands are packed by 32-bit words, with earlier
+operands occupying the lower bits.
+
+For example, consider the following instruction specification:
 
-Instructions themselves are one byte long. Some instructions take
-parameters, which follow the instruction byte in the instruction
-stream.
address@hidden Instruction {} free-set! u12:@var{dst} u12:@var{src} x8:@var{_} 
u24:@var{idx}
+Set free variable @var{idx} from the closure @var{dst} to @var{src}.
address@hidden deftypefn
+
+The first word in the instruction will start with the 8-bit value
+corresponding to the @var{free-set!} opcode in the low bits, followed by
address@hidden and @var{src} as 12-bit values.  The second word starts with 8
+dead bits, followed by the index as a 24-bit immediate value.
 
 Sometimes the compiler can figure out that it is compiling a special
 case that can be run more efficiently. So, for example, while Guile
@@ -371,28 +393,27 @@ their own test-and-branch instructions:
 @end example
 
 In addition, some Scheme primitives have their own inline
-implementations, e.g.@: @code{cons}, and @code{list}, as we saw in the
-previous section.
+implementations.  For example, in the previous section we saw
address@hidden
 
-So Guile's instruction set is a @emph{complete} instruction set, in
-that it provides the instructions that are suited to the problem, and
-is not concerned with making a minimal, orthogonal set of
-instructions. More instructions may be added over time.
+Guile's instruction set is a @emph{complete} instruction set, in that it
+provides the instructions that are suited to the problem, and is not
+concerned with making a minimal, orthogonal set of instructions. More
+instructions may be added over time.
 
 @menu
-* Lexical Environment Instructions::  
-* Top-Level Environment Instructions::  
-* Procedure Call and Return Instructions::  
-* Function Prologue Instructions::  
-* Trampoline Instructions::  
-* Branch Instructions::         
-* Data Constructor Instructions::   
-* Loading Instructions::  
-* Dynamic Environment Instructions::  
-* Miscellaneous Instructions::  
-* Inlined Scheme Instructions::  
-* Inlined Mathematical Instructions::  
-* Inlined Bytevector Instructions::  
+* Lexical Environment Instructions::
+* Top-Level Environment Instructions::
+* Procedure Call and Return Instructions::
+* Function Prologue Instructions::
+* Trampoline Instructions::
+* Branch Instructions::
+* Constant Instructions::
+* Dynamic Environment Instructions::
+* Miscellaneous Instructions::
+* Inlined Scheme Instructions::
+* Inlined Mathematical Instructions::
+* Inlined Bytevector Instructions::
 @end menu
 
 
@@ -400,101 +421,61 @@ instructions. More instructions may be added over time.
 @subsubsection Lexical Environment Instructions
 
 These instructions access and mutate the lexical environment of a
-compiled procedure---its free and bound variables.
-
-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.
-
address@hidden Layout}, for more information on the format of stack frames.
-
address@hidden Instruction local-ref index
address@hidden Instruction long-local-ref index
-Push onto the stack the value of the local variable located at
address@hidden within the current stack frame.
-
-Note that arguments and local variables are all in one block. Thus the
-first argument, if any, is at index 0, and local bindings follow the
-arguments.
address@hidden deffn
-
address@hidden Instruction local-set index
address@hidden Instruction long-local-set index
-Pop the Scheme object located on top of the stack and make it the new
-value of the local variable located at @var{index} within the current
-stack frame.
address@hidden deffn
-
address@hidden 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.
address@hidden deffn
-
address@hidden Instruction empty-box index
-Set the @var{index}th local variable to a box containing a variable
-whose value is unbound. Used when compiling some @code{letrec}
-expressions.
address@hidden deffn
-
address@hidden Instruction local-boxed-ref index
address@hidden Instruction local-boxed-set index
-Get or set the value of the variable located at @var{index} within the
-current stack frame. A shortcut for @code{local-ref} then
address@hidden or @code{variable-set}, respectively.
address@hidden deffn
-
address@hidden Instruction free-ref index
-Push the value of the captured variable located at position
address@hidden within the program's vector of captured variables.
address@hidden deffn
-
address@hidden Instruction free-boxed-ref index
address@hidden Instruction free-boxed-set index
-Get or set a boxed free variable. A shortcut for @code{free-ref} then
address@hidden or @code{variable-set}, respectively.
-
-Note that there is no @code{free-set} instruction, as variables that are
address@hidden must be boxed.
address@hidden deffn
-
address@hidden Instruction make-closure num-free-vars
-Pop @var{num-free-vars} values and a program object off the stack in
-that order, and push a new program object closing over the given free
-variables. @var{num-free-vars} is encoded as a two-byte big-endian
-value.
-
-The free variables are stored in an array, inline to the new program
-object, in the order that they were on the stack (not the order they are
-popped off). The new closure shares state with the original program. At
-the time of this writing, the space overhead of closures is 3 words,
-plus one word for each free variable.
address@hidden deffn
-
address@hidden Instruction fix-closure index
-Fix up the free variables array of the closure stored in the
address@hidden local variable. @var{index} is a two-byte big-endian
-integer.
-
-This instruction will pop as many values from the stack as are in the
-corresponding closure's free variables array. The topmost value on the
-stack will be stored as the closure's last free variable, with other
-values filling in free variable slots in order.
-
address@hidden is part of a hack for allocating mutually recursive
-procedures. The hack is to store the procedures in their corresponding
-local variable slots, with space already allocated for free variables.
-Then once they are all in place, this instruction fixes up their
-procedures' free variable bindings in place. This allows most
address@hidden procedures to be allocated unboxed on the stack.
address@hidden deffn
-
address@hidden Instruction local-bound? index
address@hidden Instruction long-local-bound? index
-Push @code{#t} on the stack if the @code{index}th local variable has
-been assigned, or @code{#f} otherwise. Mostly useful for handling
-optional arguments in procedure prologues.
address@hidden deffn
+compiled procedure---its free and bound variables.  @xref{Stack Layout},
+for more information on the format of stack frames.
+
address@hidden Instruction {} mov u12:@var{dst} u12:@var{src}
address@hidden Instruction {} long-mov u24:@var{dst} x8:@var{_} u24:@var{src}
+Copy a value from one local slot to another.
+
+As discussed previously, procedure arguments and local variables are
+allocated to local slots.  Guile's compiler tries to avoid shuffling
+variables around to different slots, which often makes @code{mov}
+instructions redundant.  However there are some cases in which shuffling
+is necessary, and in those cases, @code{mov} is the thing to use.
address@hidden deftypefn
+
address@hidden Instruction {} make-closure u24:@var{dst} l32:@var{offset} 
x8:@var{_} u24:@var{nfree}
+Make a new closure, and write it to @var{dst}.  The code for the closure
+will be found at @var{offset} words from the current @code{ip}.
address@hidden is a signed 32-bit integer.  Space for @var{nfree} free
+variables will be allocated.
+
+The size of a closure is currently two words, plus one word per free
+variable.
address@hidden deftypefn
+
address@hidden Instruction {} free-ref u12:@var{dst} u12:@var{src} x8:@var{_} 
u24:@var{idx}
+Load free variable @var{idx} from the closure @var{src} into local slot
address@hidden
address@hidden deftypefn
+
address@hidden Instruction {} free-set! u12:@var{dst} u12:@var{src} x8:@var{_} 
u24:@var{idx}
+Set free variable @var{idx} from the closure @var{dst} to @var{src}.
+
+This instruction is usually used when initializing a closure's free
+variables, but not to mutate free variables, as variables that are
+assigned are boxed.
address@hidden deftypefn
+
+Recall that variables that are assigned are usually allocated in boxes,
+so that continuations and closures can capture their identity and not
+their value at one point in time.  Variables are also used in the
+implementation of top-level bindings; see the next section for more
+information.
+
address@hidden Instruction {} box u12:@var{dst} u12:@var{src}
+Create a new variable holding @var{src}, and place it in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} box-ref u12:@var{dst} u12:@var{src}
+Unpack the variable at @var{src} into @var{dst}, asserting that the
+variable is actually bound.
address@hidden deftypefn
+
address@hidden Instruction {} box-set! u12:@var{dst} u12:@var{src}
+Set the contents of the variable at @var{dst} to @var{set}.
address@hidden deftypefn
 
 
 @node Top-Level Environment Instructions
@@ -508,210 +489,133 @@ The location in which a toplevel binding is stored can 
be looked up once
 and cached for later. The binding itself may change over time, but its
 location will stay constant.
 
-Currently only toplevel references within procedures are cached, as only
-procedures have a place to cache them, in their object tables.
-
address@hidden Instruction toplevel-ref index
address@hidden Instruction long-toplevel-ref index
-Push the value of the toplevel binding whose location is stored in at
-position @var{index} in the current procedure's object table. The
address@hidden variant encodes the index over two bytes.
-
-Initially, a cell in a procedure's object table that is used by
address@hidden is initialized to one of two forms. The normal case
-is that the cell holds a symbol, whose binding will be looked up
-relative to the module that was current when the current program was
-created.
-
-Alternately, the lookup may be performed relative to a particular
-module, determined at compile-time (e.g.@: via @code{@@} or
address@hidden@@@@}). In that case, the cell in the object table holds a list:
address@hidden(@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
-in-place mutation of the object table. This mechanism provides for
-lazy variable resolution, and an important cached fast-path once the
-variable has been successfully resolved.
-
-This instruction pushes the value of the variable onto the stack.
address@hidden deffn
-
address@hidden Instruction toplevel-set index
address@hidden Instruction long-toplevel-set index
-Pop a value off the stack, and set it as the value of the toplevel
-variable stored at @var{index} in the object table. If the variable
-has not yet been looked up, we do the lookup as in
address@hidden
address@hidden deffn
-
address@hidden 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.
address@hidden deffn
-
address@hidden 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
-on the stack. If the lookup fails, an error will be signalled.
-
-This instruction is mostly used when loading programs, because it can
-do toplevel variable lookups without an object table.
address@hidden deffn
-
address@hidden Instruction variable-ref
-Dereference the variable object which is on top of the stack and
-replace it by the value of the variable it represents.
address@hidden deffn
-
address@hidden Instruction variable-set
-Pop off two objects from the stack, a variable and a value, and set
-the variable to the value.
address@hidden deffn
-
address@hidden Instruction variable-bound?
-Pop off the variable object from top of the stack and push @code{#t} if
-it is bound, or @code{#f} otherwise. Mostly useful in procedure
-prologues for defining default values for boxed optional variables.
address@hidden deffn
-
address@hidden Instruction make-variable
-Replace the top object on the stack with a variable containing it.
-Used in some circumstances when compiling @code{letrec} expressions.
address@hidden deffn
address@hidden Instruction {} current-module u24:@var{dst}
+Store the current module in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} resolve u24:@var{dst} b1:@var{bound?} x7:@var{_} 
u24:@var{sym}
+Resolve @var{sym} in the current module, and place the resulting
+variable in @var{dst}.  An error will be signalled if no variable is
+found.  If @var{bound?} is true, an error will be signalled if the
+variable is unbound.
address@hidden deftypefn
+
address@hidden Instruction {} define! u12:@var{sym} u12:@var{val}
+Look up a binding for @var{sym} in the current module, creating it if
+necessary.  Set its value to @var{val}.
address@hidden deftypefn
+
address@hidden Instruction {} toplevel-box u24:@var{dst} s32:@var{var-offset} 
s32:@var{mod-offset} n32:@var{sym-offset} b1:@var{bound?} x31:@var{_}
+Load a value.  The value will be fetched from memory, @var{var-offset}
+32-bit words away from the current instruction pointer.
address@hidden is a signed value.  Up to here, @code{toplevel-box} is
+like @code{static-ref}.
+
+Then, if the loaded value is a variable, it is placed in @var{dst}, and
+control flow continues.
+
+Otherwise, we have to resolve the variable.  In that case we load the
+module from @var{mod-offset}, just as we loaded the variable.  Usually
+the module gets set when the closure is created.  @var{sym-offset}
+specifies the name, as an offset to a symbol.
+
+We use the module and the symbol to resolve the variable, placing it in
address@hidden, and caching the resolved variable so that we will hit the
+cache next time.  If @var{bound?} is true, an error will be signalled if
+the variable is unbound.
address@hidden deftypefn
+
address@hidden Instruction {} module-box u24:@var{dst} s32:@var{var-offset} 
n32:@var{mod-offset} n32:@var{sym-offset} b1:@var{bound?} x31:@var{_}
+Like @code{toplevel-box}, except @var{mod-offset} points at a module
+identifier instead of the module itself.  A module identifier is a
+module name, as a list, prefixed by a boolean.  If the prefix is true,
+then the variable is resolved relative to the module's public interface
+instead of its private interface.
address@hidden deftypefn
 
 
 @node Procedure Call and Return Instructions
 @subsubsection Procedure Call and Return Instructions
 
address@hidden something about the calling convention here?
-
address@hidden Instruction 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.
address@hidden deffn
-
address@hidden Instruction call nargs
-Call the procedure located at @code{sp[-nargs]} with the @var{nargs}
-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
address@hidden + 1]}, the arguments don't have to be shuffled around --
-they are already in place.
address@hidden deffn
-
address@hidden Instruction tail-call nargs
-Transfer control to the procedure located at @code{sp[-nargs]} with the
address@hidden arguments located from @code{sp[-nargs + 1]} to
address@hidden
-
-Unlike @code{call}, which requires a new frame to be pushed onto the
-stack, @code{tail-call} simply shuffles down the procedure and arguments
-to the current stack frame. This instruction implements tail calls as
-required by RnRS.
address@hidden deffn
-
address@hidden Instruction apply nargs
address@hidden 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.
address@hidden deffn
-
address@hidden Instruction call/nargs
address@hidden 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.
address@hidden deffn
-
address@hidden 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 three-byte value) is an offset within the instruction
-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.
address@hidden deffn
-
address@hidden 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
address@hidden, the @code{ip} is reset to the current return address, the
address@hidden is reset to the value of the current dynamic link, and then
-the returned value is pushed on the stack.
address@hidden deffn
-
address@hidden Instruction return/values nvalues
address@hidden Instruction return/nvalues
-Return the top @var{nvalues} to the current continuation. In the case of
address@hidden/nvalues}, @var{nvalues} itself is first popped from the top
-of the stack.
-
-If the current continuation is a multiple-value continuation,
address@hidden/values} pushes the number of values on the stack, then
-returns as in @code{return}, but to the multiple-value return address.
-
-Otherwise if the current continuation accepts only one value, i.e.@: the
-multiple-value return address is @code{NULL}, then we assume the user
-only wants one value, and we give them the first one. If there are no
-values, an error is signaled.
address@hidden deffn
-
address@hidden Instruction return/values* nvalues
-Like a combination of @code{apply} and @code{return/values}, in which
-the top value on the stack is interpreted as a list of additional
-values. This is an optimization for the common @code{(apply values
-...)} case.
address@hidden deffn
-
address@hidden Instruction truncate-values nbinds nrest
-Used in multiple-value continuations, this instruction takes the
-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
address@hidden In that case, @var{nbinds} would be 3, and @var{nrest} would
-be 1 (to indicate that one of the bindings was a rest argument).
-
-Signals an error if there is an insufficient number of values.
address@hidden deffn
-
address@hidden Instruction call/cc
address@hidden 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.
-
address@hidden/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.
address@hidden deffn
+As described earlier (@pxref{Stack Layout}), Guile's calling convention
+is that arguments are passed and values returned on the stack.
+
+For calls, both in tail position and in non-tail position, we require
+that the procedure and the arguments already be shuffled into place
+befor the call instruction.  ``Into place'' for a tail call means that
+the procedure should be in slot 0, and the arguments should follow.  For
+a non-tail call, if the procedure is in slot @var{n}, the arguments
+should follow from slot @var{n}+1, and there should be two free slots at
address@hidden and @var{n}-2 in which to save the @code{ip} and @code{fp}.
+
+Returning values is similar.  Multiple-value returns should have values
+already shuffled down to start from slot 1 before emitting
address@hidden  There is a short-cut in the single-value case, in
+that @code{return} handles the trivial shuffling itself.  We start from
+slot 1 instead of slot 0 to make tail calls to @code{values} trivial.
+
+In both calls and returns, the @code{sp} is used to indicate to the
+callee or caller the number of arguments or return values, respectively.
+After receiving return values, it is the caller's responsibility to
address@hidden the frame} by resetting the @code{sp} to its former value.
+
address@hidden Instruction {} call u24:@var{proc} x8:@var{_} u24:@var{nlocals}
+Call a procedure.  @var{proc} is the local corresponding to a procedure.
+The two values below @var{proc} will be overwritten by the saved call
+frame data.  The new frame will have space for @var{nlocals} locals: one
+for the procedure, and the rest for the arguments which should already
+have been pushed on.
+
+When the call returns, execution proceeds with the next instruction.
+There may be any number of values on the return stack; the precise
+number can be had by subtracting the address of @var{proc} from the
+post-call @code{sp}.
address@hidden deftypefn
+
address@hidden Instruction {} tail-call u24:@var{nlocals}
+Tail-call a procedure.  Requires that the procedure and all of the
+arguments have already been shuffled into position.  Will reset the
+frame to @var{nlocals}.
address@hidden deftypefn
+
address@hidden Instruction {} tail-call/shuffle u24:@var{from}
+Tail-call a procedure.  The procedure should already be set to slot 0.
+The rest of the args are taken from the frame, starting at @var{from},
+shuffled down to start at slot 0.  This is part of the implementation of
+the @code{call-with-values} builtin.
address@hidden deftypefn
+
address@hidden Instruction {} receive u12:@var{dst} u12:@var{proc} x8:@var{_} 
u24:@var{nlocals}
+Receive a single return value from a call whose procedure was in
address@hidden, asserting that the call actually returned at least one
+value.  Afterwards, resets the frame to @var{nlocals} locals.
address@hidden deftypefn
+
address@hidden Instruction {} receive-values u24:@var{proc} 
b1:@var{allow-extra?} x7:@var{_} u24:@var{nvalues}
+Receive a return of multiple values from a call whose procedure was in
address@hidden  If fewer than @var{nvalues} values were returned, signal an
+error.  Unless @var{allow-extra?} is true, require that the number of
+return values equals @var{nvalues} exactly.  After @code{receive-values}
+has run, the values can be copied down via @code{mov}, or used in place.
address@hidden deftypefn
+
address@hidden Instruction {} return u24:@var{src}
+Return a value.
address@hidden deftypefn
+
address@hidden Instruction {} return-values x24:@var{_}
+Return a number of values from a call frame.  This opcode corresponds to
+an application of @code{values} in tail position.  As with tail calls,
+we expect that the values have already been shuffled down to a
+contiguous array starting at slot 1.  We also expect the frame has
+already been reset.
address@hidden deftypefn
+
address@hidden Instruction {} call/cc x24:@var{_}
+Capture the current continuation, and tail-apply the procedure in local
+slot 1 to it.  This instruction is part of the implementation of
address@hidden/cc}, and is not generated by the compiler.
address@hidden deftypefn
 
 
 @node Function Prologue Instructions
@@ -728,374 +632,297 @@ cost of parsing keyword arguments. (At the time of this 
writing, calling
 procedures with keyword arguments is typically two to four times as
 costly as calling procedures with a fixed set of arguments.)
 
address@hidden Instruction assert-nargs-ee n
address@hidden Instruction assert-nargs-ge n
-Assert that the current procedure has been passed exactly @var{n}
-arguments, for the @code{-ee} case, or @var{n} or more arguments, for
-the @code{-ge} case. @var{n} is encoded over two bytes.
address@hidden Instruction {} assert-nargs-ee u24:@var{expected}
address@hidden Instruction {} assert-nargs-ge u24:@var{expected}
address@hidden Instruction {} assert-nargs-le u24:@var{expected}
+If the number of actual arguments is not @code{==}, @code{>=}, or
address@hidden<=} @var{expected}, respectively, signal an error.
 
 The number of arguments is determined by subtracting the frame pointer
-from the stack pointer (@code{sp - (fp -1)}). @xref{Stack Layout}, for
-more details on stack frames.
address@hidden deffn
-
address@hidden Instruction br-if-nargs-ne n offset
address@hidden Instruction br-if-nargs-gt n offset
address@hidden Instruction br-if-nargs-lt n offset
-Jump to @var{offset} if the number of arguments is not equal to, greater
-than, or less than @var{n}. @var{n} is encoded over two bytes, and
address@hidden has the normal three-byte encoding.
+from the stack pointer (@code{sp + 1 - fp}). @xref{Stack Layout}, for
+more details on stack frames.  Note that @var{expected} includes the
+procedure itself.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-nargs-ne u24:@var{expected} x8:@var{_} 
l24:@var{offset}
address@hidden Instruction {} br-if-nargs-lt u24:@var{expected} x8:@var{_} 
l24:@var{offset}
address@hidden Instruction {} br-if-nargs-gt u24:@var{expected} x8:@var{_} 
l24:@var{offset}
+If the number of actual arguments is not equal, less than, or greater
+than @var{expected}, respectively, add @var{offset}, a signed 24-bit
+number, to the current instruction pointer.  Note that @var{expected}
+includes the procedure itself.
 
 These instructions are used to implement multiple arities, as in
 @code{case-lambda}. @xref{Case-lambda}, for more information.
address@hidden deffn
-
address@hidden Instruction bind-optionals n
-If the procedure has been called with fewer than @var{n} arguments, fill
-in the remaining arguments with an unbound value (@code{SCM_UNDEFINED}).
address@hidden is encoded over two bytes.
-
-The optionals can be later initialized conditionally via the
address@hidden instruction.
address@hidden deffn
-
address@hidden Instruction push-rest n
-Pop off excess arguments (more than @var{n}), collecting them into a
-list, and push that list. Used to bind a rest argument, if the procedure
-has no keyword arguments. Procedures with keyword arguments use
address@hidden instead.
address@hidden deffn
-
address@hidden Instruction bind-rest n idx
-Pop off excess arguments (more than @var{n}), collecting them into a
-list. The list is then assigned to the @var{idx}th local variable.
address@hidden deffn
-
address@hidden Instruction bind-optionals/shuffle nreq nreq-and-opt ntotal
address@hidden Instruction bind-optionals/shuffle-or-br nreq nreq-and-opt 
ntotal offset
-Shuffle keyword arguments to the top of the stack, filling in the holes
-with @code{SCM_UNDEFINED}. Each argument is encoded over two bytes.
-
-This instruction is used by procedures with keyword arguments.
address@hidden is the number of required arguments to the procedure, and
address@hidden is the total number of positional arguments (required
-plus optional). @code{bind-optionals/shuffle} will scan the stack from
-the @var{nreq}th argument up to the @var{nreq-and-opt}th, and start
-shuffling when it sees the first keyword argument or runs out of
-positional arguments.
-
address@hidden/shuffle-or-br} does the same, except that it checks
-if there are too many positional arguments before shuffling.  If this is
-the case, it jumps to @var{offset}, encoded using the normal three-byte
-encoding.
-
-Shuffling simply moves the keyword arguments past the total number of
-arguments, @var{ntotal}, which includes keyword and rest arguments. The
-free slots created by the shuffle are filled in with
address@hidden, so they may be conditionally initialized later in
-the function's prologue.
address@hidden deffn
-
address@hidden Instruction bind-kwargs idx ntotal flags
-Parse keyword arguments, assigning their values to the corresponding
-local variables. The keyword arguments should already have been shuffled
-above the @var{ntotal}th stack slot by @code{bind-optionals/shuffle}.
address@hidden deftypefn
+
address@hidden Instruction {} alloc-frame u24:@var{nlocals}
+Ensure that there is space on the stack for @var{nlocals} local
+variables, setting them all to @code{SCM_UNDEFINED}, except those values
+that are already on the stack.
address@hidden deftypefn
+
address@hidden Instruction {} reset-frame u24:@var{nlocals}
+Like @code{alloc-frame}, but doesn't check that the stack is big enough,
+and doesn't initialize values to @code{SCM_UNDEFINED}.  Used to reset
+the frame size to something less than the size that was previously set
+via alloc-frame.
address@hidden deftypefn
+
address@hidden Instruction {} assert-nargs-ee/locals u12:@var{expected} 
u12:@var{nlocals}
+Equivalent to a sequence of @code{assert-nargs-ee} and
address@hidden  The number of locals reserved is @var{expected}
++ @var{nlocals}.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-npos-gt u24:@var{nreq} x8:@var{_} 
u24:@var{npos} x8:@var{_} l24:@var{offset}
+Find the first positional argument after @var{nreq}.  If it is greater
+than @var{npos}, jump to @var{offset}.
+
+This instruction is only emitted for functions with multiple clauses,
+and an earlier clause has keywords and no rest arguments.
address@hidden, for more on how @code{case-lambda} chooses the
+clause to apply.
address@hidden deftypefn
+
address@hidden Instruction {} bind-kwargs u24:@var{nreq} u8:@var{flags} 
u24:@var{nreq-and-opt} x8:@var{_} u24:@var{ntotal} n32:@var{kw-offset}
address@hidden is a bitfield, whose lowest bit is @var{allow-other-keys},
+second bit is @var{has-rest}, and whose following six bits are unused.
+
+Find the last positional argument, and shuffle all the rest above
address@hidden  Initialize the intervening locals to
address@hidden  Then load the constant at @var{kw-offset} words
+from the current @var{ip}, and use it and the @var{allow-other-keys}
+flag to bind keyword arguments.  If @var{has-rest}, collect all shuffled
+arguments into a list, and store it in @var{nreq-and-opt}.  Finally,
+clear the arguments that we shuffled up.
 
 The parsing is driven by a keyword arguments association list, looked up
-from the @var{idx}th element of the procedures object array. The alist
-is a list of pairs of the form @code{(@var{kw} . @var{index})}, mapping
-keyword arguments to their local variable indices.
-
-There are two bitflags that affect the parser, @code{allow-other-keys?}
-(@code{0x1}) and @code{rest?} (@code{0x2}). Unless
address@hidden is set, the parser will signal an error if an
-unknown key is found. If @code{rest?} is set, errors parsing the
-keyword arguments will be ignored, as a later @code{bind-rest}
-instruction will collect all of the tail arguments, including the
-keywords, into a list. Otherwise if the keyword arguments are invalid,
-an error is signalled.
-
address@hidden and @var{ntotal} are encoded over two bytes each, and
address@hidden is encoded over one byte.
address@hidden deffn
-
address@hidden Instruction reserve-locals n
-Resets the stack pointer to have space for @var{n} local variables,
-including the arguments. If this operation increments the stack pointer,
-as in a push, the new slots are filled with @code{SCM_UNBOUND}. If this
-operation decrements the stack pointer, any excess values are dropped.
-
address@hidden is typically used after argument parsing to
-reserve space for local variables.
address@hidden deffn
-
address@hidden Instruction assert-nargs-ee/locals n
address@hidden Instruction assert-nargs-ge/locals n
-A combination of @code{assert-nargs-ee} and @code{reserve-locals}. The
-number of arguments is encoded in the lower three bits of @var{n}, a
-one-byte value. The number of additional local variables is take from
-the upper 5 bits of @var{n}.
address@hidden deffn
+using @var{kw-offset}.  The alist is a list of pairs of the form
address@hidden(@var{kw} . @var{index})}, mapping keyword arguments to their
+local slot indices.  Unless @code{allow-other-keys} is set, the parser
+will signal an error if an unknown key is found.
+
+A macro-mega-instruction.
address@hidden deftypefn
+
address@hidden Instruction {} bind-rest u24:@var{dst}
+Collect any arguments at or above @var{dst} into a list, and store that
+list at @var{dst}.
address@hidden deftypefn
 
 
 @node Trampoline Instructions
 @subsubsection Trampoline Instructions
 
-Though most applicable objects in Guile are procedures implemented
-in bytecode, not all are. There are primitives, continuations, and other
-procedure-like objects that have their own calling convention. Instead
+Though most applicable objects in Guile are procedures implemented in
+bytecode, not all are.  There are primitives, continuations, and other
+procedure-like objects that have their own calling convention.  Instead
 of adding special cases to the @code{call} instruction, Guile wraps
 these other applicable objects in VM trampoline procedures, then
 provides special support for these objects in bytecode.
 
 Trampoline procedures are typically generated by Guile at runtime, for
-example in response to a call to @code{scm_c_make_gsubr}. As such, a
-compiler probably shouldn't emit code with these instructions. However,
+example in response to a call to @code{scm_c_make_gsubr}.  As such, a
+compiler probably shouldn't emit code with these instructions.  However,
 it's still interesting to know how these things work, so we document
 these trampoline instructions here.
 
address@hidden Instruction subr-call nargs
-Pop off a foreign pointer (which should have been pushed on by the
-trampoline), and call it directly, with the @var{nargs} arguments from
-the stack. Return the resulting value or values to the calling
-procedure.
address@hidden deffn
-
address@hidden Instruction foreign-call nargs
-Pop off an internal foreign object (which should have been pushed on by
-the trampoline), and call that foreign function with the @var{nargs}
-arguments from the stack. Return the resulting value to the calling
-procedure.
address@hidden deffn
-
address@hidden Instruction continuation-call
-Pop off an internal continuation object (which should have been pushed
-on by the trampoline), and reinstate that continuation. All of the
-procedure's arguments are passed to the continuation. Does not return.
address@hidden deffn
-
address@hidden Instruction partial-cont-call
-Pop off two objects from the stack: the dynamic winds associated with
-the partial continuation, and the VM continuation object. Unroll the
-continuation onto the stack, rewinding the dynamic environment and
-overwriting the current frame, and pass all arguments to the
-continuation. Control flow proceeds where the continuation was captured.
address@hidden deffn
address@hidden Instruction {} subr-call u24:@var{ptr-idx}
+Call a subr, passing all locals in this frame as arguments.  Fetch the
+foreign pointer from @var{ptr-idx}, a free variable.  Return from the
+calling frame.
address@hidden deftypefn
+
address@hidden Instruction {} foreign-call u12:@var{cif-idx} u12:@var{ptr-idx}
+Call a foreign function.  Fetch the @var{cif} and foreign pointer from
address@hidden and @var{ptr-idx}, both free variables.  Return from the calling
+frame.  Arguments are taken from the stack.
address@hidden deftypefn
+
address@hidden Instruction {} continuation-call u24:@var{contregs}
+Return to a continuation, nonlocally.  The arguments to the continuation
+are taken from the stack.  @var{contregs} is a free variable containing
+the reified continuation.
address@hidden deftypefn
+
address@hidden Instruction {} compose-continuation u24:@var{cont}
+Compose a partial continution with the current continuation.  The
+arguments to the continuation are taken from the stack.  @var{cont} is a
+free variable containing the reified continuation.
address@hidden deftypefn
+
address@hidden Instruction {} tail-apply x24:@var{_}
+Tail-apply the procedure in local slot 0 to the rest of the arguments.
+This instruction is part of the implementation of @code{apply}, and is
+not generated by the compiler.
address@hidden deftypefn
+
address@hidden Instruction {} builtin-ref u12:@var{dst} u12:@var{idx}
+Load a builtin stub by index into @var{dst}.
address@hidden deftypefn
 
 
 @node Branch Instructions
 @subsubsection Branch Instructions
 
-All the conditional branch instructions described below work in the
-same way:
-
address@hidden
address@hidden They pop off Scheme object(s) located on the stack for use in the
-branch condition
address@hidden If the condition is true, then the instruction pointer is
-increased by the offset passed as an argument to the branch
-instruction;
address@hidden Program execution proceeds with the next instruction (that is,
-the one to which the instruction pointer points).
address@hidden itemize
-
-Note that the offset passed to the instruction is encoded as three 8-bit
-integers, in big-endian order, effectively giving Guile a 24-bit
-relative address space.
-
address@hidden Instruction br offset
-Jump to @var{offset}. No values are popped.
address@hidden deffn
-
address@hidden Instruction br-if offset
-Jump to @var{offset} if the object on the stack is not false.
address@hidden deffn
-
address@hidden Instruction br-if-not offset
-Jump to @var{offset} if the object on the stack is false.
address@hidden deffn
-
address@hidden Instruction br-if-eq offset
-Jump to @var{offset} if the two objects located on the stack are
-equal in the sense of @code{eq?}.  Note that, for this instruction, the
-stack pointer is decremented by two Scheme objects instead of only
-one.
address@hidden deffn
-
address@hidden Instruction br-if-not-eq offset
-Same as @code{br-if-eq} for address@hidden objects.
address@hidden deffn
-
address@hidden Instruction br-if-null offset
-Jump to @var{offset} if the object on the stack is @code{'()}.
address@hidden deffn
-
address@hidden Instruction br-if-not-null offset
-Jump to @var{offset} if the object on the stack is not @code{'()}.
address@hidden deffn
-
-
address@hidden Data Constructor Instructions
address@hidden Data Constructor Instructions
-
-These instructions push simple immediate values onto the stack,
-or construct compound data structures from values on the stack.
-
address@hidden Instruction make-int8 value
-Push @var{value}, an 8-bit integer, onto the stack.
address@hidden deffn
-
address@hidden Instruction make-int8:0
-Push the immediate value @code{0} onto the stack.
address@hidden deffn
-
address@hidden Instruction make-int8:1
-Push the immediate value @code{1} onto the stack.
address@hidden deffn
-
address@hidden Instruction make-int16 value
-Push @var{value}, a 16-bit integer, onto the stack.
address@hidden deffn
-
address@hidden 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).
address@hidden deffn
-
address@hidden 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.
address@hidden deffn
-
address@hidden Instruction make-false
-Push @code{#f} onto the stack.
address@hidden deffn
-
address@hidden Instruction make-true
-Push @code{#t} onto the stack.
address@hidden deffn
-
address@hidden Instruction make-nil
-Push @code{#nil} onto the stack.
address@hidden deffn
-
address@hidden Instruction make-eol
-Push @code{'()} onto the stack.
address@hidden deffn
-
address@hidden Instruction make-char8 value
-Push @var{value}, an 8-bit character, onto the stack.
address@hidden deffn
-
address@hidden Instruction make-char32 value
-Push @var{value}, an 32-bit character, onto the stack. The value is
-encoded in big-endian order.
address@hidden deffn
-
address@hidden Instruction make-symbol
-Pops a string off the stack, and pushes a symbol.
address@hidden deffn
-
address@hidden Instruction make-keyword value
-Pops a symbol off the stack, and pushes a keyword.
address@hidden deffn
-
address@hidden 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.
address@hidden deffn
-
address@hidden 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}.
address@hidden deffn
-
address@hidden Instruction make-struct n
-Make a new struct from the top @var{n} values on the stack. The values
-are popped, and the new struct is pushed.
-
-The deepest value is used as the vtable for the struct, and the rest are
-used in order as the field initializers. Tail arrays are not supported
-by this instruction.
address@hidden deffn
-
address@hidden Instruction make-array n
-Pop an array shape from the stack, then pop the remaining @var{n}
-values, pushing a new array. @var{n} is encoded over three bytes.
-
-The array shape should be appropriate to store @var{n} values.
address@hidden Procedures}, for more information on array shapes.
address@hidden deffn
-
-Many of these data structures are constant, never changing over the
-course of the different invocations of the procedure. In that case it is
-often advantageous to make them once when the procedure is created, and
-just reference them from the object table thereafter. @xref{Variables
-and the VM}, for more information on the object table.
-
address@hidden Instruction object-ref n
address@hidden 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.
address@hidden deffn
-
-
address@hidden Loading Instructions
address@hidden Loading Instructions
-
-In addition to VM instructions, an instruction stream may contain
-variable-length data embedded within it. This data is always preceded
-by special loading instructions, which interpret the data and advance
-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
-is encoded in 3 bytes.
-
address@hidden Instruction load-number length
-Load an arbitrary number from the instruction stream. The number is
-embedded in the stream as a string.
address@hidden deffn
address@hidden Instruction load-string length
-Load a string from the instruction stream. The string is assumed to be
-encoded in the ``latin1'' locale.
address@hidden deffn
address@hidden Instruction load-wide-string length
-Load a UTF-32 string from the instruction stream. @var{length} is the
-length in bytes, not in codepoints.
address@hidden deffn
address@hidden 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}.
address@hidden deffn
address@hidden 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.
address@hidden deffn
-
address@hidden Instruction load-program
-Load bytecode from the instruction stream, and push a compiled
-procedure.
-
-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.
+All offsets to branch instructions are 24-bit signed numbers, which
+count 32-bit units.  This gives Guile effectively a 26-bit address range
+for relative jumps.
+
address@hidden Instruction {} br l24:@var{offset}
+Add @var{offset} to the current instruction pointer.
address@hidden deftypefn
+
+All the conditional branch instructions described below have an
address@hidden parameter, which if true reverses the test:
address@hidden becomes @code{br-if-false}, and so on.
+
address@hidden Instruction {} br-if-true u24:@var{test} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
+If the value in @var{test} is true for the purposes of Scheme, add
address@hidden to the current instruction pointer.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-null u24:@var{test} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
+If the value in @var{test} is the end-of-list or Lisp nil, add
address@hidden to the current instruction pointer.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-nil u24:@var{test} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
+If the value in @var{test} is false to Lisp, add @var{offset} to the
+current instruction pointer.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-pair u24:@var{test} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
+If the value in @var{test} is a pair, add @var{offset} to the current
+instruction pointer.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-struct u24:@var{test} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
+If the value in @var{test} is a struct, add @var{offset} number to the
+current instruction pointer.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-char u24:@var{test} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
+If the value in @var{test} is a char, add @var{offset} to the current
+instruction pointer.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-tc7 u24:@var{test} b1:@var{invert} 
u7:@var{tc7} l24:@var{offset}
+If the value in @var{test} has the TC7 given in the second word, add
address@hidden to the current instruction pointer.  TC7 codes are part of
+the way Guile represents non-immediate objects, and are deep wizardry.
+See @code{libguile/tags.h} for all the details.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-eq u12:@var{a} u12:@var{b} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
address@hidden Instruction {} br-if-eqv u12:@var{a} u12:@var{b} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
address@hidden Instruction {} br-if-equal u12:@var{a} u12:@var{b} 
b1:@var{invert} x7:@var{_} l24:@var{offset}
+If the value in @var{a} is @code{eq?}, @code{eqv?}, or @code{equal?} to
+the value in @var{b}, respectively, add @var{offset} to the current
+instruction pointer.
address@hidden deftypefn
+
address@hidden Instruction {} br-if-= u12:@var{a} u12:@var{b} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
address@hidden Instruction {} br-if-< u12:@var{a} u12:@var{b} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
address@hidden Instruction {} br-if-<= u12:@var{a} u12:@var{b} b1:@var{invert} 
x7:@var{_} l24:@var{offset}
+If the value in @var{a} is @code{=}, @code{<}, or @code{<=} to the value
+in @var{b}, respectively, add @var{offset} to the current instruction
+pointer.
address@hidden deftypefn
+
+
address@hidden Constant Instructions
address@hidden Constant Instructions
+
+The following instructions load literal data into a program.  There are
+two kinds.
+
+The first set of instructions loads immediate values.  These
+instructions encode the immediate directly into the instruction stream.
+
address@hidden Instruction {} make-short-immediate u8:@var{dst} 
i16:@var{low-bits}
+Make an immediate whose low bits are @var{low-bits}, and whose top bits are
+0.
address@hidden deftypefn
+
address@hidden Instruction {} make-long-immediate u24:@var{dst} 
i32:@var{low-bits}
+Make an immediate whose low bits are @var{low-bits}, and whose top bits are
+0.
address@hidden deftypefn
+
address@hidden Instruction {} make-long-long-immediate u24:@var{dst} 
a32:@var{high-bits} b32:@var{low-bits}
+Make an immediate with @var{high-bits} and @var{low-bits}.
address@hidden deftypefn
+
+Non-immediate constant literals are referenced either directly or
+indirectly.  For example, Guile knows at compile-time what the layout of
+a string will be like, and arranges to embed that object directly in the
+compiled image.  A reference to a string will use
address@hidden to treat a pointer into the compilation unit
+as a @code{SCM} value directly.
+
address@hidden Instruction {} make-non-immediate u24:@var{dst} n32:@var{offset}
+Load a pointer to statically allocated memory into @var{dst}.  The
+object's memory is will be found @var{offset} 32-bit words away from the
+current instruction pointer.  Whether the object is mutable or immutable
+depends on where it was allocated by the compiler, and loaded by the
+loader.
address@hidden deftypefn
+
+Some objects must be unique across the whole system.  This is the case
+for symbols and keywords.  For these objects, Guile arranges to
+initialize them when the compilation unit is loaded, storing them into a
+slot in the image.  References go indirectly through that slot.
address@hidden is used in this case.
+
address@hidden Instruction {} static-ref u24:@var{dst} s32:@var{offset}
+Load a @var{scm} value into @var{dst}.  The @var{scm} value will be fetched 
from
+memory, @var{offset} 32-bit words away from the current instruction
+pointer.  @var{offset} is a signed value.
address@hidden deftypefn
+
+Fields of non-immediates may need to be fixed up at load time, because
+we do not know in advance at what address they will be loaded.  This is
+the case, for example, for a pair containing a non-immediate in one of
+its fields.  @code{static-ref} and @code{static-patch!} are used in
+these situations.
+
address@hidden Instruction {} static-set! u24:@var{src} lo32:@var{offset}
+Store a @var{scm} value into memory, @var{offset} 32-bit words away from the
+current instruction pointer.  @var{offset} is a signed value.
address@hidden deftypefn
+
address@hidden Instruction {} static-patch! x24:@var{_} lo32:@var{dst-offset} 
l32:@var{src-offset}
+Patch a pointer at @var{dst-offset} to point to @var{src-offset}.  Both offsets
+are signed 32-bit values, indicating a memory address as a number
+of 32-bit words away from the current instruction pointer.
address@hidden deftypefn
+
+Many kinds of literals can be loaded with the above instructions, once
+the compiler has prepared the statically allocated data.  This is the
+case for vectors, strings, uniform vectors, pairs, and procedures with
+no free variables.  Other kinds of data might need special initializers;
+those instructions follow.
+
address@hidden Instruction {} string->number u12:@var{dst} u12:@var{src}
+Parse a string in @var{src} to a number, and store in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} string->symbol u12:@var{dst} u12:@var{src}
+Parse a string in @var{src} to a symbol, and store in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} symbol->keyword u12:@var{dst} u12:@var{src}
+Make a keyword from the symbol in @var{src}, and store it in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} load-typed-array u8:@var{dst} u8:@var{type} 
u8:@var{shape} n32:@var{offset} u32:@var{len}
+Load the contiguous typed array located at @var{offset} 32-bit words away
+from the instruction pointer, and store into @var{dst}.  @var{len} is a byte
+length.  @var{offset} is signed.
address@hidden deftypefn
 
-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.
-
-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.
address@hidden deffn
 
 @node Dynamic Environment Instructions
 @subsubsection Dynamic Environment Instructions
@@ -1103,168 +930,185 @@ closures.
 Guile's virtual machine has low-level support for @code{dynamic-wind},
 dynamic binding, and composable prompts and aborts.
 
address@hidden Instruction wind
-Pop an unwind thunk and a wind thunk from the stack, in that order, and
-push them onto the ``dynamic stack''. The unwind thunk will be called on
-nonlocal exits, and the wind thunk on reentries. Used to implement
address@hidden
-
-Note that neither thunk is actually called; the compiler should emit
-calls to wind and unwind for the normal dynamic-wind control flow.
address@hidden Wind}.
address@hidden deffn
-
address@hidden Instruction unwind
-Pop off the top entry from the ``dynamic stack'', for example, a
-wind/unwind thunk pair. @code{unwind} instructions should be properly
-paired with their winding instructions, like @code{wind}.
address@hidden deffn
-
address@hidden Instruction push-fluid
-Pop a value and a fluid from the stack, in that order.  Set the fluid
-to the value by creating a with-fluids object and pushing that object
-on the dynamic stack. @xref{Fluids and Dynamic States}.
address@hidden deffn
-
address@hidden Instruction pop-fluid
-Pop a with-fluids object from the dynamic stack, and swap the current
-values of its fluids with the saved values of its fluids. In this way,
-the dynamic environment is left as it was before the corresponding
address@hidden instruction was processed.
address@hidden deffn
-
address@hidden Instruction fluid-ref
-Pop a fluid from the stack, and push its current value.
address@hidden deffn
-
address@hidden Instruction fluid-set
-Pop a value and a fluid from the stack, in that order, and set the fluid
-to the value.
address@hidden deffn
-
address@hidden Instruction prompt escape-only? offset
-Establish a dynamic prompt. @xref{Prompts}, for more information on
-prompts.
-
-The prompt will be pushed on the dynamic stack. The normal control flow
-should ensure that the prompt is popped off at the end, via
address@hidden
-
-If an abort is made to this prompt, control will jump to @var{offset}, a
-three-byte relative address. The continuation and all arguments to the
-abort will be pushed on the stack, along with the total number of
-arguments (including the continuation. If control returns to the
-handler, the prompt is already popped off by the abort mechanism.
-(Guile's @code{prompt} implements Felleisen's @dfn{--F--} operator.)
address@hidden Instruction {} abort x24:@var{_}
+Abort to a prompt handler.  The tag is expected in slot 1, and the rest
+of the values in the frame are returned to the prompt handler.  This
+corresponds to a tail application of abort-to-prompt.
+
+If no prompt can be found in the dynamic environment with the given tag,
+an error is signalled.  Otherwise all arguments are passed to the
+prompt's handler, along with the captured continuation, if necessary.
+
+If the prompt's handler can be proven to not reference the captured
+continuation, no continuation is allocated.  This decision happens
+dynamically, at run-time; the general case is that the continuation may
+be captured, and thus resumed.  A reinstated continuation will have its
+arguments pushed on the stack from slot 1, as if from a multiple-value
+return, and control resumes in the caller.  Thus to the calling
+function, a call to @code{abort-to-prompt} looks like any other function
+call.
address@hidden deftypefn
+
address@hidden Instruction {} prompt u24:@var{tag} b1:@var{escape-only?} 
x7:@var{_} u24:@var{proc-slot} x8:@var{_} l24:@var{handler-offset}
+Push a new prompt on the dynamic stack, with a tag from @var{tag} and a
+handler at @var{handler-offset} words from the current @var{ip}.
+
+If an abort is made to this prompt, control will jump to the handler.
+The handler will expect a multiple-value return as if from a call with
+the procedure at @var{proc-slot}, with the reified partial continuation
+as the first argument, followed by the values returned to the handler.
+If control returns to the handler, the prompt is already popped off by
+the abort mechanism.  (Guile's @code{prompt} implements Felleisen's
address@hidden operator.)
 
 If @var{escape-only?} is nonzero, the prompt will be marked as
 escape-only, which allows an abort to this prompt to avoid reifying the
 continuation.
address@hidden deffn
 
address@hidden Instruction abort n
-Abort to a dynamic prompt.
address@hidden, for more information on prompts.
address@hidden deftypefn
 
-This instruction pops one tail argument list, @var{n} arguments, and a
-prompt tag from the stack. The dynamic environment is then searched for
-a prompt having the given tag. If none is found, an error is signalled.
-Otherwise all arguments are passed to the prompt's handler, along with
-the captured continuation, if necessary.
address@hidden Instruction {} wind u12:@var{winder} u12:@var{unwinder}
+Push wind and unwind procedures onto the dynamic stack. Note that
+neither are actually called; the compiler should emit calls to wind and
+unwind for the normal dynamic-wind control flow.  Also note that the
+compiler should have inserted checks that they wind and unwind procs are
+thunks, if it could not prove that to be the case.  @xref{Dynamic Wind}.
address@hidden deftypefn
 
-If the prompt's handler can be proven to not reference the captured
-continuation, no continuation is allocated. This decision happens
-dynamically, at run-time; the general case is that the continuation may
-be captured, and thus resumed. A reinstated continuation will have its
-arguments pushed on the stack, along with the number of arguments, as in
-the multiple-value return convention. Therefore an @code{abort}
-instruction should be followed by code ready to handle the equivalent of
-a multiply-valued return.
address@hidden deffn
address@hidden Instruction {} unwind x24:@var{_}
address@hidden normal exit from the dynamic extent of an expression. Pop the top
+entry off of the dynamic stack.
address@hidden deftypefn
 
address@hidden Miscellaneous Instructions
address@hidden Miscellaneous Instructions
address@hidden Instruction {} push-fluid u12:@var{fluid} u12:@var{value}
+Dynamically bind @var{value} to @var{fluid} by creating a with-fluids
+object and pushing that object on the dynamic stack.  @xref{Fluids and
+Dynamic States}.
address@hidden deftypefn
 
address@hidden Instruction nop
-Does nothing! Used for padding other instructions to certain
-alignments.
address@hidden deffn
address@hidden Instruction {} pop-fluid x24:@var{_}
+Leave the dynamic extent of a @code{with-fluid*} expression, restoring
+the fluid to its previous value.  @code{push-fluid} should always be
+balanced with @code{pop-fluid}.
address@hidden deftypefn
 
address@hidden Instruction halt
-Exits the VM, returning a SCM value. Normally, this instruction is
-only part of the ``bootstrap program'', a program run when a virtual
-machine is first entered; compiled Scheme procedures will not contain
-this instruction.
address@hidden Instruction {} fluid-ref u12:@var{dst} u12:@var{src}
+Reference the fluid in @var{src}, and place the value in @var{dst}.
address@hidden deftypefn
 
-If multiple values have been returned, the SCM value will be a
-multiple-values object (@pxref{Multiple Values}).
address@hidden deffn
address@hidden Instruction {} fluid-set u12:@var{fluid} u12:@var{val}
+Set the value of the fluid in @var{dst} to the value in @var{src}.
address@hidden deftypefn
 
address@hidden Instruction break
-Does nothing, but invokes the break hook.
address@hidden deffn
 
address@hidden Instruction drop
-Pops off the top value from the stack, throwing it away.
address@hidden deffn
address@hidden Miscellaneous Instructions
address@hidden Miscellaneous Instructions
 
address@hidden Instruction dup
-Re-pushes the top value onto the stack.
address@hidden deffn
address@hidden Instruction {} halt x24:@var{_}
+Bring the VM to a halt, returning all the values from the stack.  Used
+in the ``boot continuation'', which is used when entering the VM from C.
address@hidden deftypefn
 
address@hidden Instruction void
-Pushes ``the unspecified value'' onto the stack.
address@hidden deffn
 
 @node Inlined Scheme Instructions
 @subsubsection Inlined Scheme Instructions
 
 The Scheme compiler can recognize the application of standard Scheme
-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
-saved, the interpreter has to dispatch, called procedures have to do
-much type checking, etc. It's much more efficient to inline these
-operations in the virtual machine itself.
-
-All of these instructions pop their arguments from the stack and push
-their results, and take no parameters from the instruction stream.
-Thus, unlike in the previous sections, these instruction definitions
-show stack parameters instead of parameters from the instruction
-stream.
-
address@hidden Instruction not x
address@hidden Instruction not-not x
address@hidden Instruction eq? x y
address@hidden Instruction not-eq? x y
address@hidden Instruction null?
address@hidden Instruction not-null?
address@hidden Instruction eqv? x y
address@hidden Instruction equal? x y
address@hidden Instruction pair? x y
address@hidden Instruction list? x
address@hidden Instruction set-car! pair x
address@hidden Instruction set-cdr! pair x
address@hidden Instruction cons x y
address@hidden Instruction car x
address@hidden Instruction cdr x
address@hidden Instruction vector-ref x y
address@hidden Instruction vector-set x n y
address@hidden Instruction struct? x
address@hidden Instruction struct-ref x n
address@hidden Instruction struct-set x n v
address@hidden Instruction struct-vtable x
address@hidden Instruction class-of x
address@hidden Instruction slot-ref struct n
address@hidden Instruction slot-set struct n x
-Inlined implementations of their Scheme equivalents.
address@hidden deffn
+procedures.  It tries to inline these small operations to avoid the
+overhead of creating new stack frames.  This allows the compiler to
+optimize better.
+
address@hidden Instruction {} make-vector/immediate u8:@var{dst} 
u8:@var{length} u8:@var{init}
+Make a short vector of known size and write it to @var{dst}.  The vector
+will have space for @var{length} slots, an immediate value.  They will
+be filled with the value in slot @var{init}.
address@hidden deftypefn
+
address@hidden Instruction {} vector-length u12:@var{dst} u12:@var{src}
+Store the length of the vector in @var{src} in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} vector-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
+Fetch the item at position @var{idx} in the vector in @var{src}, and
+store it in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} vector-ref/immediate u8:@var{dst} u8:@var{src} 
u8:@var{idx}
+Fill @var{dst} with the item @var{idx} elements into the vector at
address@hidden  Useful for building data types using vectors.
address@hidden deftypefn
+
address@hidden Instruction {} vector-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
+Store @var{src} into the vector @var{dst} at index @var{idx}.
address@hidden deftypefn
+
address@hidden Instruction {} vector-set!/immediate u8:@var{dst} u8:@var{idx} 
u8:@var{src}
+Store @var{src} into the vector @var{dst} at index @var{idx}.  Here
address@hidden is an immediate value.
address@hidden deftypefn
+
address@hidden Instruction {} struct-vtable u12:@var{dst} u12:@var{src}
+Store the vtable of @var{src} into @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} allocate-struct/immediate u8:@var{dst} 
u8:@var{vtable} u8:@var{nfields}
+Allocate a new struct with @var{vtable}, and place it in @var{dst}.  The
+struct will be constructed with space for @var{nfields} fields, which
+should correspond to the field count of the @var{vtable}.
address@hidden deftypefn
+
address@hidden Instruction {} struct-ref/immediate u8:@var{dst} u8:@var{src} 
u8:@var{idx}
+Fetch the item at slot @var{idx} in the struct in @var{src}, and store
+it in @var{dst}.  @var{idx} is an immediate unsigned 8-bit value.
address@hidden deftypefn
+
address@hidden Instruction {} struct-set!/immediate u8:@var{dst} u8:@var{idx} 
u8:@var{src}
+Store @var{src} into the struct @var{dst} at slot @var{idx}.  @var{idx}
+is an immediate unsigned 8-bit value.
address@hidden deftypefn
+
address@hidden Instruction {} class-of u12:@var{dst} u12:@var{type}
+Store the vtable of @var{src} into @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} make-array u12:@var{dst} u12:@var{type} 
x8:@var{_} u12:@var{fill} u12:@var{bounds}
+Make a new array with @var{type}, @var{fill}, and @var{bounds}, storing it in 
@var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} string-length u12:@var{dst} u12:@var{src}
+Store the length of the string in @var{src} in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} string-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
+Fetch the character at position @var{idx} in the string in @var{src}, and store
+it in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} cons u8:@var{dst} u8:@var{car} u8:@var{cdr}
+Cons @var{car} and @var{cdr}, and store the result in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} car u12:@var{dst} u12:@var{src}
+Place the car of @var{src} in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} cdr u12:@var{dst} u12:@var{src}
+Place the cdr of @var{src} in @var{dst}.
address@hidden deftypefn
+
address@hidden Instruction {} set-car! u12:@var{pair} u12:@var{car}
+Set the car of @var{dst} to @var{src}.
address@hidden deftypefn
+
address@hidden Instruction {} set-cdr! u12:@var{pair} u12:@var{cdr}
+Set the cdr of @var{dst} to @var{src}.
address@hidden deftypefn
 
 Note that @code{caddr} and friends compile to a series of @code{car}
 and @code{cdr} instructions.
 
+
 @node Inlined Mathematical Instructions
 @subsubsection Inlined Mathematical Instructions
 
@@ -1275,29 +1119,61 @@ might be a couple bugs here.
 
 More instructions could be added here over time.
 
-As in the previous section, the definitions below show stack
-parameters instead of instruction stream parameters.
-
address@hidden Instruction add x y
address@hidden Instruction add1 x
address@hidden Instruction sub x y
address@hidden Instruction sub1 x
address@hidden Instruction mul x y
address@hidden Instruction div x y
address@hidden Instruction quo x y
address@hidden Instruction rem x y
address@hidden Instruction mod x y
address@hidden Instruction ee? x y
address@hidden Instruction lt? x y
address@hidden Instruction gt? x y
address@hidden Instruction le? x y
address@hidden Instruction ge? x y
address@hidden Instruction ash x n
address@hidden Instruction logand x y
address@hidden Instruction logior x y
address@hidden Instruction logxor x y
-Inlined implementations of the corresponding mathematical operations.
address@hidden deffn
+All of these operations place their result in their first operand,
address@hidden
+
address@hidden Instruction {} add u8:@var{dst} u8:@var{a} u8:@var{b}
+Add @var{a} to @var{b}.
address@hidden deftypefn
+
address@hidden Instruction {} add1 u12:@var{dst} u12:@var{src}
+Add 1 to the value in @var{src}.
address@hidden deftypefn
+
address@hidden Instruction {} sub u8:@var{dst} u8:@var{a} u8:@var{b}
+Subtract @var{b} from @var{a}.
address@hidden deftypefn
+
address@hidden Instruction {} sub1 u12:@var{dst} u12:@var{src}
+Subtract 1 from @var{src}.
address@hidden deftypefn
+
address@hidden Instruction {} mul u8:@var{dst} u8:@var{a} u8:@var{b}
+Multiply @var{a} and @var{b}.
address@hidden deftypefn
+
address@hidden Instruction {} div u8:@var{dst} u8:@var{a} u8:@var{b}
+Divide @var{a} by @var{b}.
address@hidden deftypefn
+
address@hidden Instruction {} quo u8:@var{dst} u8:@var{a} u8:@var{b}
+Divide @var{a} by @var{b}.
address@hidden deftypefn
+
address@hidden Instruction {} rem u8:@var{dst} u8:@var{a} u8:@var{b}
+Divide @var{a} by @var{b}.
address@hidden deftypefn
+
address@hidden Instruction {} mod u8:@var{dst} u8:@var{a} u8:@var{b}
+Compute the modulo of @var{a} by @var{b}.
address@hidden deftypefn
+
address@hidden Instruction {} ash u8:@var{dst} u8:@var{a} u8:@var{b}
+Shift @var{a} arithmetically by @var{b} bits.
address@hidden deftypefn
+
address@hidden Instruction {} logand u8:@var{dst} u8:@var{a} u8:@var{b}
+Compute the bitwise @code{and} of @var{a} and @var{b}.
address@hidden deftypefn
+
address@hidden Instruction {} logior u8:@var{dst} u8:@var{a} u8:@var{b}
+Compute the bitwise inclusive @code{or} of @var{a} with @var{b}.
address@hidden deftypefn
+
address@hidden Instruction {} logxor u8:@var{dst} u8:@var{a} u8:@var{b}
+Compute the bitwise exclusive @code{or} of @var{a} with @var{b}.
address@hidden deftypefn
+
 
 @node Inlined Bytevector Instructions
 @subsubsection Inlined Bytevector Instructions
@@ -1308,48 +1184,32 @@ 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.
-
address@hidden Instruction bv-u8-ref bv n
address@hidden Instruction bv-s8-ref bv n
address@hidden Instruction bv-u16-native-ref bv n
address@hidden Instruction bv-s16-native-ref bv n
address@hidden Instruction bv-u32-native-ref bv n
address@hidden Instruction bv-s32-native-ref bv n
address@hidden Instruction bv-u64-native-ref bv n
address@hidden Instruction bv-s64-native-ref bv n
address@hidden Instruction bv-f32-native-ref bv n
address@hidden Instruction bv-f64-native-ref bv n
address@hidden Instruction bv-u16-ref bv n endianness
address@hidden Instruction bv-s16-ref bv n endianness
address@hidden Instruction bv-u32-ref bv n endianness
address@hidden Instruction bv-s32-ref bv n endianness
address@hidden Instruction bv-u64-ref bv n endianness
address@hidden Instruction bv-s64-ref bv n endianness
address@hidden Instruction bv-f32-ref bv n endianness
address@hidden Instruction bv-f64-ref bv n endianness
address@hidden Instruction bv-u8-set bv n val
address@hidden Instruction bv-s8-set bv n val
address@hidden Instruction bv-u16-native-set bv n val
address@hidden Instruction bv-s16-native-set bv n val
address@hidden Instruction bv-u32-native-set bv n val
address@hidden Instruction bv-s32-native-set bv n val
address@hidden Instruction bv-u64-native-set bv n val
address@hidden Instruction bv-s64-native-set bv n val
address@hidden Instruction bv-f32-native-set bv n val
address@hidden Instruction bv-f64-native-set bv n val
address@hidden Instruction bv-u16-set bv n val endianness
address@hidden Instruction bv-s16-set bv n val endianness
address@hidden Instruction bv-u32-set bv n val endianness
address@hidden Instruction bv-s32-set bv n val endianness
address@hidden Instruction bv-u64-set bv n val endianness
address@hidden Instruction bv-s64-set bv n val endianness
address@hidden Instruction bv-f32-set bv n val endianness
address@hidden Instruction bv-f64-set bv n val endianness
-Inlined implementations of the corresponding bytevector operations.
address@hidden deffn
address@hidden Instruction {} bv-u8-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-s8-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-u16-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-s16-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-u32-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-s32-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-u64-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-s64-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-f32-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
address@hidden Instruction {} bv-f64-ref u8:@var{dst} u8:@var{src} u8:@var{idx}
+
+Fetch the item at byte offset @var{idx} in the bytevector @var{src}, and
+store it in @var{dst}.  All accesses use native endianness.
address@hidden deftypefn
+
address@hidden Instruction {} bv-u8-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-s8-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-u16-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-s16-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-u32-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-s32-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-u64-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-s64-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-f32-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
address@hidden Instruction {} bv-f64-set! u8:@var{dst} u8:@var{idx} u8:@var{src}
+
+Store @var{src} into the bytevector @var{dst} at byte offset @var{idx}.
+Multibyte values are written using native endianness.
address@hidden deftypefn
diff --git a/libguile/vm-engine.c b/libguile/vm-engine.c
index 68a8b12..6f82ece 100644
--- a/libguile/vm-engine.c
+++ b/libguile/vm-engine.c
@@ -537,7 +537,7 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
   /* call proc:24 _:8 nlocals:24
    *
    * Call a procedure.  PROC is the local corresponding to a procedure.
-   * The three values below PROC will be overwritten by the saved call
+   * The two values below PROC will be overwritten by the saved call
    * frame data.  The new frame will have space for NLOCALS locals: one
    * for the procedure, and the rest for the arguments which should
    * already have been pushed on.
@@ -1155,8 +1155,9 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
       NEXT (3);
     }
 
-  /* bind-kwargs nreq:24 allow-other-keys:1 has-rest:1 _:6 nreq-and-opt:24
-   * _:8 ntotal:24 kw-offset:32
+  /* bind-kwargs nreq:24 flags:8 nreq-and-opt:24 _:8 ntotal:24 kw-offset:32
+   *
+   * flags := allow-other-keys:1 has-rest:1 _:6
    *
    * Find the last positional argument, and shuffle all the rest above
    * NTOTAL.  Initialize the intervening locals to SCM_UNDEFINED.  Then
@@ -1421,7 +1422,7 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
       BR_ARITHMETIC (==, scm_num_eq_p);
     }
 
-  /* br-if-< a:12 b:12 _:8 offset:24
+  /* br-if-< a:12 b:12 invert:1 _:7 offset:24
    *
    * If the value in A is < to the value in B, add OFFSET, a signed
    * 24-bit number, to the current instruction pointer.
@@ -1431,7 +1432,7 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
       BR_ARITHMETIC (<, scm_less_p);
     }
 
-  /* br-if-<= a:12 b:12 _:8 offset:24
+  /* br-if-<= a:12 b:12 invert:1 _:7 offset:24
    *
    * If the value in A is <= to the value in B, add OFFSET, a signed
    * 24-bit number, to the current instruction pointer.
@@ -1568,7 +1569,7 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
       NEXT (2);
     }
 
-  /* free-set! dst:12 src:12 _8 idx:24
+  /* free-set! dst:12 src:12 _:8 idx:24
    *
    * Set free variable IDX from the closure DST to SRC.
    */
@@ -2038,9 +2039,7 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
 
   /* push-fluid fluid:12 value:12
    *
-   * Dynamically bind N fluids to values.  The fluids are expected to be
-   * allocated in a continguous range on the stack, starting from
-   * FLUID-BASE.  The values do not have this restriction.
+   * Dynamically bind VALUE to FLUID.
    */
   VM_DEFINE_OP (65, push_fluid, "push-fluid", OP1 (U8_U12_U12))
     {
@@ -2056,8 +2055,8 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
 
   /* pop-fluid _:24
    *
-   * Leave the dynamic extent of a with-fluids expression, restoring the
-   * fluids to their previous values.
+   * Leave the dynamic extent of a with-fluid* expression, restoring the
+   * fluid to its previous value.
    */
   VM_DEFINE_OP (66, pop_fluid, "pop-fluid", OP1 (U8_X24))
     {
@@ -2172,7 +2171,7 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
 
   /* No string-set! instruction, as there is no good fast path there.  */
 
-  /* string-to-number dst:12 src:12
+  /* string->number dst:12 src:12
    *
    * Parse a string in SRC to a number, and store in DST.
    */
@@ -2188,7 +2187,7 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
       NEXT (1);
     }
 
-  /* string-to-symbol dst:12 src:12
+  /* string->symbol dst:12 src:12
    *
    * Parse a string in SRC to a symbol, and store in DST.
    */
@@ -2721,34 +2720,9 @@ VM_NAME (scm_i_thread *current_thread, struct scm_vm *vp,
       RETURN (scm_class_of (obj));
     }
 
-  /* slot-ref dst:8 src:8 idx:8
-   *
-   * Fetch the item at slot IDX in the struct in SRC, and store it in
-   * DST.  Unlike struct-ref, IDX is an 8-bit immediate value, not an
-   * index into the stack.
-   */
-  VM_DEFINE_OP (103, slot_ref, "slot-ref", OP1 (U8_U8_U8_U8) | OP_DST)
-    {
-      scm_t_uint8 dst, src, idx;
-      UNPACK_8_8_8 (op, dst, src, idx);
-      LOCAL_SET (dst,
-                 SCM_PACK (SCM_STRUCT_DATA (LOCAL_REF (src))[idx]));
-      NEXT (1);
-    }
-
-  /* slot-set! dst:8 idx:8 src:8
-   *
-   * Store SRC into slot IDX of the struct in DST.  Unlike struct-set!,
-   * IDX is an 8-bit immediate value, not an index into the stack.
-   */
-  VM_DEFINE_OP (104, slot_set, "slot-set!", OP1 (U8_U8_U8_U8))
-    {
-      scm_t_uint8 dst, idx, src;
-      UNPACK_8_8_8 (op, dst, idx, src);
-      SCM_STRUCT_DATA (LOCAL_REF (dst))[idx] = SCM_UNPACK (LOCAL_REF (src));
-      NEXT (1);
-    }
-
+  VM_DEFINE_OP (103, unused_103, NULL, NOP)
+  VM_DEFINE_OP (104, unused_104, NULL, NOP)
+    goto op_unused_255;
 
   
 
diff --git a/module/language/cps/reify-primitives.scm 
b/module/language/cps/reify-primitives.scm
index 68de294..501c23c 100644
--- a/module/language/cps/reify-primitives.scm
+++ b/module/language/cps/reify-primitives.scm
@@ -69,7 +69,7 @@
       bytevector-ieee-double-ref bytevector-ieee-double-set!
       bytevector-ieee-double-native-ref bytevector-ieee-double-native-set!)
      '(rnrs bytevectors))
-    ((class-of @slot-ref @slot-set!) '(oop goops))
+    ((class-of) '(oop goops))
     (else '(guile))))
 
 (define (primitive-ref name k src)
diff --git a/module/oop/goops.scm b/module/oop/goops.scm
index eb2b67c..1b86399 100644
--- a/module/oop/goops.scm
+++ b/module/oop/goops.scm
@@ -140,13 +140,7 @@
 
 (eval-when (eval load compile)
   (use-modules ((language tree-il primitives) :select 
(add-interesting-primitive!)))
-  (add-interesting-primitive! 'class-of)
-  (define (@slot-ref o n)
-    (struct-ref o n))
-  (define (@slot-set! o n v)
-    (struct-set! o n v))
-  (add-interesting-primitive! '@slot-ref)
-  (add-interesting-primitive! '@slot-set!))
+  (add-interesting-primitive! 'class-of))
 
 ;; Then load the rest of GOOPS
 (use-modules (oop goops util)
@@ -1193,44 +1187,34 @@
 (define (make-generic-bound-check-getter proc)
   (lambda (o) (assert-bound (proc o) o)))
 
-;; the idea is to compile the index into the procedure, for fastest
-;; lookup. Also, @slot-ref and @slot-set! have their own bytecodes.
-
-(eval-when (eval load compile)
-  (define num-standard-pre-cache 20))
-
-(define-macro (define-standard-accessor-method form . body)
-  (let ((name (caar form))
-        (n-var (cadar form))
-        (args (cdr form)))
-    (define (make-one x)
-      (define (body-trans form)
-        (cond ((not (pair? form)) form)
-              ((eq? (car form) '@slot-ref)
-               `(,(car form) ,(cadr form) ,x))
-              ((eq? (car form) '@slot-set!)
-               `(,(car form) ,(cadr form) ,x ,(cadddr form)))
-              (else
-               (map body-trans form))))
-      `(lambda ,args ,@(map body-trans body)))
-    `(define ,name
-       (let ((cache (vector ,@(map make-one (iota num-standard-pre-cache)))))
-         (lambda (n)
-           (if (< n ,num-standard-pre-cache)
-               (vector-ref cache n)
-               ((lambda (,n-var) (lambda ,args ,@body)) n)))))))
+;;; Pre-generate getters and setters for the first 20 slots.
+(define-syntax define-standard-accessor-method
+  (lambda (stx)
+    (define num-standard-pre-cache 20)
+    (syntax-case stx ()
+      ((_ ((proc n) arg ...) body)
+       #`(define proc
+           (let ((cache (vector #,@(map (lambda (n*)
+                                          #`(lambda (arg ...)
+                                              (let ((n #,n*))
+                                                body)))
+                                        (iota num-standard-pre-cache)))))
+             (lambda (n)
+               (if (< n #,num-standard-pre-cache)
+                   (vector-ref cache n)
+                   (lambda (arg ...) body)))))))))
 
 (define-standard-accessor-method ((bound-check-get n) o)
-  (let ((x (@slot-ref o n)))
+  (let ((x (struct-ref o n)))
     (if (unbound? x)
         (slot-unbound o)
         x)))
 
 (define-standard-accessor-method ((standard-get n) o)
-  (@slot-ref o n))
+  (struct-ref o n))
 
 (define-standard-accessor-method ((standard-set n) o v)
-  (@slot-set! o n v))
+  (struct-set! o n v))
 
 ;;; compute-getters-n-setters
 ;;;
diff --git a/module/system/vm/disassembler.scm 
b/module/system/vm/disassembler.scm
index f09f057..577124a 100644
--- a/module/system/vm/disassembler.scm
+++ b/module/system/vm/disassembler.scm
@@ -199,7 +199,7 @@
 address of that offset."
   (+ (debug-context-base context) (* offset 4)))
 
-(define (code-annotation code len offset start labels context)
+(define (code-annotation code len offset start labels context push-addr!)
   ;; FIXME: Print names for register loads and stores that correspond to
   ;; access to named locals.
   (define (reference-scm target)
@@ -244,19 +244,22 @@ address of that offset."
      (list "~a arg~:p" nargs))
     (('make-closure dst target nfree)
      (let* ((addr (u32-offset->addr (+ offset target) context))
-            (pdi (find-program-debug-info addr context)))
-       ;; FIXME: Disassemble embedded closures as well.
-       (list "~A at 0x~X (~A free var~:p)"
-             (or (and pdi (program-debug-info-name pdi))
-                 "(anonymous procedure)")
-             addr
-             nfree)))
+            (pdi (find-program-debug-info addr context))
+            (name (or (and pdi (program-debug-info-name pdi))
+                      "anonymous procedure")))
+       (push-addr! addr name)
+       (list "~A at #x~X (~A free var~:p)" name addr nfree)))
     (('make-non-immediate dst target)
-     (list "address@hidden" (reference-scm target)))
+     (let ((val (reference-scm target)))
+       (when (program? val)
+         (push-addr! (program-code val) val))
+       (list "address@hidden" val)))
     (('builtin-ref dst idx)
      (list "~A" (builtin-index->name idx)))
     (((or 'static-ref 'static-set!) _ target)
      (list "address@hidden" (dereference-scm target)))
+    (((or 'free-ref 'free-set!) _ _ index)
+     (list "free var ~a" index))
     (('resolve-module dst name public)
      (list "~a" (if (zero? public) "private" "public")))
     (('toplevel-box _ var-offset mod-offset sym-offset bound?)
@@ -318,7 +321,7 @@ address of that offset."
   (format port "address@hidden    address@hidden;; address@hidden@[~61t at 
~a~]\n"
           addr info extra src))
 
-(define (disassemble-buffer port bv start end context)
+(define (disassemble-buffer port bv start end context push-addr!)
   (let ((labels (compute-labels bv start end))
         (sources (find-program-sources (u32-offset->addr start context)
                                        context)))
@@ -332,7 +335,7 @@ address of that offset."
               ((< pc addr) (lp sources))
               ((= pc addr)
                (format #f "~a:~a:~a"
-                       (source-file source)
+                       (or (source-file source) "(unknown file)")
                        (source-line-for-user source)
                        (source-column source)))
               (else #f)))))))
@@ -343,26 +346,39 @@ address of that offset."
             (let ((pos (- offset start))
                   (addr (u32-offset->addr offset context))
                   (annotation (code-annotation elt len offset start labels
-                                               context)))
+                                               context push-addr!)))
               (print-info port pos (vector-ref labels pos) elt annotation
                           (lookup-source addr))
               (lp (+ offset len)))))))))
 
-(define* (disassemble-program program #:optional (port (current-output-port)))
+(define (disassemble-addr addr label port)
+  (format port "Disassembly of ~A at #x~X:\n\n" label addr)
   (cond
-   ((find-program-debug-info (program-code program))
+   ((find-program-debug-info addr)
     => (lambda (pdi)
-         (format port "Disassembly of ~S at #x~X:\n\n" program
-                 (program-debug-info-addr pdi))
-         (disassemble-buffer port
-                             (program-debug-info-image pdi)
-                             (program-debug-info-u32-offset pdi)
-                             (program-debug-info-u32-offset-end pdi)
-                             (program-debug-info-context pdi))))
+         (let ((worklist '()))
+           (define (push-addr! addr label)
+             (unless (assv addr worklist)
+               (set! worklist (acons addr label worklist))))
+           (disassemble-buffer port
+                               (program-debug-info-image pdi)
+                               (program-debug-info-u32-offset pdi)
+                               (program-debug-info-u32-offset-end pdi)
+                               (program-debug-info-context pdi)
+                               push-addr!)
+           (for-each (match-lambda
+                      ((addr . label)
+                       (display "\n----------------------------------------\n"
+                                port)
+                       (disassemble-addr addr label port)))
+                     worklist))))
    (else
     (format port "Debugging information unavailable.~%")))
   (values))
 
+(define* (disassemble-program program #:optional (port (current-output-port)))
+  (disassemble-addr (program-code program) program port))
+
 (define (fold-code-range proc seed bv start end context raw?)
   (define (cook code offset)
     (define (reference-scm target)
@@ -446,7 +462,8 @@ address of that offset."
                              bv
                              (/ (+ base value) 4)
                              (/ (+ base value size) 4)
-                             ctx)
+                             ctx
+                             (lambda (addr name) #t))
          (display "\n\n" port)))))
   (values))
 


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]