Adapt GDB integration to newest patches
[bpt/guile.git] / libguile / vm-engine.c
index ad6ec62..ec112b2 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013,
+ *   2014, 2015 Free Software Foundation, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -88,7 +89,7 @@
   do {                                    \
     if (SCM_UNLIKELY (!(condition)))      \
       {                                   \
-        SYNC_ALL();                       \
+        SYNC_IP();                        \
         handler;                          \
       }                                   \
   } while (0)
   do {                                                  \
     if (SCM_UNLIKELY (vp->trace_level > 0))             \
       {                                                 \
-        SYNC_REGISTER ();                              \
+        SYNC_IP ();                                     \
         exp;                                            \
+        CACHE_FP ();                                    \
       }                                                 \
   } while (0)
 #else
 #define RUN_HOOK(exp)
 #endif
-#define RUN_HOOK0(h)      RUN_HOOK (vm_dispatch_##h##_hook (vm))
-#define RUN_HOOK1(h, arg) RUN_HOOK (vm_dispatch_##h##_hook (vm, arg))
+#define RUN_HOOK0(h)      RUN_HOOK (vm_dispatch_##h##_hook (vp))
+#define RUN_HOOK1(h, arg) RUN_HOOK (vm_dispatch_##h##_hook (vp, arg))
 
 #define APPLY_HOOK()                            \
   RUN_HOOK0 (apply)
   RUN_HOOK0 (next)
 #define ABORT_CONTINUATION_HOOK()               \
   RUN_HOOK0 (abort)
-#define RESTORE_CONTINUATION_HOOK()             \
-  RUN_HOOK0 (restore_continuation)
 
 #define VM_HANDLE_INTERRUPTS                     \
-  SCM_ASYNC_TICK_WITH_CODE (current_thread, SYNC_REGISTER ())
+  SCM_ASYNC_TICK_WITH_GUARD_CODE (thread, SYNC_IP (), CACHE_FP ())
 
 
 /* Virtual Machine
 
-   This is Guile's new virtual machine.  When I say "new", I mean
-   relative to the current virtual machine.  At some point it will
-   become "the" virtual machine, and we'll delete this paragraph.  As
-   such, the rest of the comments speak as if there's only one VM.
-   In difference from the old VM, local 0 is the procedure, and the
-   first argument is local 1.  At some point in the future we should
-   change the fp to point to the procedure and not to local 1.
-
-   <more overview here>
- */
-
-
-/* The VM has three state bits: the instruction pointer (IP), the frame
+   The VM has three state bits: the instruction pointer (IP), the frame
    pointer (FP), and the top-of-stack pointer (SP).  We cache the first
    two of these in machine registers, local to the VM, because they are
    used extensively by the VM.  As the SP is used more by code outside
    whenever we would need to know the IP of the top frame.  In practice,
    we need to SYNC_IP whenever we call out of the VM to a function that
    would like to walk the stack, perhaps as the result of an
-   exception.  */
-
-#define SYNC_IP() \
-  vp->ip = (ip)
-
-#define SYNC_REGISTER() \
-  SYNC_IP()
-#define SYNC_BEFORE_GC() /* Only SP and FP needed to trace GC */
-#define SYNC_ALL() /* FP already saved */ \
-  SYNC_IP()
-
-/* After advancing vp->sp, but before writing any stack slots, check
-   that it is actually in bounds.  If it is not in bounds, currently we
-   signal an error.  In the future we may expand the stack instead,
-   possibly by moving it elsewhere, therefore no pointer into the stack
-   besides FP is valid across a CHECK_OVERFLOW call.  Be careful!  */
-#define CHECK_OVERFLOW()                                            \
-  do {                                                              \
-    if (SCM_UNLIKELY (vp->sp >= vp->stack_limit))                   \
-      {                                                             \
-        vm_error_stack_overflow (vp);                               \
-        CACHE_REGISTER();                                           \
-      }                                                             \
+   exception.
+
+   One more thing.  We allow the stack to move, when it expands.
+   Therefore if you call out to a C procedure that could call Scheme
+   code, or otherwise push anything on the stack, you will need to
+   CACHE_FP afterwards to restore the possibly-changed FP. */
+
+#define SYNC_IP() vp->ip = (ip)
+
+#define CACHE_FP() fp = (vp->fp)
+#define CACHE_REGISTER()                        \
+  do {                                          \
+    ip = vp->ip;                                \
+    fp = vp->fp;                                \
   } while (0)
 
+
 /* Reserve stack space for a frame.  Will check that there is sufficient
    stack space for N locals, including the procedure.  Invoke after
-   preparing the new frame and setting the fp and ip.  */
+   preparing the new frame and setting the fp and ip.
+
+   If there is not enough space for this frame, we try to expand the
+   stack, possibly relocating it somewhere else in the address space.
+   Because of the possible relocation, no pointer into the stack besides
+   FP is valid across an ALLOC_FRAME call.  Be careful!  */
 #define ALLOC_FRAME(n)                                              \
   do {                                                              \
-    vp->sp = LOCAL_ADDRESS (n - 1);                                 \
-    CHECK_OVERFLOW ();                                              \
+    SCM *new_sp = LOCAL_ADDRESS (n - 1);                            \
+    if (new_sp > vp->sp_max_since_gc)                               \
+      {                                                             \
+        if (SCM_UNLIKELY (new_sp >= vp->stack_limit))               \
+          {                                                         \
+            SYNC_IP ();                                             \
+            vm_expand_stack (vp, new_sp);                           \
+            CACHE_FP ();                                            \
+          }                                                         \
+        else                                                        \
+          vp->sp_max_since_gc = vp->sp = new_sp;                    \
+      }                                                             \
+    else                                                            \
+      vp->sp = new_sp;                                              \
   } while (0)
 
 /* Reset the current frame to hold N locals.  Used when we know that no
 #define RESET_FRAME(n)                                              \
   do {                                                              \
     vp->sp = LOCAL_ADDRESS (n - 1);                                 \
+    if (vp->sp > vp->sp_max_since_gc)                               \
+      vp->sp_max_since_gc = vp->sp;                                 \
   } while (0)
 
 /* Compute the number of locals in the frame.  At a call, this is equal
   } while (0)
 
 
-#define CACHE_REGISTER()                        \
-  do {                                          \
-    ip = (scm_t_uint32 *) vp->ip;               \
-    fp = vp->fp;                                \
-  } while (0)
-
 #ifdef HAVE_LABELS_AS_VALUES
 # define BEGIN_DISPATCH_SWITCH /* */
 # define END_DISPATCH_SWITCH /* */
   switch (op & 0xff)                            \
     {
 # define END_DISPATCH_SWITCH                    \
-  default:                                      \
-    goto vm_error_bad_instruction;              \
     }
 # define NEXT(n)                                \
   do                                            \
 #define RETURN_ONE_VALUE(ret)                           \
   do {                                                  \
     SCM val = ret;                                      \
-    SCM *old_fp = fp;                                   \
+    SCM *old_fp;                                        \
     VM_HANDLE_INTERRUPTS;                               \
+    old_fp = fp;                                        \
     ip = SCM_FRAME_RETURN_ADDRESS (fp);                 \
     fp = vp->fp = SCM_FRAME_DYNAMIC_LINK (fp);          \
     /* Clear frame. */                                  \
     {                                           \
       scm_t_int32 offset = ip[1];               \
       offset >>= 8; /* Sign-extending shift. */ \
-      if (offset < 0)                           \
+      if (offset <= 0)                          \
         VM_HANDLE_INTERRUPTS;                   \
       NEXT (offset);                            \
     }                                           \
     {                                           \
       scm_t_int32 offset = ip[1];               \
       offset >>= 8; /* Sign-extending shift. */ \
-      if (offset < 0)                           \
+      if (offset <= 0)                          \
         VM_HANDLE_INTERRUPTS;                   \
       NEXT (offset);                            \
     }                                           \
           {                                                             \
             scm_t_int32 offset = ip[1];                                 \
             offset >>= 8; /* Sign-extending shift. */                   \
-            if (offset < 0)                                             \
+            if (offset <= 0)                                            \
               VM_HANDLE_INTERRUPTS;                                     \
             NEXT (offset);                                              \
           }                                                             \
         SCM res;                                                        \
         SYNC_IP ();                                                     \
         res = srel (x, y);                                              \
+        CACHE_FP ();                                                    \
         if ((ip[1] & 0x1) ? scm_is_false (res) : scm_is_true (res))     \
           {                                                             \
             scm_t_int32 offset = ip[1];                                 \
             offset >>= 8; /* Sign-extending shift. */                   \
-            if (offset < 0)                                             \
+            if (offset <= 0)                                            \
               VM_HANDLE_INTERRUPTS;                                     \
             NEXT (offset);                                              \
           }                                                             \
   a2 = LOCAL_REF (src2)
 #define RETURN(x)                               \
   do { LOCAL_SET (dst, x); NEXT (1); } while (0)
+#define RETURN_EXP(exp)                         \
+  do { SCM __x; SYNC_IP (); __x = exp; CACHE_FP (); RETURN (__x); } while (0)
 
 /* The maximum/minimum tagged integers.  */
 #define INUM_MAX  \
         if (SCM_FIXABLE (n))                                    \
           RETURN (SCM_I_MAKINUM (n));                           \
       }                                                         \
-    SYNC_IP ();                                                 \
-    RETURN (SFUNC (x, y));                                      \
+    RETURN_EXP (SFUNC (x, y));                                  \
   }
 
 #define VM_VALIDATE_PAIR(x, proc)              \
   ((scm_t_uintptr) (ptr) % alignof_type (type) == 0)
 
 static SCM
-VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
+VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
+         scm_i_jmp_buf *registers, int resume)
 {
   /* Instruction pointer: A pointer to the opcode that is currently
      running.  */
@@ -438,94 +433,34 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
   /* Current opcode: A cache of *ip.  */
   register scm_t_uint32 op;
 
-  /* Cached variables. */
-  struct scm_vm *vp = SCM_VM_DATA (vm);
-  scm_i_thread *current_thread = SCM_I_CURRENT_THREAD;
-  scm_i_jmp_buf registers;              /* used for prompts */
-
 #ifdef HAVE_LABELS_AS_VALUES
-  static const void **jump_table_pointer = NULL;
+  static const void *jump_table_[256] = {
+#define LABEL_ADDR(opcode, tag, name, meta) &&op_##tag,
+      FOR_EACH_VM_OPERATION(LABEL_ADDR)
+#undef LABEL_ADDR
+  };
   register const void **jump_table JT_REG;
-
-  if (SCM_UNLIKELY (!jump_table_pointer))
-    {
-      int i;
-      jump_table_pointer = malloc (SCM_VM_NUM_INSTRUCTIONS * sizeof (void*));
-      for (i = 0; i < SCM_VM_NUM_INSTRUCTIONS; i++)
-        jump_table_pointer[i] = &&vm_error_bad_instruction;
-#define INIT(opcode, tag, name, meta) jump_table_pointer[opcode] = &&op_##tag;
-      FOR_EACH_VM_OPERATION(INIT);
-#undef INIT
-    }
-
   /* Attempt to keep JUMP_TABLE_POINTER in a register.  This saves one
      load instruction at each instruction dispatch.  */
-  jump_table = jump_table_pointer;
+  jump_table = jump_table_;
 #endif
 
-  if (SCM_I_SETJMP (registers))
-    {
-      /* Non-local return.  The values are on the stack, on a new frame
-         set up to call `values' to return the values to the handler.
-         Cache the VM registers back from the vp, and dispatch to the
-         body of `values'.
-
-         Note, at this point, we must assume that any variable local to
-         vm_engine that can be assigned *has* been assigned. So we need
-         to pull all our state back from the ip/fp/sp.
-      */
-      CACHE_REGISTER ();
-      ABORT_CONTINUATION_HOOK ();
-      NEXT (0);
-    }
-
-  /* Load previous VM registers. */
+  /* Load VM registers. */
   CACHE_REGISTER ();
 
   VM_HANDLE_INTERRUPTS;
 
-  /* Initialization */
-  {
-    SCM *base;
-    ptrdiff_t base_frame_size;
-
-    /* Check that we have enough space: 3 words for the boot
-       continuation, 3 + nargs for the procedure application, and 3 for
-       setting up a new frame.  */
-    base_frame_size = 3 + 3 + nargs_ + 3;
-    vp->sp += base_frame_size;
-    CHECK_OVERFLOW ();
-    base = vp->sp + 1 - base_frame_size;
-
-    /* Since it's possible to receive the arguments on the stack itself,
-       and indeed the regular VM invokes us that way, shuffle up the
-       arguments first.  */
-    {
-      int i;
-      for (i = nargs_ - 1; i >= 0; i--)
-        base[6 + i] = argv[i];
-    }
-
-    /* Initial frame, saving previous fp and ip, with the boot
-       continuation.  */
-    base[0] = SCM_PACK (fp); /* dynamic link */
-    base[1] = SCM_PACK (ip); /* ra */
-    base[2] = vm_boot_continuation;
-    fp = &base[2];
-    ip = (scm_t_uint32 *) vm_boot_continuation_code;
-
-    /* MV-call frame, function & arguments */
-    base[3] = SCM_PACK (fp); /* dynamic link */
-    base[4] = SCM_PACK (ip); /* ra */
-    base[5] = program;
-    fp = vp->fp = &base[5];
-    RESET_FRAME (nargs_ + 1);
-  }
+  /* Usually a call to the VM happens on application, with the boot
+     continuation on the next frame.  Sometimes it happens after a
+     non-local exit however; in that case the VM state is all set up,
+     and we have but to jump to the next opcode.  */
+  if (SCM_UNLIKELY (resume))
+    NEXT (0);
 
  apply:
-  while (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp)))
+  while (!SCM_PROGRAM_P (LOCAL_REF (0)))
     {
-      SCM proc = SCM_FRAME_PROGRAM (fp);
+      SCM proc = LOCAL_REF (0);
 
       if (SCM_STRUCTP (proc) && SCM_STRUCT_APPLICABLE_P (proc))
         {
@@ -550,7 +485,10 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
     }
 
   /* Let's go! */
-  ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+  ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
+
+  APPLY_HOOK ();
+
   NEXT (0);
 
   BEGIN_DISPATCH_SWITCH;
@@ -579,9 +517,8 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
         {
           scm_t_uint32 n;
           ret = SCM_EOL;
-          SYNC_BEFORE_GC();
           for (n = nvals; n > 0; n--)
-            ret = scm_cons (LOCAL_REF (4 + n - 1), ret);
+            ret = scm_inline_cons (thread, LOCAL_REF (4 + n - 1), ret);
           ret = scm_values (ret);
         }
 
@@ -595,7 +532,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
   /* 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.
@@ -608,26 +545,67 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
   VM_DEFINE_OP (1, call, "call", OP2 (U8_U24, X8_U24))
     {
       scm_t_uint32 proc, nlocals;
-      SCM *old_fp = fp;
+      SCM *old_fp;
 
       UNPACK_24 (op, proc);
       UNPACK_24 (ip[1], nlocals);
 
       VM_HANDLE_INTERRUPTS;
 
+      PUSH_CONTINUATION_HOOK ();
+
+      old_fp = fp;
       fp = vp->fp = old_fp + proc;
       SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp);
       SCM_FRAME_SET_RETURN_ADDRESS (fp, ip + 2);
 
       RESET_FRAME (nlocals);
 
-      PUSH_CONTINUATION_HOOK ();
+      if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
+        goto apply;
+
+      ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
+
       APPLY_HOOK ();
 
-      if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
-        goto apply;
+      NEXT (0);
+    }
+
+  /* call-label proc:24 _:8 nlocals:24 label:32
+   *
+   * Call a procedure in the same compilation unit.
+   *
+   * This instruction is just like "call", except that instead of
+   * dereferencing PROC to find the call target, the call target is
+   * known to be at LABEL, a signed 32-bit offset in 32-bit units from
+   * the current IP.  Since PROC is not dereferenced, it may be some
+   * other representation of the closure.
+   */
+  VM_DEFINE_OP (2, call_label, "call-label", OP3 (U8_U24, X8_U24, L32))
+    {
+      scm_t_uint32 proc, nlocals;
+      scm_t_int32 label;
+      SCM *old_fp;
+
+      UNPACK_24 (op, proc);
+      UNPACK_24 (ip[1], nlocals);
+      label = ip[2];
+
+      VM_HANDLE_INTERRUPTS;
+
+      PUSH_CONTINUATION_HOOK ();
+
+      old_fp = fp;
+      fp = vp->fp = old_fp + proc;
+      SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp);
+      SCM_FRAME_SET_RETURN_ADDRESS (fp, ip + 3);
+
+      RESET_FRAME (nlocals);
+
+      ip += label;
+
+      APPLY_HOOK ();
 
-      ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
       NEXT (0);
     }
 
@@ -637,7 +615,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * arguments have already been shuffled into position.  Will reset the
    * frame to NLOCALS.
    */
-  VM_DEFINE_OP (2, tail_call, "tail-call", OP1 (U8_U24))
+  VM_DEFINE_OP (3, tail_call, "tail-call", OP1 (U8_U24))
     {
       scm_t_uint32 nlocals;
       
@@ -647,12 +625,37 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 
       RESET_FRAME (nlocals);
 
+      if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
+        goto apply;
+
+      ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
+
       APPLY_HOOK ();
 
-      if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
-        goto apply;
+      NEXT (0);
+    }
+
+  /* tail-call-label nlocals:24 label:32
+   *
+   * Tail-call a known procedure.  As call is to call-label, tail-call
+   * is to tail-call-label.
+   */
+  VM_DEFINE_OP (4, tail_call_label, "tail-call-label", OP2 (U8_U24, L32))
+    {
+      scm_t_uint32 nlocals;
+      scm_t_int32 label;
+      
+      UNPACK_24 (op, nlocals);
+      label = ip[1];
+
+      VM_HANDLE_INTERRUPTS;
+
+      RESET_FRAME (nlocals);
+
+      ip += label;
+
+      APPLY_HOOK ();
 
-      ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
       NEXT (0);
     }
 
@@ -663,7 +666,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * FROM, shuffled down to start at slot 0.  This is part of the
    * implementation of the call-with-values builtin.
    */
-  VM_DEFINE_OP (3, tail_call_shuffle, "tail-call/shuffle", OP1 (U8_U24))
+  VM_DEFINE_OP (5, tail_call_shuffle, "tail-call/shuffle", OP1 (U8_U24))
     {
       scm_t_uint32 n, from, nlocals;
 
@@ -679,12 +682,13 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 
       RESET_FRAME (n + 1);
 
-      APPLY_HOOK ();
-
-      if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
+      if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
         goto apply;
 
-      ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+      ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
+
+      APPLY_HOOK ();
+
       NEXT (0);
     }
 
@@ -694,7 +698,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * PROC, asserting that the call actually returned at least one
    * value.  Afterwards, resets the frame to NLOCALS locals.
    */
