+VM_DEFINE_INSTRUCTION (85, prompt, "prompt", 4, 2, 0)
+{
+ scm_t_int32 offset;
+ scm_t_uint8 escape_only_p;
+ SCM k, prompt;
+
+ escape_only_p = FETCH ();
+ FETCH_OFFSET (offset);
+ POP (k);
+
+ SYNC_REGISTER ();
+ /* Push the prompt onto the dynamic stack. */
+ prompt = scm_c_make_prompt (k, fp, sp, ip + offset, escape_only_p, vm_cookie,
+ scm_i_dynwinds ());
+ scm_i_set_dynwinds (scm_cons (prompt, SCM_PROMPT_DYNWINDS (prompt)));
+ if (SCM_PROMPT_SETJMP (prompt))
+ {
+ /* The prompt exited nonlocally. Cache the regs back from the vp, and go
+ to the handler.
+
+ 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 ();
+ program = SCM_FRAME_PROGRAM (fp);
+ CACHE_PROGRAM ();
+ /* The stack contains the values returned to this prompt, along
+ with a number-of-values marker -- like an MV return. */
+ ABORT_CONTINUATION_HOOK ();
+ NEXT;
+ }
+
+ /* Otherwise setjmp returned for the first time, so we go to execute the
+ prompt's body. */
+ NEXT;
+}
+
+VM_DEFINE_INSTRUCTION (86, wind, "wind", 0, 2, 0)
+{
+ SCM wind, unwind;
+ POP2 (unwind, wind);
+ SYNC_REGISTER ();
+ /* 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. */
+ 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;
+}
+
+VM_DEFINE_INSTRUCTION (87, abort, "abort", 1, -1, -1)
+{
+ unsigned n = FETCH ();
+ SYNC_REGISTER ();
+ PRE_CHECK_UNDERFLOW (n + 2);
+ vm_abort (vm, n, vm_cookie);
+ /* vm_abort should not return */
+ abort ();
+}
+
+VM_DEFINE_INSTRUCTION (88, unwind, "unwind", 0, 0, 0)
+{
+ /* A normal exit from the dynamic extent of an expression. Pop the top entry
+ off of the dynamic stack. */
+ scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
+ NEXT;
+}
+
+VM_DEFINE_INSTRUCTION (89, wind_fluids, "wind-fluids", 1, -1, 0)
+{
+ unsigned n = FETCH ();
+ SCM wf;
+
+ SYNC_REGISTER ();
+ sp -= 2 * n;
+ CHECK_UNDERFLOW ();
+ wf = scm_i_make_with_fluids (n, sp + 1, sp + 1 + n);
+ NULLSTACK (2 * n);
+
+ scm_i_swap_with_fluids (wf, current_thread->dynamic_state);
+ scm_i_set_dynwinds (scm_cons (wf, scm_i_dynwinds ()));
+ NEXT;
+}
+
+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, current_thread->dynamic_state);
+ NEXT;
+}
+
+VM_DEFINE_INSTRUCTION (91, fluid_ref, "fluid-ref", 0, 1, 1)
+{
+ size_t num;
+ SCM fluids;
+
+ CHECK_UNDERFLOW ();
+ 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)))
+ {
+ /* Punt dynstate expansion and error handling to the C proc. */
+ SYNC_REGISTER ();
+ *sp = scm_fluid_ref (*sp);
+ }
+ else
+ {
+ SCM val = SCM_SIMPLE_VECTOR_REF (fluids, num);
+ 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;
+ }
+
+ NEXT;
+}
+
+VM_DEFINE_INSTRUCTION (92, fluid_set, "fluid-set", 0, 2, 0)
+{
+ size_t num;
+ SCM val, fluid, fluids;
+
+ POP2 (val, fluid);
+ 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)))
+ {
+ /* Punt dynstate expansion and error handling to the C proc. */
+ SYNC_REGISTER ();
+ scm_fluid_set_x (fluid, val);
+ }
+ else
+ SCM_SIMPLE_VECTOR_SET (fluids, num, val);
+
+ NEXT;
+}
+
+VM_DEFINE_INSTRUCTION (93, assert_nargs_ee_locals, "assert-nargs-ee/locals", 1, 0, 0)
+{
+ scm_t_ptrdiff n;
+ SCM *old_sp;
+
+ /* nargs = n & 0x7, nlocs = nargs + (n >> 3) */
+ n = FETCH ();
+
+ VM_ASSERT (sp - (fp - 1) == (n & 0x7),
+ vm_error_wrong_num_args (program));
+
+ old_sp = sp;
+ sp += (n >> 3);
+ CHECK_OVERFLOW ();
+ while (old_sp < sp)
+ *++old_sp = SCM_UNDEFINED;
+
+ 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;
+}
+