Optimize 'string-hash'.
[bpt/guile.git] / libguile / vm-i-system.c
index 1e3c2e5..5057fb0 100644 (file)
@@ -1,6 +1,5 @@
-/* Copyright (C) 2001, 2008, 2009, 2010, 2011,
- *   2012 Free Software Foundation, Inc.
- *
+/* Copyright (C) 2001,2008,2009,2010,2011,2012,2013 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
  * as published by the Free Software Foundation; either version 3 of
 
 /* This file is included in vm_engine.c */
 
-/* Compiler barrier, to prevent instruction reordering, apparently due
-   to a bug in GCC 4.3.2 on sparc-linux-gnu and on hppa2.0-linux-gnu.
-   See <http://bugs.gnu.org/10520>, for details.  */
-
-#ifdef __GNUC__
-# define COMPILER_BARRIER  __asm__ __volatile__ ("")
-#else
-# define COMPILER_BARRIER  do { } while (0)
-#endif
-
-
 \f
 /*
  * Basic operations
@@ -43,16 +31,23 @@ VM_DEFINE_INSTRUCTION (0, nop, "nop", 0, 0, 0)
 
 VM_DEFINE_INSTRUCTION (1, halt, "halt", 0, 0, 0)
 {
-  nvalues = SCM_I_INUM (*sp--);
+  SCM ret;
+  SCM nvalues_scm;
+
+  nvalues_scm = *sp--;  /* SCM_I_INUM may evaluate its argument
+                           more than once. */
+  nvalues = SCM_I_INUM (nvalues_scm);
   NULLSTACK (1);
+
   if (nvalues == 1)
-    POP (finish_args);
+    POP (ret);
   else
     {
-      POP_LIST (nvalues);
-      POP (finish_args);
       SYNC_REGISTER ();
-      finish_args = scm_values (finish_args);
+      sp -= nvalues;
+      CHECK_UNDERFLOW ();
+      ret = scm_c_values (sp + 1, nvalues);
+      NULLSTACK (nvalues);
     }
     
   {
@@ -67,11 +62,11 @@ VM_DEFINE_INSTRUCTION (1, halt, "halt", 0, 0, 0)
        stack */
     ip = SCM_FRAME_RETURN_ADDRESS (fp);
     fp = SCM_FRAME_DYNAMIC_LINK (fp);
-    COMPILER_BARRIER;
     NULLSTACK (old_sp - sp);
   }
   
-  goto vm_done;
+  SYNC_ALL ();
+  return ret;
 }
 
 VM_DEFINE_INSTRUCTION (2, drop, "drop", 0, 1, 0)
@@ -84,7 +79,6 @@ VM_DEFINE_INSTRUCTION (3, dup, "dup", 0, 0, 1)
 {
   SCM x = *sp;
   PUSH (x);
-  DEAD (x);
   NEXT;
 }
 
@@ -227,7 +221,6 @@ VM_DEFINE_INSTRUCTION (18, vector, "vector", 2, -1, 1)
   memcpy (SCM_I_VECTOR_WELTS(vect), sp, sizeof(SCM) * len);
   NULLSTACK (len);
   *sp = vect;
-  DEAD (vect);
 
   NEXT;
 }
@@ -313,26 +306,22 @@ VM_DEFINE_INSTRUCTION (25, variable_ref, "variable-ref", 0, 1, 1)
      unlike in top-variable-ref, it really isn't an internal assertion
      that can be optimized out -- the variable could be coming directly
      from the user.  */
-  if (SCM_UNLIKELY (!SCM_VARIABLEP (x)))
-    {
-      func_name = "variable-ref";
-      finish_args = x;
-      goto vm_error_not_a_variable;
-    }
-  else if (SCM_UNLIKELY (!VARIABLE_BOUNDP (x)))
+  VM_ASSERT (SCM_VARIABLEP (x),
+             vm_error_not_a_variable ("variable-ref", x));
+
+  if (SCM_UNLIKELY (!VARIABLE_BOUNDP (x)))
     {
       SCM var_name;
 
+      SYNC_ALL ();
       /* Attempt to provide the variable name in the error message.  */
       var_name = scm_module_reverse_lookup (scm_current_module (), x);
-      finish_args = scm_is_true (var_name) ? var_name : x;
-      goto vm_error_unbound;
+      vm_error_unbound (program, scm_is_true (var_name) ? var_name : x);
     }
   else
     {
       SCM o = VARIABLE_REF (x);
       *sp = o;
-      DEAD (o);
     }
 
   NEXT;
