initial VM support for delimited continuations and dynamic-wind
authorAndy Wingo <wingo@pobox.com>
Sat, 30 Jan 2010 14:45:37 +0000 (15:45 +0100)
committerAndy Wingo <wingo@pobox.com>
Sun, 31 Jan 2010 19:40:21 +0000 (20:40 +0100)
* libguile/vm-i-system.c (prompt, wind, throw, unwind):
  New instructions, for implementing dynamic-wind and delimited
  continuations.
* libguile/vm.c: Add some stub support for the new instructions.
* libguile/vm-engine.c: Some new error conditions.

libguile/vm-engine.c
libguile/vm-i-system.c
libguile/vm.c

index c46834b..75dd613 100644 (file)
@@ -214,6 +214,12 @@ VM_NAME (SCM vm, SCM program, SCM *argv, int nargs)
     /* shouldn't get here */
     goto vm_error;
 
+  vm_error_not_a_thunk:
+    SYNC_ALL ();
+    scm_wrong_type_arg_msg (FUNC_NAME, 1, finish_args, "thunk");
+    /* shouldn't get here */
+    goto vm_error;
+
   vm_error_no_values:
     err_msg  = scm_from_locale_string ("Zero values returned to single-valued continuation");
     finish_args = SCM_EOL;
index 8c280fd..258aa52 100644 (file)
@@ -1433,6 +1433,87 @@ VM_DEFINE_INSTRUCTION (82, make_symbol, "make-symbol", 0, 1, 1)
   NEXT;
 }
 
+VM_DEFINE_INSTRUCTION (83, prompt, "prompt", 5, 3, 0)
+{
+  scm_t_int32 offset;
+  scm_t_uint8 inline_handler_p, escape_only_p;
+  SCM k, handler, pre_unwind, jmpbuf;
+
+  inline_handler_p = FETCH ();
+  escape_only_p = FETCH ();
+  FETCH_OFFSET (offset);
+  POP (pre_unwind);
+  POP (handler);
+  POP (k);
+
+  SYNC_REGISTER ();
+  /* Push the prompt onto the dynamic stack. The setjmp itself has to be local
+     to this procedure. */
+  jmpbuf = vm_prepare_prompt_jmpbuf (vm, k, handler, pre_unwind,
+                                     inline_handler_p, escape_only_p);
+  if (VM_SETJMP (jmpbuf))
+    {
+      /* The prompt exited nonlocally. Cache the regs back from the vp, and go
+         to the handler or post-handler label. (The meaning of the label differs
+         depending on whether the prompt's handler is rendered inline or not.)
+         */
+      CACHE_REGISTER (); /* Really we only need SP. FP and IP should be
+                            unmodified. */
+      ip += offset;
+      NEXT;
+    }
+      
+  /* Otherwise setjmp returned for the first time, so we go to execute the
+     prompt's body. */
+  NEXT;
+}
+
+VM_DEFINE_INSTRUCTION (85, wind, "wind", 0, 2, 0)
+{
+  SCM wind, unwind;
+  POP (unwind);
+  POP (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. */
+  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;
+    }
+  scm_i_set_dynwinds (scm_cons (scm_cons (wind, unwind), scm_i_dynwinds ()));
+  NEXT;
+}
+
+VM_DEFINE_INSTRUCTION (86, throw, "throw", 1, -1, -1)
+{
+  unsigned n = FETCH ();
+  SCM k;
+  SCM args;
+  POP_LIST (n);
+  POP (args);
+  POP (k);
+  SYNC_REGISTER ();
+  vm_throw (vm, k, args);
+  /* vm_throw should not return */
+  abort ();
+}
+
+VM_DEFINE_INSTRUCTION (87, 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;
+}
+
+
 
 /*
 (defun renumber-ops ()
index afa888e..4c647b0 100644 (file)
@@ -170,6 +170,27 @@ vm_dispatch_hook (SCM vm, int hook_num)
 }
 
 \f
+/*
+ * The dynamic stack
+ */
+static SCM
+vm_prepare_prompt_jmpbuf (SCM vm, SCM k, SCM handler, SCM pre_unwind,
+                          scm_t_uint8 inline_p, scm_t_uint8 escape_only_p)
+{
+  abort ();
+  return SCM_BOOL_F;
+}
+
+#define VM_SETJMP(jmpbuf) 0
+
+static void vm_throw (SCM vm, SCM k, SCM args) SCM_NORETURN;
+static void
+vm_throw (SCM vm, SCM k, SCM args)
+{
+  abort ();
+}
+
+\f
 /*
  * VM Internal functions
  */