Optimize 'string-hash'.
[bpt/guile.git] / libguile / vm-i-system.c
index ea00fc9..5057fb0 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001,2008,2009,2010,2011 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
@@ -31,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);
     }
     
   {
@@ -58,7 +65,8 @@ VM_DEFINE_INSTRUCTION (1, halt, "halt", 0, 0, 0)
     NULLSTACK (old_sp - sp);
   }
   
-  goto vm_done;
+  SYNC_ALL ();
+  return ret;
 }
 
 VM_DEFINE_INSTRUCTION (2, drop, "drop", 0, 1, 0)
@@ -233,7 +241,7 @@ VM_DEFINE_INSTRUCTION (18, vector, "vector", 2, -1, 1)
    nothing more than the corresponding macros.  */
 #define VARIABLE_REF(v)                SCM_VARIABLE_REF (v)
 #define VARIABLE_SET(v,o)      SCM_VARIABLE_SET (v, o)
-#define VARIABLE_BOUNDP(v)      (VARIABLE_REF (v) != SCM_UNDEFINED)
+#define VARIABLE_BOUNDP(v)      (!scm_is_eq (VARIABLE_REF (v), SCM_UNDEFINED))
 
 #define FREE_VARIABLE_REF(i)   SCM_PROGRAM_FREE_VARIABLE_REF (program, i)
 
@@ -277,10 +285,7 @@ VM_DEFINE_INSTRUCTION (22, long_local_ref, "long-local-ref", 2, 0, 1)
 
 VM_DEFINE_INSTRUCTION (23, local_bound, "local-bound?", 1, 0, 1)
 {
-  if (LOCAL_REF (FETCH ()) == SCM_UNDEFINED)
-    PUSH (SCM_BOOL_F);
-  else
-    PUSH (SCM_BOOL_T);
+  PUSH (scm_from_bool (!scm_is_eq (LOCAL_REF (FETCH ()), SCM_UNDEFINED)));
   NEXT;
 }
 
@@ -289,10 +294,7 @@ VM_DEFINE_INSTRUCTION (24, long_local_bound, "long-local-bound?", 2, 0, 1)
   unsigned int i = FETCH ();
   i <<= 8;
   i += FETCH ();
-  if (LOCAL_REF (i) == SCM_UNDEFINED)
-    PUSH (SCM_BOOL_F);
-  else
-    PUSH (SCM_BOOL_T);
+  PUSH (scm_from_bool (!scm_is_eq (LOCAL_REF (i), SCM_UNDEFINED)));
   NEXT;
 }
 
@@ -304,20 +306,17 @@ 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
     {
@@ -332,14 +331,10 @@ 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));
+  VM_ASSERT (SCM_VARIABLEP (x),
+             vm_error_not_a_variable ("variable-bound?", x));
+
+  *sp = scm_from_bool (VARIABLE_BOUNDP (x));
   NEXT;
 }
 
@@ -354,11 +349,7 @@ VM_DEFINE_INSTRUCTION (27, toplevel_ref, "toplevel-ref", 1, 0, 1)
     {
       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;
       OBJECT_SET (objnum, what);
     }
@@ -380,11 +371,8 @@ VM_DEFINE_INSTRUCTION (28, long_toplevel_ref, "long-toplevel-ref", 2, 0, 1)
     {
       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;
       OBJECT_SET (objnum, what);
     }
@@ -416,12 +404,8 @@ VM_DEFINE_INSTRUCTION (30, long_local_set, "long-local-set", 2, 1, 0)
 
 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;
@@ -591,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;
 }
 
@@ -601,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;
 }
 
@@ -653,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.  */
@@ -672,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);
@@ -696,13 +682,14 @@ 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]));
     }
 
   NEXT;
@@ -771,9 +758,9 @@ VM_DEFINE_INSTRUCTION (52, new_frame, "new-frame", 0, 0, 3)
      know that this frame will point to the current fp: it could be
      placed elsewhere on the stack if captured in a partial
      continuation, and invoked from some other context.  */
-  PUSH (0); /* dynamic link */
-  PUSH (0); /* mvra */
-  PUSH (0); /* ra */
+  PUSH (SCM_PACK (0)); /* dynamic link */
+  PUSH (SCM_PACK (0)); /* mvra */
+  PUSH (SCM_PACK (0)); /* ra */
   NEXT;
 }
 
@@ -782,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;
 
@@ -819,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;
 }
@@ -830,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;
+
+    NULLSTACK (old_sp - sp);
+  }
 
-      sp = fp + i - 1;
+  program = fp[-1];
 
-      NULLSTACK (old_sp - sp);
+  if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
+    goto apply;
 