@@ -342,48 +331,36 @@ VM_DEFINE_INSTRUCTION (26, variable_bound, "variable-bound?", 0, 1, 1)
 {
   SCM x = *sp;
   
-  if (SCM_UNLIKELY (!SCM_VARIABLEP (x)))
-    {
-      func_name = "variable-bound?";
-      finish_args = x;
-      goto vm_error_not_a_variable;
-    }
-  else
-    *sp = scm_from_bool (VARIABLE_BOUNDP (x));
-  DEAD (x);
+  VM_ASSERT (SCM_VARIABLEP (x),
+             vm_error_not_a_variable ("variable-bound?", x));
+
+  *sp = scm_from_bool (VARIABLE_BOUNDP (x));
   NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (27, toplevel_ref, "toplevel-ref", 1, 0, 1)
 {
   unsigned objnum = FETCH ();
-  SCM what;
+  SCM what, resolved;
   CHECK_OBJECT (objnum);
   what = OBJECT_REF (objnum);
 
   if (!SCM_VARIABLEP (what))
     {
-      SCM resolved;
       SYNC_REGISTER ();
       resolved = resolve_variable (what, scm_program_module (program));
-      if (!VARIABLE_BOUNDP (resolved))
-        {
-          finish_args = what;
-          goto vm_error_unbound;
-        }
+      VM_ASSERT (VARIABLE_BOUNDP (resolved), vm_error_unbound (program, what));
       what = resolved;
-      DEAD (resolved);
       OBJECT_SET (objnum, what);
     }
 
   PUSH (VARIABLE_REF (what));
-  DEAD (what);
   NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (28, long_toplevel_ref, "long-toplevel-ref", 2, 0, 1)
 {
-  SCM what;
+  SCM what, resolved;
   unsigned int objnum = FETCH ();
   objnum <<= 8;
   objnum += FETCH ();
@@ -392,21 +369,15 @@ VM_DEFINE_INSTRUCTION (28, long_toplevel_ref, "long-toplevel-ref", 2, 0, 1)
 
   if (!SCM_VARIABLEP (what))
     {
-      SCM resolved;
       SYNC_REGISTER ();
       resolved = resolve_variable (what, scm_program_module (program));
-      if (!VARIABLE_BOUNDP (resolved))
-        {
-          finish_args = what;
-          goto vm_error_unbound;
-        }
+      VM_ASSERT (VARIABLE_BOUNDP (resolved),
+                 vm_error_unbound (program, what));
       what = resolved;
-      DEAD (resolved);
       OBJECT_SET (objnum, what);
     }
 
   PUSH (VARIABLE_REF (what));
-  DEAD (what);
   NEXT;
 }
 
@@ -417,7 +388,6 @@ VM_DEFINE_INSTRUCTION (29, local_set, "local-set", 1, 1, 0)
   SCM x;
   POP (x);
   LOCAL_SET (FETCH (), x);
-  DEAD (x);
   NEXT;
 }
 
@@ -429,18 +399,13 @@ VM_DEFINE_INSTRUCTION (30, long_local_set, "long-local-set", 2, 1, 0)
   i += FETCH ();
   POP (x);
   LOCAL_SET (i, x);
-  DEAD (x);
   NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (31, variable_set, "variable-set", 0, 2, 0)
 {
-  if (SCM_UNLIKELY (!SCM_VARIABLEP (sp[0])))
-    {
-      func_name = "variable-set!";
-      finish_args = sp[0];
-      goto vm_error_not_a_variable;
-    }
+  VM_ASSERT (SCM_VARIABLEP (sp[0]),
+             vm_error_not_a_variable ("variable-set!", sp[0]));
   VARIABLE_SET (sp[0], sp[-1]);
   DROPN (2);
   NEXT;
@@ -461,7 +426,6 @@ VM_DEFINE_INSTRUCTION (32, toplevel_set, "toplevel-set", 1, 1, 0)
     }
 
   VARIABLE_SET (what, *sp);
-  DEAD (what);
   DROP ();
   NEXT;
 }
@@ -483,7 +447,6 @@ VM_DEFINE_INSTRUCTION (33, long_toplevel_set, "long-toplevel-set", 2, 1, 0)
     }
 
   VARIABLE_SET (what, *sp);
-  DEAD (what);
   DROP ();
   NEXT;
 }
@@ -510,6 +473,7 @@ VM_DEFINE_INSTRUCTION (33, long_toplevel_set, "long-toplevel-set", 2, 1, 0)
     ip += offset;                               \
   if (offset < 0)                               \
     VM_HANDLE_INTERRUPTS;                       \
+  NEXT;                                                \
 }
 
 VM_DEFINE_INSTRUCTION (34, br, "br", 3, 0, 0)
@@ -527,8 +491,6 @@ VM_DEFINE_INSTRUCTION (35, br_if, "br-if", 3, 0, 0)
   SCM x;
   POP (x);
   BR (scm_is_true (x));
-  DEAD (x);
-  NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (36, br_if_not, "br-if-not", 3, 0, 0)
@@ -536,8 +498,6 @@ VM_DEFINE_INSTRUCTION (36, br_if_not, "br-if-not", 3, 0, 0)
   SCM x;
   POP (x);
   BR (scm_is_false (x));
-  DEAD (x);
-  NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (37, br_if_eq, "br-if-eq", 3, 0, 0)
@@ -545,9 +505,6 @@ VM_DEFINE_INSTRUCTION (37, br_if_eq, "br-if-eq", 3, 0, 0)
   SCM x, y;
   POP2 (y, x);
   BR (scm_is_eq (x, y));
-  DEAD (x);
-  DEAD (y);
-  NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (38, br_if_not_eq, "br-if-not-eq", 3, 0, 0)
@@ -555,9 +512,6 @@ VM_DEFINE_INSTRUCTION (38, br_if_not_eq, "br-if-not-eq", 3, 0, 0)
   SCM x, y;
   POP2 (y, x);
   BR (!scm_is_eq (x, y));
-  DEAD (x);
-  DEAD (y);
-  NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (39, br_if_null, "br-if-null", 3, 0, 0)
@@ -565,8 +519,6 @@ VM_DEFINE_INSTRUCTION (39, br_if_null, "br-if-null", 3, 0, 0)
   SCM x;
   POP (x);
   BR (scm_is_null (x));
-  DEAD (x);
-  NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (40, br_if_not_null, "br-if-not-null", 3, 0, 0)
@@ -574,8 +526,6 @@ VM_DEFINE_INSTRUCTION (40, br_if_not_null, "br-if-not-null", 3, 0, 0)
   SCM x;
   POP (x);
   BR (!scm_is_null (x));