-  VM_DEFINE_OP (4, receive, "receive", OP2 (U8_U12_U12, X8_U24) | OP_DST)
+  VM_DEFINE_OP (6, receive, "receive", OP2 (U8_U12_U12, X8_U24) | OP_DST)
     {
       scm_t_uint16 dst, proc;
       scm_t_uint32 nlocals;
@@ -714,7 +718,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * return values equals NVALUES exactly.  After receive-values has
    * run, the values can be copied down via `mov'.
    */
-  VM_DEFINE_OP (5, receive_values, "receive-values", OP2 (U8_U24, B1_X7_U24))
+  VM_DEFINE_OP (7, receive_values, "receive-values", OP2 (U8_U24, B1_X7_U24))
     {
       scm_t_uint32 proc, nvalues;
       UNPACK_24 (op, proc);
@@ -732,7 +736,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Return a value.
    */
-  VM_DEFINE_OP (6, return, "return", OP1 (U8_U24))
+  VM_DEFINE_OP (8, return, "return", OP1 (U8_U24))
     {
       scm_t_uint32 src;
       UNPACK_24 (op, src);
@@ -747,11 +751,13 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * shuffled down to a contiguous array starting at slot 1.
    * We also expect the frame has already been reset.
    */
-  VM_DEFINE_OP (7, return_values, "return-values", OP1 (U8_X24))
+  VM_DEFINE_OP (9, return_values, "return-values", OP1 (U8_X24))
     {
-      SCM *old_fp = fp;
+      SCM *old_fp;
 
       VM_HANDLE_INTERRUPTS;
+
+      old_fp = fp;
       ip = SCM_FRAME_RETURN_ADDRESS (fp);
       fp = vp->fp = SCM_FRAME_DYNAMIC_LINK (fp);
 
@@ -778,7 +784,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * calling frame.  This instruction is part of the trampolines
    * created in gsubr.c, and is not generated by the compiler.
    */
-  VM_DEFINE_OP (8, subr_call, "subr-call", OP1 (U8_U24))
+  VM_DEFINE_OP (10, subr_call, "subr-call", OP1 (U8_U24))
     {
       scm_t_uint32 ptr_idx;
       SCM pointer, ret;
@@ -789,7 +795,6 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       pointer = SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), ptr_idx);
       subr = SCM_POINTER_VALUE (pointer);
 
-      VM_HANDLE_INTERRUPTS;
       SYNC_IP ();
 
       switch (FRAME_LOCALS_COUNT_FROM (1))
@@ -831,7 +836,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
           abort ();
         }
 
-      // NULLSTACK_FOR_NONLOCAL_EXIT ();
+      CACHE_FP ();
 
       if (SCM_UNLIKELY (SCM_VALUESP (ret)))
         /* multiple values returned to continuation */
@@ -848,7 +853,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * part of the trampolines created by the FFI, and is not generated by
    * the compiler.
    */
-  VM_DEFINE_OP (9, foreign_call, "foreign-call", OP1 (U8_U12_U12))
+  VM_DEFINE_OP (11, foreign_call, "foreign-call", OP1 (U8_U12_U12))
     {
       scm_t_uint16 cif_idx, ptr_idx;
       SCM closure, cif, pointer, ret;
@@ -860,12 +865,12 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       pointer = SCM_PROGRAM_FREE_VARIABLE_REF (closure, ptr_idx);
 
       SYNC_IP ();
-      VM_HANDLE_INTERRUPTS;
 
       // FIXME: separate args
-      ret = scm_i_foreign_call (scm_cons (cif, pointer), LOCAL_ADDRESS (1));
+      ret = scm_i_foreign_call (scm_inline_cons (thread, cif, pointer),
+                                LOCAL_ADDRESS (1));
 
-      // NULLSTACK_FOR_NONLOCAL_EXIT ();
+      CACHE_FP ();
 
       if (SCM_UNLIKELY (SCM_VALUESP (ret)))
         /* multiple values returned to continuation */
@@ -882,7 +887,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * the implementation of undelimited continuations, and is not
    * generated by the compiler.
    */
-  VM_DEFINE_OP (10, continuation_call, "continuation-call", OP1 (U8_U24))
+  VM_DEFINE_OP (12, continuation_call, "continuation-call", OP1 (U8_U24))
     {
       SCM contregs;
       scm_t_uint32 contregs_idx;
@@ -894,7 +899,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 
       SYNC_IP ();
       scm_i_check_continuation (contregs);
-      vm_return_to_continuation (scm_i_contregs_vm (contregs),
+      vm_return_to_continuation (scm_i_contregs_vp (contregs),
                                  scm_i_contregs_vm_cont (contregs),
                                  FRAME_LOCALS_COUNT_FROM (1),
                                  LOCAL_ADDRESS (1));
@@ -912,7 +917,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * instruction is part of the implementation of partial continuations,
    * and is not generated by the compiler.
    */
-  VM_DEFINE_OP (11, compose_continuation, "compose-continuation", OP1 (U8_U24))
+  VM_DEFINE_OP (13, compose_continuation, "compose-continuation", OP1 (U8_U24))
     {
       SCM vmcont;
       scm_t_uint32 cont_idx;
@@ -923,10 +928,10 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       SYNC_IP ();
       VM_ASSERT (SCM_VM_CONT_REWINDABLE_P (vmcont),
                  vm_error_continuation_not_rewindable (vmcont));
-      vm_reinstate_partial_continuation (vm, vmcont, FRAME_LOCALS_COUNT_FROM (1),
+      vm_reinstate_partial_continuation (vp, vmcont, FRAME_LOCALS_COUNT_FROM (1),
                                          LOCAL_ADDRESS (1),
-                                         &current_thread->dynstack,
-                                         &registers);
+                                         &thread->dynstack,
+                                         registers);
       CACHE_REGISTER ();
       NEXT (0);
     }
@@ -937,7 +942,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * arguments.  This instruction is part of the implementation of
    * `apply', and is not generated by the compiler.
    */
-  VM_DEFINE_OP (12, tail_apply, "tail-apply", OP1 (U8_X24))
+  VM_DEFINE_OP (14, tail_apply, "tail-apply", OP1 (U8_X24))
     {
       int i, list_idx, list_len, nlocals;
       SCM list;
@@ -967,12 +972,13 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       for (i = 0; i < list_len; i++, list = SCM_CDR (list))
         LOCAL_SET (list_idx - 1 + i, SCM_CAR (list));
 
-      APPLY_HOOK ();
-
-      if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
+      if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
         goto apply;
 
-      ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+      ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
+
+      APPLY_HOOK ();
+
       NEXT (0);
     }
 
@@ -982,7 +988,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * local slot 1 to it.  This instruction is part of the implementation
    * of `call/cc', and is not generated by the compiler.
    */
-  VM_DEFINE_OP (13, call_cc, "call/cc", OP1 (U8_X24))
+  VM_DEFINE_OP (15, call_cc, "call/cc", OP1 (U8_X24))
     {
       SCM vm_cont, cont;
       scm_t_dynstack *dynstack;
@@ -991,7 +997,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       VM_HANDLE_INTERRUPTS;
 
       SYNC_IP ();
-      dynstack = scm_dynstack_capture_all (&current_thread->dynstack);
+      dynstack = scm_dynstack_capture_all (&thread->dynstack);
       vm_cont = scm_i_vm_capture_stack (vp->stack_base,
                                         SCM_FRAME_DYNAMIC_LINK (fp),
                                         SCM_FRAME_PREVIOUS_SP (fp),
@@ -1003,7 +1009,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
          copying out to the heap; and likewise, the setjmp(&registers)
          code already has the non-local return handler.  But oh
          well!  */
-      cont = scm_i_make_continuation (&first, vm, vm_cont);
+      cont = scm_i_make_continuation (&first, vp, vm_cont);
 
       if (first)
         {
@@ -1011,12 +1017,13 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
           LOCAL_SET (1, cont);
           RESET_FRAME (2);
 
-          APPLY_HOOK ();
-
-          if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
+          if (SCM_UNLIKELY (!SCM_PROGRAM_P (LOCAL_REF (0))))
             goto apply;
 
-          ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
+          ip = SCM_PROGRAM_CODE (LOCAL_REF (0));
+
+          APPLY_HOOK ();
+
           NEXT (0);
         }
       else
@@ -1033,7 +1040,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * of the values in the frame are returned to the prompt handler.
    * This corresponds to a tail application of abort-to-prompt.
    */
-  VM_DEFINE_OP (14, abort, "abort", OP1 (U8_X24))
+  VM_DEFINE_OP (16, abort, "abort", OP1 (U8_X24))
     {
       scm_t_uint32 nlocals = FRAME_LOCALS_COUNT ();
 
@@ -1043,8 +1050,8 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
          it continues with the next instruction.  */
       ip++;
       SYNC_IP ();
-      vm_abort (vm, LOCAL_REF (1), nlocals - 2, LOCAL_ADDRESS (2),
-                SCM_EOL, LOCAL_ADDRESS (0), &registers);
+      vm_abort (vp, LOCAL_REF (1), nlocals - 2, LOCAL_ADDRESS (2),
+                SCM_EOL, LOCAL_ADDRESS (0), registers);
 
       /* vm_abort should not return */
       abort ();
@@ -1054,7 +1061,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Load a builtin stub by index into DST.
    */
-  VM_DEFINE_OP (15, builtin_ref, "builtin-ref", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (17, builtin_ref, "builtin-ref", OP1 (U8_U12_U12) | OP_DST)
     {
       scm_t_uint16 dst, idx;
 
@@ -1079,15 +1086,15 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * than EXPECTED, respectively, add OFFSET, a signed 24-bit number, to
    * the current instruction pointer.
    */
-  VM_DEFINE_OP (16, br_if_nargs_ne, "br-if-nargs-ne", OP2 (U8_U24, X8_L24))
+  VM_DEFINE_OP (18, br_if_nargs_ne, "br-if-nargs-ne", OP2 (U8_U24, X8_L24))
     {
       BR_NARGS (!=);
     }
-  VM_DEFINE_OP (17, br_if_nargs_lt, "br-if-nargs-lt", OP2 (U8_U24, X8_L24))
+  VM_DEFINE_OP (19, br_if_nargs_lt, "br-if-nargs-lt", OP2 (U8_U24, X8_L24))
     {
       BR_NARGS (<);
     }
-  VM_DEFINE_OP (18, br_if_nargs_gt, "br-if-nargs-gt", OP2 (U8_U24, X8_L24))
+  VM_DEFINE_OP (20, br_if_nargs_gt, "br-if-nargs-gt", OP2 (U8_U24, X8_L24))
     {
       BR_NARGS (>);
     }
@@ -1099,28 +1106,28 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the number of actual arguments is not ==, >=, or <= EXPECTED,
    * respectively, signal an error.
    */
-  VM_DEFINE_OP (19, assert_nargs_ee, "assert-nargs-ee", OP1 (U8_U24))
+  VM_DEFINE_OP (21, assert_nargs_ee, "assert-nargs-ee", OP1 (U8_U24))
     {
       scm_t_uint32 expected;
       UNPACK_24 (op, expected);
       VM_ASSERT (FRAME_LOCALS_COUNT () == expected,
-                 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
+                 vm_error_wrong_num_args (LOCAL_REF (0)));
       NEXT (1);
     }
-  VM_DEFINE_OP (20, assert_nargs_ge, "assert-nargs-ge", OP1 (U8_U24))
+  VM_DEFINE_OP (22, assert_nargs_ge, "assert-nargs-ge", OP1 (U8_U24))
     {
       scm_t_uint32 expected;
       UNPACK_24 (op, expected);
       VM_ASSERT (FRAME_LOCALS_COUNT () >= expected,
-                 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
+                 vm_error_wrong_num_args (LOCAL_REF (0)));
       NEXT (1);
     }
-  VM_DEFINE_OP (21, assert_nargs_le, "assert-nargs-le", OP1 (U8_U24))
+  VM_DEFINE_OP (23, assert_nargs_le, "assert-nargs-le", OP1 (U8_U24))
     {
       scm_t_uint32 expected;
       UNPACK_24 (op, expected);
       VM_ASSERT (FRAME_LOCALS_COUNT () <= expected,
-                 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
+                 vm_error_wrong_num_args (LOCAL_REF (0)));
       NEXT (1);
     }
 
@@ -1130,7 +1137,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * setting them all to SCM_UNDEFINED, except those nargs values that
    * were passed as arguments and procedure.
    */
-  VM_DEFINE_OP (22, alloc_frame, "alloc-frame", OP1 (U8_U24))
+  VM_DEFINE_OP (24, alloc_frame, "alloc-frame", OP1 (U8_U24))
     {
       scm_t_uint32 nlocals, nargs;
       UNPACK_24 (op, nlocals);
@@ -1149,7 +1156,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Used to reset the frame size to something less than the size that
    * was previously set via alloc-frame.
    */
-  VM_DEFINE_OP (23, reset_frame, "reset-frame", OP1 (U8_U24))
+  VM_DEFINE_OP (25, reset_frame, "reset-frame", OP1 (U8_U24))
     {
       scm_t_uint32 nlocals;
       UNPACK_24 (op, nlocals);
@@ -1162,12 +1169,12 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Equivalent to a sequence of assert-nargs-ee and reserve-locals.  The
    * number of locals reserved is EXPECTED + NLOCALS.
    */
-  VM_DEFINE_OP (24, assert_nargs_ee_locals, "assert-nargs-ee/locals", OP1 (U8_U12_U12))
+  VM_DEFINE_OP (26, assert_nargs_ee_locals, "assert-nargs-ee/locals", OP1 (U8_U12_U12))
     {
       scm_t_uint16 expected, nlocals;
       UNPACK_12_12 (op, expected, nlocals);
       VM_ASSERT (FRAME_LOCALS_COUNT () == expected,
-                 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
+                 vm_error_wrong_num_args (LOCAL_REF (0)));
       ALLOC_FRAME (expected + nlocals);
       while (nlocals--)
         LOCAL_SET (expected + nlocals, SCM_UNDEFINED);
@@ -1185,7 +1192,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * See "Case-lambda" in the manual, for more on how case-lambda
    * chooses the clause to apply.
    */
-  VM_DEFINE_OP (25, br_if_npos_gt, "br-if-npos-gt", OP3 (U8_U24, X8_U24, X8_L24))
+  VM_DEFINE_OP (27, br_if_npos_gt, "br-if-npos-gt", OP3 (U8_U24, X8_U24, X8_L24))
     {
       scm_t_uint32 nreq, npos;
 
@@ -1210,8 +1217,9 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       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
@@ -1222,7 +1230,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * A macro-mega-instruction.
    */
-  VM_DEFINE_OP (26, bind_kwargs, "bind-kwargs", OP4 (U8_U24, U8_U24, X8_U24, N32))
+  VM_DEFINE_OP (28, bind_kwargs, "bind-kwargs", OP4 (U8_U24, U8_U24, X8_U24, N32))
     {
       scm_t_uint32 nreq, nreq_and_opt, ntotal, npositional, nkw, n, nargs;
       scm_t_int32 kw_offset;
@@ -1265,7 +1273,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
         LOCAL_SET (n++, SCM_UNDEFINED);
 
       VM_ASSERT (has_rest || (nkw % 2) == 0,
-                 vm_error_kwargs_length_not_even (SCM_FRAME_PROGRAM (fp)));
+                 vm_error_kwargs_length_not_even (LOCAL_REF (0)));
 
       /* Now bind keywords, in the order given.  */
       for (n = 0; n < nkw; n++)
@@ -1281,12 +1289,12 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
                   break;
                 }
             VM_ASSERT (scm_is_pair (walk) || allow_other_keys,
-                       vm_error_kwargs_unrecognized_keyword (SCM_FRAME_PROGRAM (fp),
+                       vm_error_kwargs_unrecognized_keyword (LOCAL_REF (0),
                                                              LOCAL_REF (ntotal + n)));
             n++;
           }
         else
-          VM_ASSERT (has_rest, vm_error_kwargs_invalid_keyword (SCM_FRAME_PROGRAM (fp),
+          VM_ASSERT (has_rest, vm_error_kwargs_invalid_keyword (LOCAL_REF (0),
                                                                 LOCAL_REF (ntotal + n)));
 
       if (has_rest)
@@ -1294,7 +1302,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
           SCM rest = SCM_EOL;
           n = nkw;
           while (n--)
-            rest = scm_cons (LOCAL_REF (ntotal + n), rest);
+            rest = scm_inline_cons (thread, LOCAL_REF (ntotal + n), rest);
           LOCAL_SET (nreq_and_opt, rest);
         }
 
@@ -1308,7 +1316,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Collect any arguments at or above DST into a list, and store that
    * list at DST.
    */
-  VM_DEFINE_OP (27, bind_rest, "bind-rest", OP1 (U8_U24) | OP_DST)
+  VM_DEFINE_OP (29, bind_rest, "bind-rest", OP1 (U8_U24) | OP_DST)
     {
       scm_t_uint32 dst, nargs;
       SCM rest = SCM_EOL;
@@ -1326,7 +1334,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
         {
           while (nargs-- > dst)
             {
-              rest = scm_cons (LOCAL_REF (nargs), rest);
+              rest = scm_inline_cons (thread, LOCAL_REF (nargs), rest);
               LOCAL_SET (nargs, SCM_UNDEFINED);
             }
 
@@ -1350,10 +1358,12 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Add OFFSET, a signed 24-bit number, to the current instruction
    * pointer.
    */
-  VM_DEFINE_OP (28, br, "br", OP1 (U8_L24))
+  VM_DEFINE_OP (30, br, "br", OP1 (U8_L24))
     {
       scm_t_int32 offset = op;
       offset >>= 8; /* Sign-extending shift. */
+      if (offset <= 0)
+        VM_HANDLE_INTERRUPTS;
       NEXT (offset);
     }
 
@@ -1362,7 +1372,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in TEST is true for the purposes of Scheme, add
    * OFFSET, a signed 24-bit number, to the current instruction pointer.
    */
-  VM_DEFINE_OP (29, br_if_true, "br-if-true", OP2 (U8_U24, B1_X7_L24))
+  VM_DEFINE_OP (31, br_if_true, "br-if-true", OP2 (U8_U24, B1_X7_L24))
     {
       BR_UNARY (x, scm_is_true (x));
     }
@@ -1372,7 +1382,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in TEST is the end-of-list or Lisp nil, add OFFSET, a
    * signed 24-bit number, to the current instruction pointer.
    */
-  VM_DEFINE_OP (30, br_if_null, "br-if-null", OP2 (U8_U24, B1_X7_L24))
+  VM_DEFINE_OP (32, br_if_null, "br-if-null", OP2 (U8_U24, B1_X7_L24))
     {
       BR_UNARY (x, scm_is_null (x));
     }
@@ -1382,7 +1392,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in TEST is false to Lisp, add OFFSET, a signed 24-bit
    * number, to the current instruction pointer.
    */
-  VM_DEFINE_OP (31, br_if_nil, "br-if-nil", OP2 (U8_U24, B1_X7_L24))
+  VM_DEFINE_OP (33, br_if_nil, "br-if-nil", OP2 (U8_U24, B1_X7_L24))
     {
       BR_UNARY (x, scm_is_lisp_false (x));
     }
@@ -1392,7 +1402,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in TEST is a pair, add OFFSET, a signed 24-bit number,
    * to the current instruction pointer.
    */
-  VM_DEFINE_OP (32, br_if_pair, "br-if-pair", OP2 (U8_U24, B1_X7_L24))
+  VM_DEFINE_OP (34, br_if_pair, "br-if-pair", OP2 (U8_U24, B1_X7_L24))
     {
       BR_UNARY (x, scm_is_pair (x));
     }
@@ -1402,7 +1412,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in TEST is a struct, add OFFSET, a signed 24-bit
    * number, to the current instruction pointer.
    */
-  VM_DEFINE_OP (33, br_if_struct, "br-if-struct", OP2 (U8_U24, B1_X7_L24))
+  VM_DEFINE_OP (35, br_if_struct, "br-if-struct", OP2 (U8_U24, B1_X7_L24))
     {
       BR_UNARY (x, SCM_STRUCTP (x));
     }
@@ -1412,7 +1422,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in TEST is a char, add OFFSET, a signed 24-bit number,
    * to the current instruction pointer.
    */
-  VM_DEFINE_OP (34, br_if_char, "br-if-char", OP2 (U8_U24, B1_X7_L24))
+  VM_DEFINE_OP (36, br_if_char, "br-if-char", OP2 (U8_U24, B1_X7_L24))
     {
       BR_UNARY (x, SCM_CHARP (x));
     }
@@ -1422,7 +1432,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in TEST has the TC7 given in the second word, add
    * OFFSET, a signed 24-bit number, to the current instruction pointer.
    */
-  VM_DEFINE_OP (35, br_if_tc7, "br-if-tc7", OP2 (U8_U24, B1_U7_L24))
+  VM_DEFINE_OP (37, br_if_tc7, "br-if-tc7", OP2 (U8_U24, B1_U7_L24))
     {
       BR_UNARY (x, SCM_HAS_TYP7 (x, (ip[1] >> 1) & 0x7f));
     }
@@ -1432,7 +1442,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in A is eq? to the value in B, add OFFSET, a signed
    * 24-bit number, to the current instruction pointer.
    */
-  VM_DEFINE_OP (36, br_if_eq, "br-if-eq", OP2 (U8_U12_U12, B1_X7_L24))
+  VM_DEFINE_OP (38, br_if_eq, "br-if-eq", OP2 (U8_U12_U12, B1_X7_L24))
     {
       BR_BINARY (x, y, scm_is_eq (x, y));
     }
@@ -1442,7 +1452,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in A is eqv? to the value in B, add OFFSET, a signed
    * 24-bit number, to the current instruction pointer.
    */
-  VM_DEFINE_OP (37, br_if_eqv, "br-if-eqv", OP2 (U8_U12_U12, B1_X7_L24))
+  VM_DEFINE_OP (39, br_if_eqv, "br-if-eqv", OP2 (U8_U12_U12, B1_X7_L24))
     {
       BR_BINARY (x, y,
                  scm_is_eq (x, y)
@@ -1456,8 +1466,9 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in A is equal? to the value in B, add OFFSET, a signed
    * 24-bit number, to the current instruction pointer.
    */
-  // FIXME: should sync_ip before calling out?
-  VM_DEFINE_OP (38, br_if_equal, "br-if-equal", OP2 (U8_U12_U12, B1_X7_L24))
+  // FIXME: Should sync_ip before calling out and cache_fp before coming
+  // back!  Another reason to remove this opcode!
+  VM_DEFINE_OP (40, br_if_equal, "br-if-equal", OP2 (U8_U12_U12, B1_X7_L24))
     {
       BR_BINARY (x, y,
                  scm_is_eq (x, y)
@@ -1470,27 +1481,27 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * If the value in A is = to the value in B, add OFFSET, a signed
    * 24-bit number, to the current instruction pointer.
    */
-  VM_DEFINE_OP (39, br_if_ee, "br-if-=", OP2 (U8_U12_U12, B1_X7_L24))
+  VM_DEFINE_OP (41, br_if_ee, "br-if-=", OP2 (U8_U12_U12, B1_X7_L24))
     {
       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.
    */
-  VM_DEFINE_OP (40, br_if_lt, "br-if-<", OP2 (U8_U12_U12, B1_X7_L24))
+  VM_DEFINE_OP (42, br_if_lt, "br-if-<", OP2 (U8_U12_U12, B1_X7_L24))
     {
       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.
    */
-  VM_DEFINE_OP (41, br_if_le, "br-if-<=", OP2 (U8_U12_U12, B1_X7_L24))
+  VM_DEFINE_OP (43, br_if_le, "br-if-<=", OP2 (U8_U12_U12, B1_X7_L24))
     {
       BR_ARITHMETIC (<=, scm_leq_p);
     }
@@ -1506,7 +1517,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Copy a value from one local slot to another.
    */
-  VM_DEFINE_OP (42, mov, "mov", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (44, mov, "mov", OP1 (U8_U12_U12) | OP_DST)
     {
       scm_t_uint16 dst;
       scm_t_uint16 src;
@@ -1521,7 +1532,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Copy a value from one local slot to another.
    */
-  VM_DEFINE_OP (43, long_mov, "long-mov", OP2 (U8_U24, X8_U24) | OP_DST)
+  VM_DEFINE_OP (45, long_mov, "long-mov", OP2 (U8_U24, X8_U24) | OP_DST)
     {
       scm_t_uint32 dst;
       scm_t_uint32 src;
@@ -1537,11 +1548,12 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Create a new variable holding SRC, and place it in DST.
    */
-  VM_DEFINE_OP (44, box, "box", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (46, box, "box", OP1 (U8_U12_U12) | OP_DST)
     {
       scm_t_uint16 dst, src;
       UNPACK_12_12 (op, dst, src);
-      LOCAL_SET (dst, scm_cell (scm_tc7_variable, SCM_UNPACK (LOCAL_REF (src))));
+      LOCAL_SET (dst, scm_inline_cell (thread, scm_tc7_variable,
+                                       SCM_UNPACK (LOCAL_REF (src))));
       NEXT (1);
     }
 
@@ -1550,7 +1562,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Unpack the variable at SRC into DST, asserting that the variable is
    * actually bound.
    */
-  VM_DEFINE_OP (45, box_ref, "box-ref", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (47, box_ref, "box-ref", OP1 (U8_U12_U12) | OP_DST)
     {
       scm_t_uint16 dst, src;
       SCM var;
@@ -1558,8 +1570,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       var = LOCAL_REF (src);
       VM_ASSERT (SCM_VARIABLEP (var),
                  vm_error_not_a_variable ("variable-ref", var));
-      VM_ASSERT (VARIABLE_BOUNDP (var),
-                 vm_error_unbound (SCM_FRAME_PROGRAM (fp), var));
+      VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (var));
       LOCAL_SET (dst, VARIABLE_REF (var));
       NEXT (1);
     }
@@ -1568,7 +1579,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Set the contents of the variable at DST to SET.
    */
-  VM_DEFINE_OP (46, box_set, "box-set!", OP1 (U8_U12_U12))
+  VM_DEFINE_OP (48, box_set, "box-set!", OP1 (U8_U12_U12))
     {
       scm_t_uint16 dst, src;
       SCM var;
@@ -1587,7 +1598,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * signed 32-bit integer.  Space for NFREE free variables will be
    * allocated.
    */
-  VM_DEFINE_OP (47, make_closure, "make-closure", OP3 (U8_U24, L32, X8_U24) | OP_DST)
+  VM_DEFINE_OP (49, make_closure, "make-closure", OP3 (U8_U24, L32, X8_U24) | OP_DST)
     {
       scm_t_uint32 dst, nfree, n;
       scm_t_int32 offset;
@@ -1598,7 +1609,8 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       UNPACK_24 (ip[2], nfree);
 
       // FIXME: Assert range of nfree?
-      closure = scm_words (scm_tc7_program | (nfree << 16), nfree + 2);
+      closure = scm_inline_words (thread, scm_tc7_program | (nfree << 16),
+                                  nfree + 2);
       SCM_SET_CELL_WORD_1 (closure, ip + offset);
       // FIXME: Elide these initializations?
       for (n = 0; n < nfree; n++)
@@ -1611,7 +1623,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Load free variable IDX from the closure SRC into local slot DST.
    */
-  VM_DEFINE_OP (48, free_ref, "free-ref", OP2 (U8_U12_U12, X8_U24) | OP_DST)
+  VM_DEFINE_OP (50, free_ref, "free-ref", OP2 (U8_U12_U12, X8_U24) | OP_DST)
     {
       scm_t_uint16 dst, src;
       scm_t_uint32 idx;
@@ -1622,11 +1634,11 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       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.
    */
-  VM_DEFINE_OP (49, free_set, "free-set!", OP2 (U8_U12_U12, X8_U24))
+  VM_DEFINE_OP (51, free_set, "free-set!", OP2 (U8_U12_U12, X8_U24))
     {
       scm_t_uint16 dst, src;
       scm_t_uint32 idx;
@@ -1649,7 +1661,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Make an immediate whose low bits are LOW-BITS, and whose top bits are
    * 0.
    */
-  VM_DEFINE_OP (50, make_short_immediate, "make-short-immediate", OP1 (U8_U8_I16) | OP_DST)
+  VM_DEFINE_OP (52, make_short_immediate, "make-short-immediate", OP1 (U8_U8_I16) | OP_DST)
     {
       scm_t_uint8 dst;
       scm_t_bits val;
@@ -1664,7 +1676,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Make an immediate whose low bits are LOW-BITS, and whose top bits are
    * 0.
    */
-  VM_DEFINE_OP (51, make_long_immediate, "make-long-immediate", OP2 (U8_U24, I32))
+  VM_DEFINE_OP (53, make_long_immediate, "make-long-immediate", OP2 (U8_U24, I32) | OP_DST)
     {
       scm_t_uint32 dst;
       scm_t_bits val;
@@ -1679,7 +1691,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Make an immediate with HIGH-BITS and LOW-BITS.
    */
-  VM_DEFINE_OP (52, make_long_long_immediate, "make-long-long-immediate", OP3 (U8_U24, A32, B32) | OP_DST)
+  VM_DEFINE_OP (54, make_long_long_immediate, "make-long-long-immediate", OP3 (U8_U24, A32, B32) | OP_DST)
     {
       scm_t_uint32 dst;
       scm_t_bits val;
@@ -1710,7 +1722,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Whether the object is mutable or immutable depends on where it was
    * allocated by the compiler, and loaded by the loader.
    */
-  VM_DEFINE_OP (53, make_non_immediate, "make-non-immediate", OP2 (U8_U24, N32) | OP_DST)
+  VM_DEFINE_OP (55, make_non_immediate, "make-non-immediate", OP2 (U8_U24, N32) | OP_DST)
     {
       scm_t_uint32 dst;
       scm_t_int32 offset;
@@ -1739,7 +1751,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * that the compiler is unable to statically allocate, like symbols.
    * These values would be initialized when the object file loads.
    */
-  VM_DEFINE_OP (54, static_ref, "static-ref", OP2 (U8_U24, S32))
+  VM_DEFINE_OP (56, static_ref, "static-ref", OP2 (U8_U24, S32) | OP_DST)
     {
       scm_t_uint32 dst;
       scm_t_int32 offset;
@@ -1762,7 +1774,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Store a SCM value into memory, OFFSET 32-bit words away from the
    * current instruction pointer.  OFFSET is a signed value.
    */
-  VM_DEFINE_OP (55, static_set, "static-set!", OP2 (U8_U24, LO32))
+  VM_DEFINE_OP (57, static_set, "static-set!", OP2 (U8_U24, LO32))
     {
       scm_t_uint32 src;
       scm_t_int32 offset;
@@ -1784,7 +1796,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * are signed 32-bit values, indicating a memory address as a number
    * of 32-bit words away from the current instruction pointer.
    */
-  VM_DEFINE_OP (56, static_patch, "static-patch!", OP3 (U8_X24, LO32, L32))
+  VM_DEFINE_OP (58, static_patch, "static-patch!", OP3 (U8_X24, LO32, L32))
     {
       scm_t_int32 dst_offset, src_offset;
       void *src;
@@ -1842,7 +1854,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Store the current module in DST.
    */
-  VM_DEFINE_OP (57, current_module, "current-module", OP1 (U8_U24) | OP_DST)
+  VM_DEFINE_OP (59, current_module, "current-module", OP1 (U8_U24) | OP_DST)
     {
       scm_t_uint32 dst;
 
@@ -1859,7 +1871,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Resolve SYM in the current module, and place the resulting variable
    * in DST.
    */
-  VM_DEFINE_OP (58, resolve, "resolve", OP2 (U8_U24, B1_X7_U24) | OP_DST)
+  VM_DEFINE_OP (60, resolve, "resolve", OP2 (U8_U24, B1_X7_U24) | OP_DST)
     {
       scm_t_uint32 dst;
       scm_t_uint32 sym;
@@ -1870,9 +1882,9 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 
       SYNC_IP ();
       var = scm_lookup (LOCAL_REF (sym));
+      CACHE_FP ();
       if (ip[1] & 0x1)
-        VM_ASSERT (VARIABLE_BOUNDP (var),
-                   vm_error_unbound (fp[0], LOCAL_REF (sym)));
+        VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (LOCAL_REF (sym)));
       LOCAL_SET (dst, var);
 
       NEXT (2);
@@ -1883,12 +1895,13 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Look up a binding for SYM in the current module, creating it if
    * necessary.  Set its value to VAL.
    */
-  VM_DEFINE_OP (59, define, "define!", OP1 (U8_U12_U12))
+  VM_DEFINE_OP (61, define, "define!", OP1 (U8_U12_U12))
     {
       scm_t_uint16 sym, val;
       UNPACK_12_12 (op, sym, val);
       SYNC_IP ();
       scm_define (LOCAL_REF (sym), LOCAL_REF (val));
+      CACHE_FP ();
       NEXT (1);
     }
 
@@ -1911,7 +1924,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * DST, and caching the resolved variable so that we will hit the cache next
    * time.
    */
-  VM_DEFINE_OP (60, toplevel_box, "toplevel-box", OP5 (U8_U24, S32, S32, N32, B1_X31) | OP_DST)
+  VM_DEFINE_OP (62, toplevel_box, "toplevel-box", OP5 (U8_U24, S32, S32, N32, B1_X31) | OP_DST)
     {
       scm_t_uint32 dst;
       scm_t_int32 var_offset;
@@ -1948,8 +1961,9 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
             mod = scm_the_root_module ();
 
           var = scm_module_lookup (mod, sym);
+          CACHE_FP ();
           if (ip[4] & 0x1)
-            VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (fp[0], sym));
+            VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (sym));
 
           *var_loc = var;
         }
@@ -1963,7 +1977,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Like toplevel-box, except MOD-OFFSET points at the name of a module
    * instead of the module itself.
    */
-  VM_DEFINE_OP (61, module_box, "module-box", OP5 (U8_U24, S32, N32, N32, B1_X31) | OP_DST)
+  VM_DEFINE_OP (63, module_box, "module-box", OP5 (U8_U24, S32, N32, N32, B1_X31) | OP_DST)
     {
       scm_t_uint32 dst;
       scm_t_int32 var_offset;
@@ -1996,13 +2010,11 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 
           if (!scm_module_system_booted_p)
             {
-#ifdef VM_ENABLE_PARANOID_ASSERTIONS
-              ASSERT
-                (scm_is_true
-                 scm_equal_p (modname,
-                              scm_list_2 (SCM_BOOL_T,
-                                          scm_from_utf8_symbol ("guile"))));
-#endif
+              ASSERT (scm_is_true
+                      scm_equal_p (modname,
+                                   scm_list_2
+                                   (SCM_BOOL_T,
+                                    scm_from_utf8_symbol ("guile"))));
               var = scm_lookup (sym);
             }
           else if (scm_is_true (SCM_CAR (modname)))
@@ -2010,8 +2022,10 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
           else
             var = scm_private_lookup (SCM_CDR (modname), sym);
 
+          CACHE_FP ();
+
           if (ip[4] & 0x1)
-            VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (fp[0], sym));
+            VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (sym));
 
           *var_loc = var;
         }
@@ -2033,7 +2047,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * will expect a multiple-value return as if from a call with the
    * procedure at PROC-SLOT.
    */
-  VM_DEFINE_OP (62, prompt, "prompt", OP3 (U8_U24, B1_X7_U24, X8_L24))
+  VM_DEFINE_OP (64, prompt, "prompt", OP3 (U8_U24, B1_X7_U24, X8_L24))
     {
       scm_t_uint32 tag, proc_slot;
       scm_t_int32 offset;
@@ -2048,12 +2062,12 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
   
       /* Push the prompt onto the dynamic stack. */
       flags = escape_only_p ? SCM_F_DYNSTACK_PROMPT_ESCAPE_ONLY : 0;
-      scm_dynstack_push_prompt (&current_thread->dynstack, flags,
+      scm_dynstack_push_prompt (&thread->dynstack, flags,
                                 LOCAL_REF (tag),
                                 fp - vp->stack_base,
                                 LOCAL_ADDRESS (proc_slot) - vp->stack_base,
                                 ip + offset,
-                                &registers);
+                                registers);
       NEXT (3);
     }
 
@@ -2065,11 +2079,11 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * the compiler should have inserted checks that they wind and unwind
    * procs are thunks, if it could not prove that to be the case.
    */
-  VM_DEFINE_OP (63, wind, "wind", OP1 (U8_U12_U12))
+  VM_DEFINE_OP (65, wind, "wind", OP1 (U8_U12_U12))
     {
       scm_t_uint16 winder, unwinder;
       UNPACK_12_12 (op, winder, unwinder);
-      scm_dynstack_push_dynwind (&current_thread->dynstack,
+      scm_dynstack_push_dynwind (&thread->dynstack,
                                  LOCAL_REF (winder), LOCAL_REF (unwinder));
       NEXT (1);
     }
@@ -2079,40 +2093,38 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * A normal exit from the dynamic extent of an expression. Pop the top
    * entry off of the dynamic stack.
    */
-  VM_DEFINE_OP (64, unwind, "unwind", OP1 (U8_X24))
+  VM_DEFINE_OP (66, unwind, "unwind", OP1 (U8_X24))
     {
-      scm_dynstack_pop (&current_thread->dynstack);
+      scm_dynstack_pop (&thread->dynstack);
       NEXT (1);
     }
 
   /* 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))
+  VM_DEFINE_OP (67, push_fluid, "push-fluid", OP1 (U8_U12_U12))
     {
       scm_t_uint32 fluid, value;
 
       UNPACK_12_12 (op, fluid, value);
 
-      scm_dynstack_push_fluid (&current_thread->dynstack,
+      scm_dynstack_push_fluid (&thread->dynstack,
                                LOCAL_REF (fluid), LOCAL_REF (value),
-                               current_thread->dynamic_state);
+                               thread->dynamic_state);
       NEXT (1);
     }
 
   /* 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))
+  VM_DEFINE_OP (68, pop_fluid, "pop-fluid", OP1 (U8_X24))
     {
       /* This function must not allocate.  */
-      scm_dynstack_unwind_fluid (&current_thread->dynstack,
-                                 current_thread->dynamic_state);
+      scm_dynstack_unwind_fluid (&thread->dynstack,
+                                 thread->dynamic_state);
       NEXT (1);
     }
 
@@ -2120,7 +2132,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Reference the fluid in SRC, and place the value in DST.
    */
-  VM_DEFINE_OP (67, fluid_ref, "fluid-ref", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (69, fluid_ref, "fluid-ref", OP1 (U8_U12_U12) | OP_DST)
     {
       scm_t_uint16 dst, src;
       size_t num;
@@ -2128,7 +2140,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 
       UNPACK_12_12 (op, dst, src);
       fluid = LOCAL_REF (src);
-      fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
+      fluids = SCM_I_DYNAMIC_STATE_FLUIDS (thread->dynamic_state);
       if (SCM_UNLIKELY (!SCM_FLUID_P (fluid))
           || ((num = SCM_I_FLUID_NUM (fluid)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
         {
@@ -2142,7 +2154,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
           if (scm_is_eq (val, SCM_UNDEFINED))
             val = SCM_I_FLUID_DEFAULT (fluid);
           VM_ASSERT (!scm_is_eq (val, SCM_UNDEFINED),
-                     vm_error_unbound_fluid (program, fluid));
+                     vm_error_unbound_fluid (fluid));
           LOCAL_SET (dst, val);
         }
 
@@ -2153,7 +2165,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Set the value of the fluid in DST to the value in SRC.
    */
-  VM_DEFINE_OP (68, fluid_set, "fluid-set", OP1 (U8_U12_U12))
+  VM_DEFINE_OP (70, fluid_set, "fluid-set", OP1 (U8_U12_U12))
     {
       scm_t_uint16 a, b;
       size_t num;
@@ -2161,7 +2173,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 
       UNPACK_12_12 (op, a, b);
       fluid = LOCAL_REF (a);
-      fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
+      fluids = SCM_I_DYNAMIC_STATE_FLUIDS (thread->dynamic_state);
       if (SCM_UNLIKELY (!SCM_FLUID_P (fluid))
           || ((num = SCM_I_FLUID_NUM (fluid)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
         {
@@ -2186,7 +2198,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Store the length of the string in SRC in DST.
    */
-  VM_DEFINE_OP (69, string_length, "string-length", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (71, string_length, "string-length", OP1 (U8_U12_U12) | OP_DST)
     {
       ARGS1 (str);
       if (SCM_LIKELY (scm_is_string (str)))
@@ -2203,7 +2215,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Fetch the character at position IDX in the string in SRC, and store
    * it in DST.
    */
-  VM_DEFINE_OP (70, string_ref, "string-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (72, string_ref, "string-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       scm_t_signed_bits i = 0;
       ARGS2 (str, idx);
@@ -2221,11 +2233,11 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 
   /* 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.
    */
-  VM_DEFINE_OP (71, string_to_number, "string->number", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (73, string_to_number, "string->number", OP1 (U8_U12_U12) | OP_DST)
     {
       scm_t_uint16 dst, src;
 
@@ -2237,11 +2249,11 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       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.
    */
-  VM_DEFINE_OP (72, string_to_symbol, "string->symbol", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (74, string_to_symbol, "string->symbol", OP1 (U8_U12_U12) | OP_DST)
     {
       scm_t_uint16 dst, src;
 
@@ -2255,7 +2267,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Make a keyword from the symbol in SRC, and store it in DST.
    */
-  VM_DEFINE_OP (73, symbol_to_keyword, "symbol->keyword", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (75, symbol_to_keyword, "symbol->keyword", OP1 (U8_U12_U12) | OP_DST)
     {
       scm_t_uint16 dst, src;
       UNPACK_12_12 (op, dst, src);
@@ -2274,17 +2286,17 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Cons CAR and CDR, and store the result in DST.
    */
-  VM_DEFINE_OP (74, cons, "cons", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (76, cons, "cons", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
-      RETURN (scm_cons (x, y));
+      RETURN (scm_inline_cons (thread, x, y));
     }
 
   /* car dst:12 src:12
    *
    * Place the car of SRC in DST.
    */
-  VM_DEFINE_OP (75, car, "car", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (77, car, "car", OP1 (U8_U12_U12) | OP_DST)
     {
       ARGS1 (x);
       VM_VALIDATE_PAIR (x, "car");
@@ -2295,7 +2307,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Place the cdr of SRC in DST.
    */
-  VM_DEFINE_OP (76, cdr, "cdr", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (78, cdr, "cdr", OP1 (U8_U12_U12) | OP_DST)
     {
       ARGS1 (x);
       VM_VALIDATE_PAIR (x, "cdr");
@@ -2306,7 +2318,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Set the car of DST to SRC.
    */
-  VM_DEFINE_OP (77, set_car, "set-car!", OP1 (U8_U12_U12))
+  VM_DEFINE_OP (79, set_car, "set-car!", OP1 (U8_U12_U12))
     {
       scm_t_uint16 a, b;
       SCM x, y;
@@ -2322,7 +2334,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Set the cdr of DST to SRC.
    */
-  VM_DEFINE_OP (78, set_cdr, "set-cdr!", OP1 (U8_U12_U12))
+  VM_DEFINE_OP (80, set_cdr, "set-cdr!", OP1 (U8_U12_U12))
     {
       scm_t_uint16 a, b;
       SCM x, y;
@@ -2345,7 +2357,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Add A to B, and place the result in DST.
    */
-  VM_DEFINE_OP (79, add, "add", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (81, add, "add", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       BINARY_INTEGER_OP (+, scm_sum);
     }
@@ -2354,7 +2366,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Add 1 to the value in SRC, and place the result in DST.
    */
-  VM_DEFINE_OP (80, add1, "add1", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (82, add1, "add1", OP1 (U8_U12_U12) | OP_DST)
     {
       ARGS1 (x);
 
@@ -2371,15 +2383,14 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
             RETURN (result);
         }
 
-      SYNC_IP ();
-      RETURN (scm_sum (x, SCM_I_MAKINUM (1)));
+      RETURN_EXP (scm_sum (x, SCM_I_MAKINUM (1)));
     }
 
   /* sub dst:8 a:8 b:8
    *
    * Subtract B from A, and place the result in DST.
    */
-  VM_DEFINE_OP (81, sub, "sub", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (83, sub, "sub", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       BINARY_INTEGER_OP (-, scm_difference);
     }
@@ -2388,7 +2399,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Subtract 1 from SRC, and place the result in DST.
    */
-  VM_DEFINE_OP (82, sub1, "sub1", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (84, sub1, "sub1", OP1 (U8_U12_U12) | OP_DST)
     {
       ARGS1 (x);
 
@@ -2405,70 +2416,64 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
             RETURN (result);
         }
 
-      SYNC_IP ();
-      RETURN (scm_difference (x, SCM_I_MAKINUM (1)));
+      RETURN_EXP (scm_difference (x, SCM_I_MAKINUM (1)));
     }
 
   /* mul dst:8 a:8 b:8
    *
    * Multiply A and B, and place the result in DST.
    */
-  VM_DEFINE_OP (83, mul, "mul", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (85, mul, "mul", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
-      SYNC_IP ();
-      RETURN (scm_product (x, y));
+      RETURN_EXP (scm_product (x, y));
     }
 
   /* div dst:8 a:8 b:8
    *
    * Divide A by B, and place the result in DST.
    */
-  VM_DEFINE_OP (84, div, "div", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (86, div, "div", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
-      SYNC_IP ();
-      RETURN (scm_divide (x, y));
+      RETURN_EXP (scm_divide (x, y));
     }
 
   /* quo dst:8 a:8 b:8
    *
    * Divide A by B, and place the quotient in DST.
    */
-  VM_DEFINE_OP (85, quo, "quo", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (87, quo, "quo", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
-      SYNC_IP ();
-      RETURN (scm_quotient (x, y));
+      RETURN_EXP (scm_quotient (x, y));
     }
 
   /* rem dst:8 a:8 b:8
    *
    * Divide A by B, and place the remainder in DST.
    */
-  VM_DEFINE_OP (86, rem, "rem", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (88, rem, "rem", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
-      SYNC_IP ();
-      RETURN (scm_remainder (x, y));
+      RETURN_EXP (scm_remainder (x, y));
     }
 
   /* mod dst:8 a:8 b:8
    *
    * Place the modulo of A by B in DST.
    */
-  VM_DEFINE_OP (87, mod, "mod", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (89, mod, "mod", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
-      SYNC_IP ();
-      RETURN (scm_modulo (x, y));
+      RETURN_EXP (scm_modulo (x, y));
     }
 
   /* ash dst:8 a:8 b:8
    *
    * Shift A arithmetically by B bits, and place the result in DST.
    */
-  VM_DEFINE_OP (88, ash, "ash", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (90, ash, "ash", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
       if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
@@ -2491,54 +2496,68 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
                   && ((scm_t_bits)
                       (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - bits_to_shift)) + 1)
                       <= 1))
-                RETURN (SCM_I_MAKINUM (nn << bits_to_shift));
+                RETURN (SCM_I_MAKINUM (nn < 0
+                                       ? -(-nn << bits_to_shift)
+                                       : (nn << bits_to_shift)));
               /* fall through */
             }
           /* fall through */
         }
-      SYNC_IP ();
-      RETURN (scm_ash (x, y));
+      RETURN_EXP (scm_ash (x, y));
     }
 
   /* logand dst:8 a:8 b:8
    *
    * Place the bitwise AND of A and B into DST.
    */
-  VM_DEFINE_OP (89, logand, "logand", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (91, logand, "logand", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
       if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
         /* Compute bitwise AND without untagging */
         RETURN (SCM_PACK (SCM_UNPACK (x) & SCM_UNPACK (y)));
-      SYNC_IP ();
-      RETURN (scm_logand (x, y));
+      RETURN_EXP (scm_logand (x, y));
     }
 
   /* logior dst:8 a:8 b:8
    *
    * Place the bitwise inclusive OR of A with B in DST.
    */
-  VM_DEFINE_OP (90, logior, "logior", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (92, logior, "logior", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
       if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
         /* Compute bitwise OR without untagging */
         RETURN (SCM_PACK (SCM_UNPACK (x) | SCM_UNPACK (y)));
-      SYNC_IP ();
-      RETURN (scm_logior (x, y));
+      RETURN_EXP (scm_logior (x, y));
     }
 
   /* logxor dst:8 a:8 b:8
    *
    * Place the bitwise exclusive OR of A with B in DST.
    */
-  VM_DEFINE_OP (91, logxor, "logxor", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (93, logxor, "logxor", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       ARGS2 (x, y);
       if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
         RETURN (SCM_I_MAKINUM (SCM_I_INUM (x) ^ SCM_I_INUM (y)));
-      SYNC_IP ();
-      RETURN (scm_logxor (x, y));
+      RETURN_EXP (scm_logxor (x, y));
+    }
+
+  /* make-vector dst:8 length:8 init:8
+   *
+   * Make a vector and write it to DST.  The vector will have space for
+   * LENGTH slots.  They will be filled with the value in slot INIT.
+   */
+  VM_DEFINE_OP (94, make_vector, "make-vector", OP1 (U8_U8_U8_U8) | OP_DST)
+    {
+      scm_t_uint8 dst, init, length;
+
+      UNPACK_8_8_8 (op, dst, length, init);
+
+      LOCAL_SET (dst, scm_make_vector (LOCAL_REF (length), LOCAL_REF (init)));
+
+      NEXT (1);
     }
 
   /* make-vector/immediate dst:8 length:8 init:8
@@ -2547,7 +2566,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * will have space for LENGTH slots, an immediate value.  They will be
    * filled with the value in slot INIT.
    */
-  VM_DEFINE_OP (92, make_vector_immediate, "make-vector/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (95, make_vector_immediate, "make-vector/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       scm_t_uint8 dst, init;
       scm_t_int32 length, n;
@@ -2556,7 +2575,8 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       UNPACK_8_8_8 (op, dst, length, init);
 
       val = LOCAL_REF (init);
-      vector = scm_words (scm_tc7_vector | (length << 8), length + 1);
+      vector = scm_inline_words (thread, scm_tc7_vector | (length << 8),
+                                 length + 1);
       for (n = 0; n < length; n++)
         SCM_SIMPLE_VECTOR_SET (vector, n, val);
       LOCAL_SET (dst, vector);
@@ -2567,16 +2587,12 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Store the length of the vector in SRC in DST.
    */
-  VM_DEFINE_OP (93, vector_length, "vector-length", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (96, vector_length, "vector-length", OP1 (U8_U12_U12) | OP_DST)
     {
       ARGS1 (vect);
-      if (SCM_LIKELY (SCM_I_IS_VECTOR (vect)))
-        RETURN (SCM_I_MAKINUM (SCM_I_VECTOR_LENGTH (vect)));
-      else
-        {
-          SYNC_IP ();
-          RETURN (scm_vector_length (vect));
-        }
+      VM_ASSERT (SCM_I_IS_VECTOR (vect),
+                 vm_error_not_a_vector ("vector-ref", vect));
+      RETURN (SCM_I_MAKINUM (SCM_I_VECTOR_LENGTH (vect)));
     }
 
   /* vector-ref dst:8 src:8 idx:8
@@ -2584,20 +2600,17 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Fetch the item at position IDX in the vector in SRC, and store it
    * in DST.
    */
-  VM_DEFINE_OP (94, vector_ref, "vector-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (97, vector_ref, "vector-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       scm_t_signed_bits i = 0;
       ARGS2 (vect, idx);
-      if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
-                      && SCM_I_INUMP (idx)
-                      && ((i = SCM_I_INUM (idx)) >= 0)
-                      && i < SCM_I_VECTOR_LENGTH (vect)))
-        RETURN (SCM_I_VECTOR_ELTS (vect)[i]);
-      else
-        {
-          SYNC_IP ();
-          RETURN (scm_vector_ref (vect, idx));
-        }
+      VM_ASSERT (SCM_I_IS_VECTOR (vect),
+                 vm_error_not_a_vector ("vector-ref", vect));
+      VM_ASSERT ((SCM_I_INUMP (idx)
+                  && ((i = SCM_I_INUM (idx)) >= 0)
+                  && i < SCM_I_VECTOR_LENGTH (vect)),
+                 vm_error_out_of_range ("vector-ref", idx));
+      RETURN (SCM_I_VECTOR_ELTS (vect)[i]);
     }
 
   /* vector-ref/immediate dst:8 src:8 idx:8
@@ -2605,18 +2618,18 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Fill DST with the item IDX elements into the vector at SRC.  Useful
    * for building data types using vectors.
    */
-  VM_DEFINE_OP (95, vector_ref_immediate, "vector-ref/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (98, vector_ref_immediate, "vector-ref/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       scm_t_uint8 dst, src, idx;
       SCM v;
       
       UNPACK_8_8_8 (op, dst, src, idx);
       v = LOCAL_REF (src);
-      if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (v)
-                      && idx < SCM_I_VECTOR_LENGTH (v)))
-        LOCAL_SET (dst, SCM_I_VECTOR_ELTS (LOCAL_REF (src))[idx]);
-      else
-        LOCAL_SET (dst, scm_c_vector_ref (v, idx));
+      VM_ASSERT (SCM_I_IS_VECTOR (v),
+                 vm_error_not_a_vector ("vector-ref", v));
+      VM_ASSERT (idx < SCM_I_VECTOR_LENGTH (v),
+                 vm_error_out_of_range ("vector-ref", scm_from_size_t (idx)));
+      LOCAL_SET (dst, SCM_I_VECTOR_ELTS (LOCAL_REF (src))[idx]);
       NEXT (1);
     }
 
@@ -2624,7 +2637,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Store SRC into the vector DST at index IDX.
    */
-  VM_DEFINE_OP (96, vector_set, "vector-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (99, vector_set, "vector-set!", OP1 (U8_U8_U8_U8))
     {
       scm_t_uint8 dst, idx_var, src;
       SCM vect, idx, val;
@@ -2635,16 +2648,13 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       idx = LOCAL_REF (idx_var);
       val = LOCAL_REF (src);
 
-      if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
-                      && SCM_I_INUMP (idx)
-                      && ((i = SCM_I_INUM (idx)) >= 0)
-                      && i < SCM_I_VECTOR_LENGTH (vect)))
-        SCM_I_VECTOR_WELTS (vect)[i] = val;
-      else
-        {
-          SYNC_IP ();
-          scm_vector_set_x (vect, idx, val);
-        }
+      VM_ASSERT (SCM_I_IS_VECTOR (vect),
+                 vm_error_not_a_vector ("vector-ref", vect));
+      VM_ASSERT ((SCM_I_INUMP (idx)
+                  && ((i = SCM_I_INUM (idx)) >= 0)
+                  && i < SCM_I_VECTOR_LENGTH (vect)),
+                 vm_error_out_of_range ("vector-ref", idx));
+      SCM_I_VECTOR_WELTS (vect)[i] = val;
       NEXT (1);
     }
 
@@ -2653,7 +2663,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Store SRC into the vector DST at index IDX.  Here IDX is an
    * immediate value.
    */
-  VM_DEFINE_OP (97, vector_set_immediate, "vector-set!/immediate", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (100, vector_set_immediate, "vector-set!/immediate", OP1 (U8_U8_U8_U8))
     {
       scm_t_uint8 dst, idx, src;
       SCM vect, val;
@@ -2662,14 +2672,11 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       vect = LOCAL_REF (dst);
       val = LOCAL_REF (src);
 
-      if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
-                      && idx < SCM_I_VECTOR_LENGTH (vect)))
-        SCM_I_VECTOR_WELTS (vect)[idx] = val;
-      else
-        {
-          SYNC_IP ();
-          scm_vector_set_x (vect, scm_from_uint8 (idx), val);
-        }
+      VM_ASSERT (SCM_I_IS_VECTOR (vect),
+                 vm_error_not_a_vector ("vector-ref", vect));
+      VM_ASSERT (idx < SCM_I_VECTOR_LENGTH (vect),
+                 vm_error_out_of_range ("vector-ref", scm_from_size_t (idx)));
+      SCM_I_VECTOR_WELTS (vect)[idx] = val;
       NEXT (1);
     }
 
@@ -2684,7 +2691,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Store the vtable of SRC into DST.
    */
-  VM_DEFINE_OP (98, struct_vtable, "struct-vtable", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (101, struct_vtable, "struct-vtable", OP1 (U8_U12_U12) | OP_DST)
     {
       ARGS1 (obj);
       VM_VALIDATE_STRUCT (obj, "struct_vtable");
@@ -2697,7 +2704,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * will be constructed with space for NFIELDS fields, which should
    * correspond to the field count of the VTABLE.
    */
-  VM_DEFINE_OP (99, allocate_struct_immediate, "allocate-struct/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (102, allocate_struct_immediate, "allocate-struct/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       scm_t_uint8 dst, vtable, nfields;
       SCM ret;
@@ -2716,7 +2723,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Fetch the item at slot IDX in the struct in SRC, and store it
    * in DST.  IDX is an immediate unsigned 8-bit value.
    */
-  VM_DEFINE_OP (100, struct_ref_immediate, "struct-ref/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (103, struct_ref_immediate, "struct-ref/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
     {
       scm_t_uint8 dst, src, idx;
       SCM obj;
@@ -2741,7 +2748,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * Store SRC into the struct DST at slot IDX.  IDX is an immediate
    * unsigned 8-bit value.
    */
-  VM_DEFINE_OP (101, struct_set_immediate, "struct-set!/immediate", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (104, struct_set_immediate, "struct-set!/immediate", OP1 (U8_U8_U8_U8))
     {
       scm_t_uint8 dst, idx, src;
       SCM obj, val;
@@ -2772,7 +2779,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    *
    * Store the vtable of SRC into DST.
    */
-  VM_DEFINE_OP (102, class_of, "class-of", OP1 (U8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (105, class_of, "class-of", OP1 (U8_U12_U12) | OP_DST)
     {
       ARGS1 (obj);
       if (SCM_INSTANCEP (obj))
@@ -2781,35 +2788,6 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       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);
-    }
-
-
   \f
 
   /*
@@ -2822,7 +2800,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
    * from the instruction pointer, and store into DST.  LEN is a byte
    * length.  OFFSET is signed.
    */
-  VM_DEFINE_OP (105, load_typed_array, "load-typed-array", OP3 (U8_U8_U8_U8, N32, U32) | OP_DST)
+  VM_DEFINE_OP (106, load_typed_array, "load-typed-array", OP3 (U8_U8_U8_U8, N32, U32) | OP_DST)
     {
       scm_t_uint8 dst, type, shape;
       scm_t_int32 offset;
@@ -2838,15 +2816,15 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       NEXT (3);
     }
 
-  /* make-array dst:12 type:12 _:8 fill:12 bounds:12
+  /* make-array dst:8 type:8 fill:8 _:8 bounds:24
    *
    * Make a new array with TYPE, FILL, and BOUNDS, storing it in DST.
    */
-  VM_DEFINE_OP (106, make_array, "make-array", OP2 (U8_U12_U12, X8_U12_U12) | OP_DST)
+  VM_DEFINE_OP (107, make_array, "make-array", OP2 (U8_U8_U8_U8, X8_U24) | OP_DST)
     {
-      scm_t_uint16 dst, type, fill, bounds;
-      UNPACK_12_12 (op, dst, type);
-      UNPACK_12_12 (ip[1], fill, bounds);
+      scm_t_uint8 dst, type, fill, bounds;
+      UNPACK_8_8_8 (op, dst, type, fill);
+      UNPACK_24 (ip[1], bounds);
       SYNC_IP ();
       LOCAL_SET (dst, scm_make_typed_array (LOCAL_REF (type), LOCAL_REF (fill),
                                             LOCAL_REF (bounds)));
@@ -2940,42 +2918,42 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
       RETURN (scm_bytevector_ ## fn_stem ## _native_ref (bv, idx));    \
   } while (0)
 
-  VM_DEFINE_OP (107, bv_u8_ref, "bv-u8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (108, bv_u8_ref, "bv-u8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     BV_FIXABLE_INT_REF (u8, u8, uint8, 1);
 
-  VM_DEFINE_OP (108, bv_s8_ref, "bv-s8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (109, bv_s8_ref, "bv-s8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     BV_FIXABLE_INT_REF (s8, s8, int8, 1);
 
-  VM_DEFINE_OP (109, bv_u16_ref, "bv-u16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (110, bv_u16_ref, "bv-u16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     BV_FIXABLE_INT_REF (u16, u16_native, uint16, 2);
 
-  VM_DEFINE_OP (110, bv_s16_ref, "bv-s16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (111, bv_s16_ref, "bv-s16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     BV_FIXABLE_INT_REF (s16, s16_native, int16, 2);
 
-  VM_DEFINE_OP (111, bv_u32_ref, "bv-u32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (112, bv_u32_ref, "bv-u32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
 #if SIZEOF_VOID_P > 4
     BV_FIXABLE_INT_REF (u32, u32_native, uint32, 4);
 #else
     BV_INT_REF (u32, uint32, 4);
 #endif
 
-  VM_DEFINE_OP (112, bv_s32_ref, "bv-s32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (113, bv_s32_ref, "bv-s32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
 #if SIZEOF_VOID_P > 4
     BV_FIXABLE_INT_REF (s32, s32_native, int32, 4);
 #else
     BV_INT_REF (s32, int32, 4);
 #endif
 
-  VM_DEFINE_OP (113, bv_u64_ref, "bv-u64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (114, bv_u64_ref, "bv-u64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     BV_INT_REF (u64, uint64, 8);
 
-  VM_DEFINE_OP (114, bv_s64_ref, "bv-s64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (115, bv_s64_ref, "bv-s64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     BV_INT_REF (s64, int64, 8);
 
-  VM_DEFINE_OP (115, bv_f32_ref, "bv-f32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (116, bv_f32_ref, "bv-f32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     BV_FLOAT_REF (f32, ieee_single, float, 4);
 
-  VM_DEFINE_OP (116, bv_f64_ref, "bv-f64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+  VM_DEFINE_OP (117, bv_f64_ref, "bv-f64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
     BV_FLOAT_REF (f64, ieee_double, double, 8);
 
   /* bv-u8-set! dst:8 idx:8 src:8
@@ -3079,50 +3057,275 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
     NEXT (1);                                                           \
   } while (0)
 
-  VM_DEFINE_OP (117, bv_u8_set, "bv-u8-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (118, bv_u8_set, "bv-u8-set!", OP1 (U8_U8_U8_U8))
     BV_FIXABLE_INT_SET (u8, u8, uint8, 0, SCM_T_UINT8_MAX, 1);
 
-  VM_DEFINE_OP (118, bv_s8_set, "bv-s8-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (119, bv_s8_set, "bv-s8-set!", OP1 (U8_U8_U8_U8))
     BV_FIXABLE_INT_SET (s8, s8, int8, SCM_T_INT8_MIN, SCM_T_INT8_MAX, 1);
 
-  VM_DEFINE_OP (119, bv_u16_set, "bv-u16-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (120, bv_u16_set, "bv-u16-set!", OP1 (U8_U8_U8_U8))
     BV_FIXABLE_INT_SET (u16, u16_native, uint16, 0, SCM_T_UINT16_MAX, 2);
 
-  VM_DEFINE_OP (120, bv_s16_set, "bv-s16-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (121, bv_s16_set, "bv-s16-set!", OP1 (U8_U8_U8_U8))
     BV_FIXABLE_INT_SET (s16, s16_native, int16, SCM_T_INT16_MIN, SCM_T_INT16_MAX, 2);
 
-  VM_DEFINE_OP (121, bv_u32_set, "bv-u32-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (122, bv_u32_set, "bv-u32-set!", OP1 (U8_U8_U8_U8))
 #if SIZEOF_VOID_P > 4
     BV_FIXABLE_INT_SET (u32, u32_native, uint32, 0, SCM_T_UINT32_MAX, 4);
 #else
     BV_INT_SET (u32, uint32, 4);
 #endif
 
-  VM_DEFINE_OP (122, bv_s32_set, "bv-s32-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (123, bv_s32_set, "bv-s32-set!", OP1 (U8_U8_U8_U8))
 #if SIZEOF_VOID_P > 4
     BV_FIXABLE_INT_SET (s32, s32_native, int32, SCM_T_INT32_MIN, SCM_T_INT32_MAX, 4);
 #else
     BV_INT_SET (s32, int32, 4);
 #endif
 
-  VM_DEFINE_OP (123, bv_u64_set, "bv-u64-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (124, bv_u64_set, "bv-u64-set!", OP1 (U8_U8_U8_U8))
     BV_INT_SET (u64, uint64, 8);
 
-  VM_DEFINE_OP (124, bv_s64_set, "bv-s64-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (125, bv_s64_set, "bv-s64-set!", OP1 (U8_U8_U8_U8))
     BV_INT_SET (s64, int64, 8);
 
-  VM_DEFINE_OP (125, bv_f32_set, "bv-f32-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (126, bv_f32_set, "bv-f32-set!", OP1 (U8_U8_U8_U8))
     BV_FLOAT_SET (f32, ieee_single, float, 4);
 
-  VM_DEFINE_OP (126, bv_f64_set, "bv-f64-set!", OP1 (U8_U8_U8_U8))
+  VM_DEFINE_OP (127, bv_f64_set, "bv-f64-set!", OP1 (U8_U8_U8_U8))
     BV_FLOAT_SET (f64, ieee_double, double, 8);
 
-  END_DISPATCH_SWITCH;
+  /* br-if-logtest a:12 b:12 invert:1 _:7 offset:24
+   *
+   * If the exact integer in A has any bits in common with the exact
+   * integer in B, add OFFSET, a signed 24-bit number, to the current
+   * instruction pointer.
+   */
+  VM_DEFINE_OP (128, br_if_logtest, "br-if-logtest", OP2 (U8_U12_U12, B1_X7_L24))
+    {
+      BR_BINARY (x, y,
+                 ((SCM_I_INUMP (x) && SCM_I_INUMP (y))
+                  ? (SCM_UNPACK (x) & SCM_UNPACK (y) & ~scm_tc2_int)
+                  : scm_is_true (scm_logtest (x, y))));
+    }
+
+  /* FIXME: Move above */
+
+  /* allocate-struct dst:8 vtable:8 nfields:8
+   *
+   * Allocate a new struct with VTABLE, and place it in DST.  The struct
+   * will be constructed with space for NFIELDS fields, which should
+   * correspond to the field count of the VTABLE.
+   */
+  VM_DEFINE_OP (129, allocate_struct, "allocate-struct", OP1 (U8_U8_U8_U8) | OP_DST)
+    {
+      scm_t_uint8 dst, vtable, nfields;
+      SCM ret;
+
+      UNPACK_8_8_8 (op, dst, vtable, nfields);
+
+      SYNC_IP ();
+      ret = scm_allocate_struct (LOCAL_REF (vtable), LOCAL_REF (nfields));
+      LOCAL_SET (dst, ret);
+
+      NEXT (1);
+    }
 
- vm_error_bad_instruction:
-  vm_error_bad_instruction (op);
+  /* struct-ref dst:8 src:8 idx:8
+   *
+   * Fetch the item at slot IDX in the struct in SRC, and store it
+   * in DST.
+   */
+  VM_DEFINE_OP (130, struct_ref, "struct-ref", OP1 (U8_U8_U8_U8) | OP_DST)
+    {
+      scm_t_uint8 dst, src, idx;
+      SCM obj;
+      SCM index;
+
+      UNPACK_8_8_8 (op, dst, src, idx);
+
+      obj = LOCAL_REF (src);
+      index = LOCAL_REF (idx);
+
+      if (SCM_LIKELY (SCM_STRUCTP (obj)
+                      && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
+                                                        SCM_VTABLE_FLAG_SIMPLE)
+                      && SCM_I_INUMP (index)
+                      && SCM_I_INUM (index) >= 0
+                      && SCM_I_INUM (index) < (SCM_STRUCT_DATA_REF
+                                               (SCM_STRUCT_VTABLE (obj),
+                                                scm_vtable_index_size))))
+        RETURN (SCM_STRUCT_SLOT_REF (obj, SCM_I_INUM (index)));
 
-  abort (); /* never reached */
+      SYNC_IP ();
+      RETURN (scm_struct_ref (obj, index));
+    }
+
+  /* struct-set! dst:8 idx:8 src:8
+   *
+   * Store SRC into the struct DST at slot IDX.
+   */
+  VM_DEFINE_OP (131, struct_set, "struct-set!", OP1 (U8_U8_U8_U8))
+    {
+      scm_t_uint8 dst, idx, src;
+      SCM obj, val, index;
+
+      UNPACK_8_8_8 (op, dst, idx, src);
+
+      obj = LOCAL_REF (dst);
+      val = LOCAL_REF (src);
+      index = LOCAL_REF (idx);
+
+      if (SCM_LIKELY (SCM_STRUCTP (obj)
+                      && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
+                                                        SCM_VTABLE_FLAG_SIMPLE)
+                      && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
+                                                        SCM_VTABLE_FLAG_SIMPLE_RW)
+                      && SCM_I_INUMP (index)
+                      && SCM_I_INUM (index) >= 0
+                      && SCM_I_INUM (index) < (SCM_STRUCT_DATA_REF
+                                               (SCM_STRUCT_VTABLE (obj),
+                                                scm_vtable_index_size))))
+        {
+          SCM_STRUCT_SLOT_SET (obj, SCM_I_INUM (index), val);
+          NEXT (1);
+        }
+
+      SYNC_IP ();
+      scm_struct_set_x (obj, index, val);
+      NEXT (1);
+    }
+
+  VM_DEFINE_OP (132, unused_132, NULL, NOP)
+  VM_DEFINE_OP (133, unused_133, NULL, NOP)
+  VM_DEFINE_OP (134, unused_134, NULL, NOP)
+  VM_DEFINE_OP (135, unused_135, NULL, NOP)
+  VM_DEFINE_OP (136, unused_136, NULL, NOP)
+  VM_DEFINE_OP (137, unused_137, NULL, NOP)
+  VM_DEFINE_OP (138, unused_138, NULL, NOP)
+  VM_DEFINE_OP (139, unused_139, NULL, NOP)
+  VM_DEFINE_OP (140, unused_140, NULL, NOP)
+  VM_DEFINE_OP (141, unused_141, NULL, NOP)
+  VM_DEFINE_OP (142, unused_142, NULL, NOP)
+  VM_DEFINE_OP (143, unused_143, NULL, NOP)
+  VM_DEFINE_OP (144, unused_144, NULL, NOP)
+  VM_DEFINE_OP (145, unused_145, NULL, NOP)
+  VM_DEFINE_OP (146, unused_146, NULL, NOP)
+  VM_DEFINE_OP (147, unused_147, NULL, NOP)
+  VM_DEFINE_OP (148, unused_148, NULL, NOP)
+  VM_DEFINE_OP (149, unused_149, NULL, NOP)
+  VM_DEFINE_OP (150, unused_150, NULL, NOP)
+  VM_DEFINE_OP (151, unused_151, NULL, NOP)
+  VM_DEFINE_OP (152, unused_152, NULL, NOP)
+  VM_DEFINE_OP (153, unused_153, NULL, NOP)
+  VM_DEFINE_OP (154, unused_154, NULL, NOP)
+  VM_DEFINE_OP (155, unused_155, NULL, NOP)
+  VM_DEFINE_OP (156, unused_156, NULL, NOP)
+  VM_DEFINE_OP (157, unused_157, NULL, NOP)
+  VM_DEFINE_OP (158, unused_158, NULL, NOP)
+  VM_DEFINE_OP (159, unused_159, NULL, NOP)
+  VM_DEFINE_OP (160, unused_160, NULL, NOP)
+  VM_DEFINE_OP (161, unused_161, NULL, NOP)
+  VM_DEFINE_OP (162, unused_162, NULL, NOP)
+  VM_DEFINE_OP (163, unused_163, NULL, NOP)
+  VM_DEFINE_OP (164, unused_164, NULL, NOP)
+  VM_DEFINE_OP (165, unused_165, NULL, NOP)
+  VM_DEFINE_OP (166, unused_166, NULL, NOP)
+  VM_DEFINE_OP (167, unused_167, NULL, NOP)
+  VM_DEFINE_OP (168, unused_168, NULL, NOP)
+  VM_DEFINE_OP (169, unused_169, NULL, NOP)
+  VM_DEFINE_OP (170, unused_170, NULL, NOP)
+  VM_DEFINE_OP (171, unused_171, NULL, NOP)
+  VM_DEFINE_OP (172, unused_172, NULL, NOP)
+  VM_DEFINE_OP (173, unused_173, NULL, NOP)
+  VM_DEFINE_OP (174, unused_174, NULL, NOP)
+  VM_DEFINE_OP (175, unused_175, NULL, NOP)
+  VM_DEFINE_OP (176, unused_176, NULL, NOP)
+  VM_DEFINE_OP (177, unused_177, NULL, NOP)
+  VM_DEFINE_OP (178, unused_178, NULL, NOP)
+  VM_DEFINE_OP (179, unused_179, NULL, NOP)
+  VM_DEFINE_OP (180, unused_180, NULL, NOP)
+  VM_DEFINE_OP (181, unused_181, NULL, NOP)
+  VM_DEFINE_OP (182, unused_182, NULL, NOP)
+  VM_DEFINE_OP (183, unused_183, NULL, NOP)
+  VM_DEFINE_OP (184, unused_184, NULL, NOP)
+  VM_DEFINE_OP (185, unused_185, NULL, NOP)
+  VM_DEFINE_OP (186, unused_186, NULL, NOP)
+  VM_DEFINE_OP (187, unused_187, NULL, NOP)
+  VM_DEFINE_OP (188, unused_188, NULL, NOP)
+  VM_DEFINE_OP (189, unused_189, NULL, NOP)
+  VM_DEFINE_OP (190, unused_190, NULL, NOP)
+  VM_DEFINE_OP (191, unused_191, NULL, NOP)
+  VM_DEFINE_OP (192, unused_192, NULL, NOP)
+  VM_DEFINE_OP (193, unused_193, NULL, NOP)
+  VM_DEFINE_OP (194, unused_194, NULL, NOP)
+  VM_DEFINE_OP (195, unused_195, NULL, NOP)
+  VM_DEFINE_OP (196, unused_196, NULL, NOP)
+  VM_DEFINE_OP (197, unused_197, NULL, NOP)
+  VM_DEFINE_OP (198, unused_198, NULL, NOP)
+  VM_DEFINE_OP (199, unused_199, NULL, NOP)
+  VM_DEFINE_OP (200, unused_200, NULL, NOP)
+  VM_DEFINE_OP (201, unused_201, NULL, NOP)
+  VM_DEFINE_OP (202, unused_202, NULL, NOP)
+  VM_DEFINE_OP (203, unused_203, NULL, NOP)
+  VM_DEFINE_OP (204, unused_204, NULL, NOP)
+  VM_DEFINE_OP (205, unused_205, NULL, NOP)
+  VM_DEFINE_OP (206, unused_206, NULL, NOP)
+  VM_DEFINE_OP (207, unused_207, NULL, NOP)
+  VM_DEFINE_OP (208, unused_208, NULL, NOP)
+  VM_DEFINE_OP (209, unused_209, NULL, NOP)
+  VM_DEFINE_OP (210, unused_210, NULL, NOP)
+  VM_DEFINE_OP (211, unused_211, NULL, NOP)
+  VM_DEFINE_OP (212, unused_212, NULL, NOP)
+  VM_DEFINE_OP (213, unused_213, NULL, NOP)
+  VM_DEFINE_OP (214, unused_214, NULL, NOP)
+  VM_DEFINE_OP (215, unused_215, NULL, NOP)
+  VM_DEFINE_OP (216, unused_216, NULL, NOP)
+  VM_DEFINE_OP (217, unused_217, NULL, NOP)
+  VM_DEFINE_OP (218, unused_218, NULL, NOP)
+  VM_DEFINE_OP (219, unused_219, NULL, NOP)
+  VM_DEFINE_OP (220, unused_220, NULL, NOP)
+  VM_DEFINE_OP (221, unused_221, NULL, NOP)
+  VM_DEFINE_OP (222, unused_222, NULL, NOP)
+  VM_DEFINE_OP (223, unused_223, NULL, NOP)
+  VM_DEFINE_OP (224, unused_224, NULL, NOP)
+  VM_DEFINE_OP (225, unused_225, NULL, NOP)
+  VM_DEFINE_OP (226, unused_226, NULL, NOP)
+  VM_DEFINE_OP (227, unused_227, NULL, NOP)
+  VM_DEFINE_OP (228, unused_228, NULL, NOP)
+  VM_DEFINE_OP (229, unused_229, NULL, NOP)
+  VM_DEFINE_OP (230, unused_230, NULL, NOP)
+  VM_DEFINE_OP (231, unused_231, NULL, NOP)
+  VM_DEFINE_OP (232, unused_232, NULL, NOP)
+  VM_DEFINE_OP (233, unused_233, NULL, NOP)
+  VM_DEFINE_OP (234, unused_234, NULL, NOP)
+  VM_DEFINE_OP (235, unused_235, NULL, NOP)
+  VM_DEFINE_OP (236, unused_236, NULL, NOP)
+  VM_DEFINE_OP (237, unused_237, NULL, NOP)
+  VM_DEFINE_OP (238, unused_238, NULL, NOP)
+  VM_DEFINE_OP (239, unused_239, NULL, NOP)
+  VM_DEFINE_OP (240, unused_240, NULL, NOP)
+  VM_DEFINE_OP (241, unused_241, NULL, NOP)
+  VM_DEFINE_OP (242, unused_242, NULL, NOP)
+  VM_DEFINE_OP (243, unused_243, NULL, NOP)
+  VM_DEFINE_OP (244, unused_244, NULL, NOP)
+  VM_DEFINE_OP (245, unused_245, NULL, NOP)
+  VM_DEFINE_OP (246, unused_246, NULL, NOP)
+  VM_DEFINE_OP (247, unused_247, NULL, NOP)
+  VM_DEFINE_OP (248, unused_248, NULL, NOP)
+  VM_DEFINE_OP (249, unused_249, NULL, NOP)
+  VM_DEFINE_OP (250, unused_250, NULL, NOP)
+  VM_DEFINE_OP (251, unused_251, NULL, NOP)
+  VM_DEFINE_OP (252, unused_252, NULL, NOP)
+  VM_DEFINE_OP (253, unused_253, NULL, NOP)
+  VM_DEFINE_OP (254, unused_254, NULL, NOP)
+  VM_DEFINE_OP (255, unused_255, NULL, NOP)
+    {
+      vm_error_bad_instruction (op);
+      abort (); /* never reached */
+    }
+
+  END_DISPATCH_SWITCH;
 }
 
 
@@ -3144,7 +3347,6 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 #undef BV_INT_REF
 #undef BV_INT_SET
 #undef CACHE_REGISTER
-#undef CHECK_OVERFLOW
 #undef END_DISPATCH_SWITCH
 #undef FREE_VARIABLE_REF
 #undef INIT
@@ -3157,17 +3359,13 @@ VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
 #undef NEXT_JUMP
 #undef POP_CONTINUATION_HOOK
 #undef PUSH_CONTINUATION_HOOK
-#undef RESTORE_CONTINUATION_HOOK
 #undef RETURN
 #undef RETURN_ONE_VALUE
 #undef RETURN_VALUE_LIST
 #undef RUN_HOOK
 #undef RUN_HOOK0
 #undef RUN_HOOK1
-#undef SYNC_ALL
-#undef SYNC_BEFORE_GC
 #undef SYNC_IP
-#undef SYNC_REGISTER
 #undef UNPACK_8_8_8
 #undef UNPACK_8_16
 #undef UNPACK_16_8