-      ip = SCM_C_OBJCODE_BASE (bp);
+  CACHE_PROGRAM ();
+  ip = SCM_C_OBJCODE_BASE (bp);
 
-      APPLY_HOOK ();
-      NEXT;
-    }
+  APPLY_HOOK ();
+  NEXT;
 }
 
 VM_DEFINE_INSTRUCTION (55, subr_call, "subr-call", 1, -1, -1)
@@ -1041,10 +998,8 @@ 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);
@@ -1085,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;
 }
@@ -1144,12 +1081,8 @@ 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);
 
   nargs += len - 2;
@@ -1166,12 +1099,8 @@ 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);
 
   nargs += len - 2;
@@ -1188,9 +1117,9 @@ VM_DEFINE_INSTRUCTION (65, call_cc, "call/cc", 0, 1, 1)
   cont = scm_i_make_continuation (&first, vm, vm_cont);
   if (first) 
     {
-      PUSH (0); /* dynamic link */
-      PUSH (0);  /* mvra */
-      PUSH (0);  /* ra */
+      PUSH (SCM_PACK (0)); /* dynamic link */
+      PUSH (SCM_PACK (0));  /* mvra */
+      PUSH (SCM_PACK (0));  /* ra */
       PUSH (proc);
       PUSH (cont);
       nargs = 1;
@@ -1336,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);
@@ -1360,10 +1292,7 @@ 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));
 
   goto vm_return_values;
 }
@@ -1389,8 +1318,7 @@ VM_DEFINE_INSTRUCTION (71, truncate_values, "truncate-values", 2, -1, -1)
   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);
@@ -1523,9 +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);
+  scm_define (sym, val);
   NEXT;
 }
 
@@ -1591,16 +1517,10 @@ 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 ()));
   NEXT;
 }
@@ -1609,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 ();
@@ -1635,7 +1554,7 @@ VM_DEFINE_INSTRUCTION (89, wind_fluids, "wind-fluids", 1, -1, 0)
   wf = scm_i_make_with_fluids (n, sp + 1, sp + 1 + n);
   NULLSTACK (2 * n);
 
-  scm_i_swap_with_fluids (wf, dynstate);
+  scm_i_swap_with_fluids (wf, current_thread->dynamic_state);
   scm_i_set_dynwinds (scm_cons (wf, scm_i_dynwinds ()));
   NEXT;
 }
@@ -1645,7 +1564,7 @@ VM_DEFINE_INSTRUCTION (90, unwind_fluids, "unwind-fluids", 0, 0, 0)
   SCM wf;
   wf = scm_car (scm_i_dynwinds ());
   scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
-  scm_i_swap_with_fluids (wf, dynstate);
+  scm_i_swap_with_fluids (wf, current_thread->dynamic_state);
   NEXT;
 }
 
@@ -1655,7 +1574,7 @@ VM_DEFINE_INSTRUCTION (91, fluid_ref, "fluid-ref", 0, 1, 1)
   SCM fluids;
   
   CHECK_UNDERFLOW ();
-  fluids = SCM_I_DYNAMIC_STATE_FLUIDS (dynstate);
+  fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
   if (SCM_UNLIKELY (!SCM_FLUID_P (*sp))
       || ((num = SCM_I_FLUID_NUM (*sp)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
     {
@@ -1666,11 +1585,10 @@ VM_DEFINE_INSTRUCTION (91, fluid_ref, "fluid-ref", 0, 1, 1)
   else
     {
       SCM val = SCM_SIMPLE_VECTOR_REF (fluids, num);
-      if (SCM_UNLIKELY (val == SCM_UNDEFINED))
-        {
-          finish_args = *sp;
-          goto vm_error_unbound_fluid;
-        }
+      if (scm_is_eq (val, SCM_UNDEFINED))
+        val = SCM_I_FLUID_DEFAULT (*sp);
+      VM_ASSERT (!scm_is_eq (val, SCM_UNDEFINED),
+                 vm_error_unbound_fluid (program, *sp));
       *sp = val;
     }
   
@@ -1683,7 +1601,7 @@ VM_DEFINE_INSTRUCTION (92, fluid_set, "fluid-set", 0, 2, 0)
   SCM val, fluid, fluids;
   
   POP2 (val, fluid);
-  fluids = SCM_I_DYNAMIC_STATE_FLUIDS (dynstate);
+  fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
   if (SCM_UNLIKELY (!SCM_FLUID_P (fluid))
       || ((num = SCM_I_FLUID_NUM (fluid)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
     {
@@ -1705,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);
@@ -1717,6 +1635,60 @@ VM_DEFINE_INSTRUCTION (93, assert_nargs_ee_locals, "assert-nargs-ee/locals", 1,
   NEXT;
 }
 
+/* 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 ()