-  DEAD (x);
-  NEXT;
 }
 
 \f
@@ -625,8 +575,8 @@ VM_DEFINE_INSTRUCTION (44, assert_nargs_ee, "assert-nargs-ee", 2, 0, 0)
   scm_t_ptrdiff n;
   n = FETCH () << 8;
   n += FETCH ();
-  if (sp - (fp - 1) != n)
-    goto vm_error_wrong_num_args;
+  VM_ASSERT (sp - (fp - 1) == n,
+             vm_error_wrong_num_args (program));
   NEXT;
 }
 
@@ -635,8 +585,8 @@ VM_DEFINE_INSTRUCTION (45, assert_nargs_ge, "assert-nargs-ge", 2, 0, 0)
   scm_t_ptrdiff n;
   n = FETCH () << 8;
   n += FETCH ();
-  if (sp - (fp - 1) < n)
-    goto vm_error_wrong_num_args;
+  VM_ASSERT (sp - (fp - 1) >= n,
+             vm_error_wrong_num_args (program));
   NEXT;
 }
 
@@ -687,6 +637,8 @@ VM_DEFINE_INSTRUCTION (47, bind_optionals_shuffle, "bind-optionals/shuffle", 6,
   NEXT;
 }
 
+/* See also bind-optionals/shuffle-or-br below.  */
+
 /* Flags that determine whether other keywords are allowed, and whether a
    rest argument is expected.  These values must match those used by the
    glil->assembly compiler.  */
@@ -706,9 +658,9 @@ VM_DEFINE_INSTRUCTION (48, bind_kwargs, "bind-kwargs", 5, 0, 0)
   nkw += FETCH ();
   kw_and_rest_flags = FETCH ();
 
-  if (!(kw_and_rest_flags & F_REST)
-      && ((sp - (fp - 1) - nkw) % 2))
-    goto vm_error_kwargs_length_not_even;
+  VM_ASSERT ((kw_and_rest_flags & F_REST)
+             || ((sp - (fp - 1) - nkw) % 2) == 0,
+             vm_error_kwargs_length_not_even (program))
 
   CHECK_OBJECT (idx);
   kw = OBJECT_REF (idx);
@@ -730,17 +682,16 @@ VM_DEFINE_INSTRUCTION (48, bind_kwargs, "bind-kwargs", 5, 0, 0)
                  break;
                }
            }
-         if (!(kw_and_rest_flags & F_ALLOW_OTHER_KEYS) && !scm_is_pair (walk))
-           goto vm_error_kwargs_unrecognized_keyword;
-
+          VM_ASSERT (scm_is_pair (walk)
+                     || (kw_and_rest_flags & F_ALLOW_OTHER_KEYS),
+                     vm_error_kwargs_unrecognized_keyword (program, sp[nkw]));
          nkw++;
        }
-      else if (!(kw_and_rest_flags & F_REST))
-        goto vm_error_kwargs_invalid_keyword;
+      else
+        VM_ASSERT (kw_and_rest_flags & F_REST,
+                   vm_error_kwargs_invalid_keyword (program, sp[nkw]));
     }
 
-  DEAD (kw);
-
   NEXT;
 }
 
@@ -758,7 +709,6 @@ VM_DEFINE_INSTRUCTION (49, push_rest, "push-rest", 2, -1, -1)
     /* No need to check for underflow. */
     CONS (rest, *sp--, rest);
   PUSH (rest);
-  DEAD (rest);
   NEXT;
 }
 
@@ -775,7 +725,6 @@ VM_DEFINE_INSTRUCTION (50, bind_rest, "bind-rest", 4, -1, -1)
     /* No need to check for underflow. */
     CONS (rest, *sp--, rest);
   LOCAL_SET (i, rest);
-  DEAD (rest);
   NEXT;
 }
 
@@ -820,30 +769,8 @@ VM_DEFINE_INSTRUCTION (53, call, "call", 1, -1, 1)
   nargs = FETCH ();
 
  vm_call:
-  program = sp[-nargs];
-
   VM_HANDLE_INTERRUPTS;
 
-  if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
-    {
-      if (SCM_STRUCTP (program) && SCM_STRUCT_APPLICABLE_P (program))
-        {
-          sp[-nargs] = SCM_STRUCT_PROCEDURE (program);
-          goto vm_call;
-        }
-      else if (SCM_NIMP (program) && SCM_TYP7 (program) == scm_tc7_smob
-               && SCM_SMOB_APPLICABLE_P (program))
-        {
-          SYNC_REGISTER ();
-          sp[-nargs] = scm_i_smob_apply_trampoline (program);
-          goto vm_call;
-        }
-      else
-        goto vm_error_wrong_type_apply;
-    }
-
-  CACHE_PROGRAM ();
-
   {
     SCM *old_fp = fp;
 
@@ -857,8 +784,16 @@ VM_DEFINE_INSTRUCTION (53, call, "call", 1, -1, 1)
     SCM_FRAME_SET_MV_RETURN_ADDRESS (fp, 0);
   }
   
-  ip = SCM_C_OBJCODE_BASE (bp);
   PUSH_CONTINUATION_HOOK ();
+
+  program = fp[-1];
+
+  if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
+    goto apply;
+
+  CACHE_PROGRAM ();
+  ip = SCM_C_OBJCODE_BASE (bp);
+
   APPLY_HOOK ();
   NEXT;
 }
@@ -868,50 +803,34 @@ VM_DEFINE_INSTRUCTION (54, tail_call, "tail-call", 1, -1, 1)
   nargs = FETCH ();
 
  vm_tail_call:
-  program = sp[-nargs];
-
   VM_HANDLE_INTERRUPTS;
 
-  if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
-    {
-      if (SCM_STRUCTP (program) && SCM_STRUCT_APPLICABLE_P (program))
-        {
-          sp[-nargs] = SCM_STRUCT_PROCEDURE (program);
-          goto vm_tail_call;
-        }
-      else if (SCM_NIMP (program) && SCM_TYP7 (program) == scm_tc7_smob
-               && SCM_SMOB_APPLICABLE_P (program))
-        {
-          SYNC_REGISTER ();
-          sp[-nargs] = scm_i_smob_apply_trampoline (program);
-          goto vm_tail_call;
-        }
-      else
-        goto vm_error_wrong_type_apply;
-    }
-  else
-    {
-      int i;
+  {
+    int i;
 #ifdef VM_ENABLE_STACK_NULLING
-      SCM *old_sp = sp;
-      CHECK_STACK_LEAK ();
+    SCM *old_sp = sp;
+    CHECK_STACK_LEAK ();
 #endif
 
-      /* switch programs */
-      CACHE_PROGRAM ();
-      /* shuffle down the program and the arguments */
-      for (i = -1, sp = sp - nargs + 1; i < nargs; i++)
-        SCM_FRAME_STACK_ADDRESS (fp)[i] = sp[i];
+    /* shuffle down the program and the arguments */
+    for (i = -1, sp = sp - nargs + 1; i < nargs; i++)
+      SCM_FRAME_STACK_ADDRESS (fp)[i] = sp[i];
 
-      sp = fp + i - 1;
+    sp = fp + i - 1;
 
-      NULLSTACK (old_sp - sp);
+    NULLSTACK (old_sp - sp);
+  }
 
-      ip = SCM_C_OBJCODE_BASE (bp);
+  program = fp[-1];
 
-      APPLY_HOOK ();
-      NEXT;
-    }
+  if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
+    goto apply;
+
+  CACHE_PROGRAM ();
+  ip = SCM_C_OBJCODE_BASE (bp);
+
+  APPLY_HOOK ();
+  NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (55, subr_call, "subr-call", 1, -1, -1)
@@ -966,7 +885,6 @@ VM_DEFINE_INSTRUCTION (55, subr_call, "subr-call", 1, -1, -1)
       abort ();
     }
   
-  DEAD (pointer);
   NULLSTACK_FOR_NONLOCAL_EXIT ();
       
   if (SCM_UNLIKELY (SCM_VALUESP (ret)))
@@ -975,13 +893,11 @@ VM_DEFINE_INSTRUCTION (55, subr_call, "subr-call", 1, -1, -1)
       ret = scm_struct_ref (ret, SCM_INUM0);
       nvalues = scm_ilength (ret);
       PUSH_LIST (ret, scm_is_null);
-      DEAD (ret);
       goto vm_return_values;
     }
   else
     {
       PUSH (ret);
-      DEAD (ret);
       goto vm_return;
     }
 }
@@ -1016,7 +932,6 @@ VM_DEFINE_INSTRUCTION (56, smob_call, "smob-call", 1, -1, -1)
       abort ();
     }
   
-  DEAD (smob);
   NULLSTACK_FOR_NONLOCAL_EXIT ();
       
   if (SCM_UNLIKELY (SCM_VALUESP (ret)))
@@ -1025,13 +940,11 @@ VM_DEFINE_INSTRUCTION (56, smob_call, "smob-call", 1, -1, -1)
       ret = scm_struct_ref (ret, SCM_INUM0);
       nvalues = scm_ilength (ret);
       PUSH_LIST (ret, scm_is_null);
-      DEAD (ret);
       goto vm_return_values;
     }
   else
     {
       PUSH (ret);
-      DEAD (ret);
       goto vm_return;
     }
 }
@@ -1047,7 +960,6 @@ VM_DEFINE_INSTRUCTION (57, foreign_call, "foreign-call", 1, -1, -1)
 
   ret = scm_i_foreign_call (foreign, sp - nargs + 1);
 
-  DEAD (foreign);
   NULLSTACK_FOR_NONLOCAL_EXIT ();
       
   if (SCM_UNLIKELY (SCM_VALUESP (ret)))
@@ -1056,13 +968,11 @@ VM_DEFINE_INSTRUCTION (57, foreign_call, "foreign-call", 1, -1, -1)
       ret = scm_struct_ref (ret, SCM_INUM0);
       nvalues = scm_ilength (ret);
       PUSH_LIST (ret, scm_is_null);
-      DEAD (ret);
       goto vm_return_values;
     }
   else
     {
       PUSH (ret);
-      DEAD (ret);
       goto vm_return;
     }
 }
@@ -1079,7 +989,7 @@ VM_DEFINE_INSTRUCTION (58, continuation_call, "continuation-call", 0, -1, 0)
                              sp - (fp - 1), fp);
   scm_i_reinstate_continuation (contregs);
 
-  /* no DEAD, no NEXT */
+  /* no NEXT */
   abort ();
 }
 
@@ -1088,16 +998,11 @@ VM_DEFINE_INSTRUCTION (59, partial_cont_call, "partial-cont-call", 0, -1, 0)
   SCM vmcont, intwinds, prevwinds;
   POP2 (intwinds, vmcont);
   SYNC_REGISTER ();
-  if (SCM_UNLIKELY (!SCM_VM_CONT_REWINDABLE_P (vmcont)))
-    {
-      finish_args = vmcont;
-      goto vm_error_continuation_not_rewindable;
-    }
+  VM_ASSERT (SCM_VM_CONT_REWINDABLE_P (vmcont),
+             vm_error_continuation_not_rewindable (vmcont));
   prevwinds = scm_i_dynwinds ();
   vm_reinstate_partial_continuation (vm, vmcont, intwinds, sp + 1 - fp, fp,
                                      vm_cookie);
-  DEAD (vmcont);
-  DEAD (intwinds);
 
   /* Rewind prompt jmpbuffers, if any. */
   {
@@ -1105,9 +1010,7 @@ VM_DEFINE_INSTRUCTION (59, partial_cont_call, "partial-cont-call", 0, -1, 0)
     for (; !scm_is_eq (winds, prevwinds); winds = scm_cdr (winds))
       if (SCM_PROMPT_P (scm_car (winds)) && SCM_PROMPT_SETJMP (scm_car (winds)))
         break;
-    DEAD (winds);
   }
-  DEAD (prevwinds);
     
   CACHE_REGISTER ();
   program = SCM_FRAME_PROGRAM (fp);
@@ -1120,7 +1023,6 @@ VM_DEFINE_INSTRUCTION (60, tail_call_nargs, "tail-call/nargs", 0, 0, 1)
   SCM x;
   POP (x);
   nargs = scm_to_int (x);
-  DEAD (x);
   /* FIXME: should truncate values? */
   goto vm_tail_call;
 }
@@ -1130,7 +1032,6 @@ VM_DEFINE_INSTRUCTION (61, call_nargs, "call/nargs", 0, 0, 1)
   SCM x;
   POP (x);
   nargs = scm_to_int (x);
-  DEAD (x);
   /* FIXME: should truncate values? */
   goto vm_call;
 }
@@ -1139,51 +1040,33 @@ VM_DEFINE_INSTRUCTION (62, mv_call, "mv-call", 4, -1, 1)
 {
   scm_t_int32 offset;
   scm_t_uint8 *mvra;
+  SCM *old_fp = fp;
   
   nargs = FETCH ();
   FETCH_OFFSET (offset);
   mvra = ip + offset;
 
- vm_mv_call:
-  program = sp[-nargs];
-
   VM_HANDLE_INTERRUPTS;
 
-  if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
-    {
-      if (SCM_STRUCTP (program) && SCM_STRUCT_APPLICABLE_P (program))
-        {
-          sp[-nargs] = SCM_STRUCT_PROCEDURE (program);
-          goto vm_mv_call;
-        }
-      else if (SCM_NIMP (program) && SCM_TYP7 (program) == scm_tc7_smob
-               && SCM_SMOB_APPLICABLE_P (program))
-        {
-          SYNC_REGISTER ();
-          sp[-nargs] = scm_i_smob_apply_trampoline (program);
-          goto vm_mv_call;
-        }
-      else
-        goto vm_error_wrong_type_apply;
-    }
+  fp = sp - nargs + 1;
+  
+  ASSERT (SCM_FRAME_DYNAMIC_LINK (fp) == 0);
+  ASSERT (SCM_FRAME_RETURN_ADDRESS (fp) == 0);
+  ASSERT (SCM_FRAME_MV_RETURN_ADDRESS (fp) == 0);
+  SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp);
+  SCM_FRAME_SET_RETURN_ADDRESS (fp, ip);
+  SCM_FRAME_SET_MV_RETURN_ADDRESS (fp, mvra);
+  
+  PUSH_CONTINUATION_HOOK ();
 
-  CACHE_PROGRAM ();
+  program = fp[-1];
 
-  {
-    SCM *old_fp = fp;
+  if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
+    goto apply;
 
-    fp = sp - nargs + 1;
-  
-    ASSERT (SCM_FRAME_DYNAMIC_LINK (fp) == 0);
-    ASSERT (SCM_FRAME_RETURN_ADDRESS (fp) == 0);
-    ASSERT (SCM_FRAME_MV_RETURN_ADDRESS (fp) == 0);
-    SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp);
-    SCM_FRAME_SET_RETURN_ADDRESS (fp, ip);
-    SCM_FRAME_SET_MV_RETURN_ADDRESS (fp, mvra);
-  }
-  
+  CACHE_PROGRAM ();
   ip = SCM_C_OBJCODE_BASE (bp);
-  PUSH_CONTINUATION_HOOK ();
+
   APPLY_HOOK ();
   NEXT;
 }
@@ -1198,14 +1081,9 @@ VM_DEFINE_INSTRUCTION (63, apply, "apply", 1, -1, 1)
   ASSERT (nargs >= 2);
 
   len = scm_ilength (ls);
-  if (SCM_UNLIKELY (len < 0))
-    {
-      finish_args = ls;
-      goto vm_error_apply_to_non_list;
-    }
-
+  VM_ASSERT (len >= 0,
+             vm_error_apply_to_non_list (ls));
   PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
-  DEAD (ls);
 
   nargs += len - 2;
   goto vm_call;
@@ -1221,14 +1099,9 @@ VM_DEFINE_INSTRUCTION (64, tail_apply, "tail-apply", 1, -1, 1)
   ASSERT (nargs >= 2);
 
   len = scm_ilength (ls);
-  if (SCM_UNLIKELY (len < 0))
-    {
-      finish_args = ls;
-      goto vm_error_apply_to_non_list;
-    }
-
+  VM_ASSERT (len >= 0,
+             vm_error_apply_to_non_list (ls));
   PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
-  DEAD (ls);
 
   nargs += len - 2;
   goto vm_tail_call;
@@ -1242,16 +1115,13 @@ VM_DEFINE_INSTRUCTION (65, call_cc, "call/cc", 0, 1, 1)
   SYNC_ALL ();
   vm_cont = scm_i_vm_capture_stack (vp->stack_base, fp, sp, ip, NULL, 0);
   cont = scm_i_make_continuation (&first, vm, vm_cont);
-  DEAD (vm_cont);
   if (first) 
     {
       PUSH (SCM_PACK (0)); /* dynamic link */
       PUSH (SCM_PACK (0));  /* mvra */
       PUSH (SCM_PACK (0));  /* ra */
       PUSH (proc);
-      DEAD (proc);
       PUSH (cont);
-      DEAD (cont);
       nargs = 1;
       goto vm_call;
     }
@@ -1264,8 +1134,6 @@ VM_DEFINE_INSTRUCTION (65, call_cc, "call/cc", 0, 1, 1)
 
          So, pull our regs back down from the vp, and march on to the
          next instruction. */
-      DEAD (proc);
-      DEAD (cont);
       CACHE_REGISTER ();
       program = SCM_FRAME_PROGRAM (fp);
       CACHE_PROGRAM ();
@@ -1289,20 +1157,15 @@ VM_DEFINE_INSTRUCTION (66, tail_call_cc, "tail-call/cc", 0, 1, 1)
                                     SCM_FRAME_MV_RETURN_ADDRESS (fp),
                                     0);
   cont = scm_i_make_continuation (&first, vm, vm_cont);
-  DEAD (vm_cont);
   if (first) 
     {
       PUSH (proc);
-      DEAD (proc);
       PUSH (cont);
-      DEAD (cont);
       nargs = 1;
       goto vm_tail_call;
     }
   else
     {
-      DEAD (proc);
-      DEAD (cont);
       /* Otherwise, cache regs and NEXT, as above. Invoking the continuation
          does a return from the frame, either to the RA or
          MVRA. */
@@ -1339,7 +1202,6 @@ VM_DEFINE_INSTRUCTION (67, return, "return", 0, 1, 1)
     sp = SCM_FRAME_LOWER_ADDRESS (fp);
     ip = SCM_FRAME_RETURN_ADDRESS (fp);
     fp = SCM_FRAME_DYNAMIC_LINK (fp);
-    COMPILER_BARRIER;
 
 #ifdef VM_ENABLE_STACK_NULLING
     NULLSTACK (old_sp - sp);
@@ -1347,8 +1209,6 @@ VM_DEFINE_INSTRUCTION (67, return, "return", 0, 1, 1)
 
     /* Set return value (sp is already pushed) */
     *sp = ret;
-
-    DEAD (ret);
   }
 
   /* Restore the last program */
@@ -1377,8 +1237,7 @@ VM_DEFINE_INSTRUCTION (68, return_values, "return/values", 1, -1, -1)
       sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
       ip = SCM_FRAME_MV_RETURN_ADDRESS (fp);
       fp = SCM_FRAME_DYNAMIC_LINK (fp);
-      COMPILER_BARRIER;
-
+        
       /* Push return values, and the number of values */
       for (i = 0; i < nvalues; i++)
         *++sp = vals[i+1];
@@ -1398,8 +1257,7 @@ VM_DEFINE_INSTRUCTION (68, return_values, "return/values", 1, -1, -1)
       sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
       ip = SCM_FRAME_RETURN_ADDRESS (fp);
       fp = SCM_FRAME_DYNAMIC_LINK (fp);
-      COMPILER_BARRIER;
-
+        
       /* Push first value */
       *++sp = vals[1];
              
@@ -1407,7 +1265,10 @@ VM_DEFINE_INSTRUCTION (68, return_values, "return/values", 1, -1, -1)
       NULLSTACK (vals + nvalues - sp);
     }
   else
-    goto vm_error_no_values;
+    {
+      SYNC_ALL ();
+      vm_error_no_values ();
+    }
 
   /* Restore the last program */
   program = SCM_FRAME_PROGRAM (fp);
@@ -1431,12 +1292,8 @@ VM_DEFINE_INSTRUCTION (69, return_values_star, "return/values*", 1, -1, -1)
       l = SCM_CDR (l);
       nvalues++;
     }
-  if (SCM_UNLIKELY (!SCM_NULL_OR_NIL_P (l))) {
-    finish_args = scm_list_1 (l);
-    goto vm_error_improper_list;
-  }
+  VM_ASSERT (SCM_NULL_OR_NIL_P (l), vm_error_improper_list (l));
 
-  DEAD (l);
   goto vm_return_values;
 }
 
@@ -1445,7 +1302,6 @@ VM_DEFINE_INSTRUCTION (70, return_nvalues, "return/nvalues", 0, 1, -1)
   SCM n;
   POP (n);
   nvalues = scm_to_int (n);
-  DEAD (n);
   ASSERT (nvalues >= 0);
   goto vm_return_values;
 }
@@ -1456,15 +1312,13 @@ VM_DEFINE_INSTRUCTION (71, truncate_values, "truncate-values", 2, -1, -1)
   int nbinds, rest;
   POP (x);
   nvalues = scm_to_int (x);
-  DEAD (x);
   nbinds = FETCH ();
   rest = FETCH ();
 
   if (rest)
     nbinds--;
 
-  if (nvalues < nbinds)
-    goto vm_error_not_enough_values;
+  VM_ASSERT (nvalues >= nbinds, vm_error_not_enough_values ());
 
   if (rest)
     POP_LIST (nvalues - nbinds);
@@ -1480,7 +1334,6 @@ VM_DEFINE_INSTRUCTION (72, box, "box", 1, 1, 0)
   POP (val);
   SYNC_BEFORE_GC ();
   LOCAL_SET (FETCH (), scm_cell (scm_tc7_variable, SCM_UNPACK (val)));
-  DEAD (val);
   NEXT;
 }
 
@@ -1502,7 +1355,6 @@ VM_DEFINE_INSTRUCTION (74, local_boxed_ref, "local-boxed-ref", 1, 0, 1)
   SCM v = LOCAL_REF (FETCH ());
   ASSERT_BOUND_VARIABLE (v);
   PUSH (VARIABLE_REF (v));
-  DEAD (v);
   NEXT;
 }
 
@@ -1513,8 +1365,6 @@ VM_DEFINE_INSTRUCTION (75, local_boxed_set, "local-boxed-set", 1, 1, 0)
   POP (val);
   ASSERT_VARIABLE (v);
   VARIABLE_SET (v, val);
-  DEAD (v);
-  DEAD (val);
   NEXT;
 }
 
@@ -1537,7 +1387,6 @@ VM_DEFINE_INSTRUCTION (77, free_boxed_ref, "free-boxed-ref", 1, 0, 1)
   v = FREE_VARIABLE_REF (idx);
   ASSERT_BOUND_VARIABLE (v);
   PUSH (VARIABLE_REF (v));
-  DEAD (v);
   NEXT;
 }
 
@@ -1550,8 +1399,6 @@ VM_DEFINE_INSTRUCTION (78, free_boxed_set, "free-boxed-set", 1, 1, 0)
   v = FREE_VARIABLE_REF (idx);
   ASSERT_BOUND_VARIABLE (v);
   VARIABLE_SET (v, val);
-  DEAD (v);
-  DEAD (val);
   NEXT;
 }
 
@@ -1570,7 +1417,6 @@ VM_DEFINE_INSTRUCTION (79, make_closure, "make-closure", 2, -1, 1)
   sp[-len] = closure;
   for (n = 0; n < len; n++)
     SCM_PROGRAM_FREE_VARIABLE_SET (closure, n, sp[-len + 1 + n]);
-  DEAD (closure);
   DROPN (len);
   NEXT;
 }
@@ -1596,7 +1442,6 @@ VM_DEFINE_INSTRUCTION (81, fix_closure, "fix-closure", 2, -1, 0)
   len = SCM_PROGRAM_NUM_FREE_VARIABLES (x);
   for (n = 0; n < len; n++)
     SCM_PROGRAM_FREE_VARIABLE_SET (x, n, sp[-len + 1 + n]);
-  DEAD (x);
   DROPN (len);
   NEXT;
 }
@@ -1606,11 +1451,7 @@ VM_DEFINE_INSTRUCTION (82, define, "define", 0, 0, 2)
   SCM sym, val;
   POP2 (sym, val);
   SYNC_REGISTER ();
-  VARIABLE_SET (scm_sym2var (sym, scm_current_module_lookup_closure (),
-                             SCM_BOOL_T),
-                val);
-  DEAD (sym);
-  DEAD (val);
+  scm_define (sym, val);
   NEXT;
 }
 
@@ -1654,8 +1495,6 @@ VM_DEFINE_INSTRUCTION (85, prompt, "prompt", 4, 2, 0)
          vm_engine that can be assigned *has* been assigned. So we need to pull
          all our state back from the ip/fp/sp.
       */
-      DEAD (k);
-      DEAD (prompt);
       CACHE_REGISTER ();
       program = SCM_FRAME_PROGRAM (fp);
       CACHE_PROGRAM ();
@@ -1665,9 +1504,6 @@ VM_DEFINE_INSTRUCTION (85, prompt, "prompt", 4, 2, 0)
       NEXT;
     }
       
-  DEAD (k);
-  DEAD (prompt);
-  
   /* Otherwise setjmp returned for the first time, so we go to execute the
      prompt's body. */
   NEXT;
@@ -1681,19 +1517,11 @@ VM_DEFINE_INSTRUCTION (86, wind, "wind", 0, 2, 0)
   /* Push wind and unwind procedures onto the dynamic stack. Note that neither
      are actually called; the compiler should emit calls to wind and unwind for
      the normal dynamic-wind control flow. */
-  if (SCM_UNLIKELY (scm_is_false (scm_thunk_p (wind))))
-    {
-      finish_args = wind;
-      goto vm_error_not_a_thunk;
-    }
-  if (SCM_UNLIKELY (scm_is_false (scm_thunk_p (unwind))))
-    {
-      finish_args = unwind;
-      goto vm_error_not_a_thunk;
-    }
+  VM_ASSERT (scm_to_bool (scm_thunk_p (wind)),
+            vm_error_not_a_thunk ("dynamic-wind", wind));
+  VM_ASSERT (scm_to_bool (scm_thunk_p (unwind)),
+            vm_error_not_a_thunk ("dynamic-wind", unwind));
   scm_i_set_dynwinds (scm_cons (scm_cons (wind, unwind), scm_i_dynwinds ()));
-  DEAD (wind);
-  DEAD (unwind);
   NEXT;
 }
 
@@ -1701,8 +1529,7 @@ VM_DEFINE_INSTRUCTION (87, abort, "abort", 1, -1, -1)
 {
   unsigned n = FETCH ();
   SYNC_REGISTER ();
-  if (sp - n - 2 <= SCM_FRAME_UPPER_ADDRESS (fp))
-    goto vm_error_stack_underflow;
+  PRE_CHECK_UNDERFLOW (n + 2);
   vm_abort (vm, n, vm_cookie);
   /* vm_abort should not return */
   abort ();
@@ -1729,7 +1556,6 @@ VM_DEFINE_INSTRUCTION (89, wind_fluids, "wind-fluids", 1, -1, 0)
 
   scm_i_swap_with_fluids (wf, current_thread->dynamic_state);
   scm_i_set_dynwinds (scm_cons (wf, scm_i_dynwinds ()));
-  DEAD (wf);
   NEXT;
 }
 
@@ -1739,7 +1565,6 @@ VM_DEFINE_INSTRUCTION (90, unwind_fluids, "unwind-fluids", 0, 0, 0)
   wf = scm_car (scm_i_dynwinds ());
   scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
   scm_i_swap_with_fluids (wf, current_thread->dynamic_state);
-  DEAD (wf);
   NEXT;
 }
 
@@ -1754,21 +1579,16 @@ VM_DEFINE_INSTRUCTION (91, fluid_ref, "fluid-ref", 0, 1, 1)
       || ((num = SCM_I_FLUID_NUM (*sp)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
     {
       /* Punt dynstate expansion and error handling to the C proc. */
-      DEAD (fluids);
       SYNC_REGISTER ();
       *sp = scm_fluid_ref (*sp);
     }
   else
     {
       SCM val = SCM_SIMPLE_VECTOR_REF (fluids, num);
-      DEAD (fluids);
       if (scm_is_eq (val, SCM_UNDEFINED))
         val = SCM_I_FLUID_DEFAULT (*sp);
-      if (SCM_UNLIKELY (scm_is_eq (val, SCM_UNDEFINED)))
-        {
-          finish_args = *sp;
-          goto vm_error_unbound_fluid;
-        }
+      VM_ASSERT (!scm_is_eq (val, SCM_UNDEFINED),
+                 vm_error_unbound_fluid (program, *sp));
       *sp = val;
     }
   
@@ -1791,9 +1611,7 @@ VM_DEFINE_INSTRUCTION (92, fluid_set, "fluid-set", 0, 2, 0)
     }
   else
     SCM_SIMPLE_VECTOR_SET (fluids, num, val);
-  DEAD (fluids);
-  DEAD (fluid);
-  DEAD (val);
+  
   NEXT;
 }
 
@@ -1805,8 +1623,8 @@ VM_DEFINE_INSTRUCTION (93, assert_nargs_ee_locals, "assert-nargs-ee/locals", 1,
   /* nargs = n & 0x7, nlocs = nargs + (n >> 3) */
   n = FETCH ();
 
-  if (SCM_UNLIKELY (sp - (fp - 1) != (n & 0x7)))
-    goto vm_error_wrong_num_args;
+  VM_ASSERT (sp - (fp - 1) == (n & 0x7),
+             vm_error_wrong_num_args (program));
 
   old_sp = sp;
   sp += (n >> 3);
@@ -1817,7 +1635,60 @@ VM_DEFINE_INSTRUCTION (93, assert_nargs_ee_locals, "assert-nargs-ee/locals", 1,
   NEXT;
 }
 
-#undef COMPILER_BARRIER
+/* Like bind-optionals/shuffle, but if there are too many positional
+   arguments, jumps to the next case-lambda clause.  */
+VM_DEFINE_INSTRUCTION (94, bind_optionals_shuffle_or_br, "bind-optionals/shuffle-or-br", 9, -1, -1)
+{
+  SCM *walk;
+  scm_t_ptrdiff nreq, nreq_and_opt, ntotal;
+  scm_t_int32 offset;
+  nreq = FETCH () << 8;
+  nreq += FETCH ();
+  nreq_and_opt = FETCH () << 8;
+  nreq_and_opt += FETCH ();
+  ntotal = FETCH () << 8;
+  ntotal += FETCH ();
+  FETCH_OFFSET (offset);
+
+  /* look in optionals for first keyword or last positional */
+  /* starting after the last required positional arg */
+  walk = fp + nreq;
+  while (/* while we have args */
+         walk <= sp
+         /* and we still have positionals to fill */
+         && walk - fp < nreq_and_opt
+         /* and we haven't reached a keyword yet */
+         && !scm_is_keyword (*walk))
+    /* bind this optional arg (by leaving it in place) */
+    walk++;
+  if (/* If we have filled all the positionals */
+      walk - fp == nreq_and_opt
+      /* and there are still more arguments */
+      && walk <= sp
+      /* and the next argument is not a keyword, */
+      && !scm_is_keyword (*walk))
+    {
+      /* Jump to the next case-lambda* clause. */
+      ip += offset;
+    }
+  else
+    {
+      /* Otherwise, finish as in bind-optionals/shuffle: shuffle up,
+         from walk to ntotal */
+      scm_t_ptrdiff nshuf = sp - walk + 1, i;
+      sp = (fp - 1) + ntotal + nshuf;
+      CHECK_OVERFLOW ();
+      for (i = 0; i < nshuf; i++)
+        sp[-i] = walk[nshuf-i-1];
+
+      /* and fill optionals & keyword args with SCM_UNDEFINED */
+      while (walk <= (fp - 1) + ntotal)
+        *walk++ = SCM_UNDEFINED;
+    }
+
+  NEXT;
+}
+
 
 /*
 (defun renumber-ops ()