[PATCH] Modify call/cc to invoke the prompt handler in some cases

From: Asumu Takikawa (asumu at ccs.neu.edu)
Date: Fri Aug 31 16:26:50 EDT 2012

---
 src/racket/src/eval.c |  141 ++++++++++++++++++++++++++-----------------------
 1 file changed, 76 insertions(+), 65 deletions(-)

diff --git a/src/racket/src/eval.c b/src/racket/src/eval.c
index 65d138e..4fe1fef 100644
--- a/src/racket/src/eval.c
+++ b/src/racket/src/eval.c
@@ -1490,6 +1490,23 @@ static int exec_dyn_wind_posts(Scheme_Dynamic_Wind *common, Scheme_Cont *c, int
   return common_depth;
 }
 
+static Scheme_Object *callcc_thunk(int argc, Scheme_Object **argv, Scheme_Object *prim)
+{
+  Scheme_Object *cont = SCHEME_PRIM_CLOSURE_ELS(prim)[0];
+  int num_rands = (int)SCHEME_PRIM_CLOSURE_ELS(prim)[1];
+  Scheme_Object *val = SCHEME_PRIM_CLOSURE_ELS(prim)[2];
+
+  if (num_rands == 1) {
+    Scheme_Object *a[1];
+    a[0] = val;
+    return _scheme_apply_multi(cont, 1, a);
+  }
+  else {
+    Scheme_Object** vals = (Scheme_Object**)val;
+    return _scheme_apply_multi(cont, num_rands, vals);
+  }
+}
+
 Scheme_Object *scheme_jump_to_continuation(Scheme_Object *obj, int num_rands, Scheme_Object **rands, 
                                            Scheme_Object **old_runstack, int can_ec)
 {
@@ -1550,6 +1567,63 @@ Scheme_Object *scheme_jump_to_continuation(Scheme_Object *obj, int num_rands, Sc
     prompt = lookup_cont_prompt(c, &prompt_mc, &prompt_pos, LOOKUP_NO_PROMPT);
     barrier_prompt = check_barrier(prompt, prompt_mc, prompt_pos, c);
 
+    if (prompt &&
+        !(prompt->id && (prompt->id == c->prompt_id)
+          && !prompt_mc)) {
+      Scheme_Object* a[3];
+      Scheme_Object* thunk;
+      Scheme_Dynamic_Wind* dw;
+      Scheme_Meta_Continuation* mc;
+      c->composable = 1;
+ 
+      /* Remove extra dynamic wind records in call/cc continuation
+         to pretend it was composable to begin with */
+      dw = c->dw;
+      if (dw && dw->prompt_tag == c->prompt_tag)
+        c->dw = NULL;
+
+      for (; dw; dw = dw->prev) {
+        if (dw->prev && c->prompt_tag &&
+            (dw->prev->prompt_tag == c->prompt_tag)) {
+          dw->prev = NULL;
+          break;
+        }
+      }
+
+      /* Remove extra meta-continuation for composable */
+      mc = c->meta_continuation;
+      if (mc && mc->pseudo && mc->prompt_tag == c->prompt_tag)
+        c->meta_continuation = NULL;
+ 
+      for (; mc; mc = mc->next) {
+        if (mc->pseudo && mc->empty_to_next && mc->next
+            && SAME_OBJ(mc->next->prompt_tag, c->prompt_tag)) {
+          mc->next = NULL;
+          break;
+        }
+      }
+
+      a[0] = (Scheme_Object *)c;
+      a[1] = (Scheme_Object *)num_rands;
+      a[2] = (Scheme_Object *)value;
+      thunk = scheme_make_prim_closure_w_arity(callcc_thunk,
+                                               3, a,
+                                               "callcc-thunk",
+                                               0, 0);
+
+      p->cjs.jumping_to_continuation = (Scheme_Object *)prompt;
+      p->cjs.alt_full_continuation = NULL;
+      p->cjs.num_vals = 1;
+      p->cjs.val = thunk;
+      p->cjs.is_escape = 0;
+      p->cjs.skip_dws = 0;
+
+      MZ_RUNSTACK = old_runstack;
+      scheme_longjmp(*p->error_buf, 1);
+
+      return NULL;
+    }
+
     p->suspend_break++; /* restored at call/cc destination */
 
     /* Find `common', the intersection of dynamic-wind chain for 
@@ -1637,73 +1711,10 @@ Scheme_Object *scheme_jump_to_continuation(Scheme_Object *obj, int num_rands, Sc
         p->cjs.skip_dws = 0;
         scheme_longjmpup(&overflow->jmp->cont);
       }
-    } else {
-      /* The prompt is different than when we captured the continuation,
-         so we need to compose the continuation with the current prompt. */
-      p->cjs.jumping_to_continuation = (Scheme_Object *)prompt;
-      p->cjs.alt_full_continuation = NULL;
-      p->cjs.num_vals = 1;
-      p->cjs.val = (Scheme_Object *)c;
-      p->cjs.is_escape = 1;
-      p->cjs.skip_dws = 0;
-       
-      if (prompt_mc) {
-        /* The prompt is from a meta-continuation that's different
-           from the current one. Jump to the meta-continuation
-           and continue from there. Immediate destination is
-           in compose_continuation() in fun.c; the ultimate
-           destination is in scheme_finish_apply_for_prompt()
-           in fun.c.
-           We need to adjust the meta-continuation offsets in
-           common, based on the number that we're discarding
-           here. */
-        {
-          Scheme_Meta_Continuation *xmc;
-          int offset = 1;
-          for (xmc = p->meta_continuation; 
-               xmc->prompt_tag != prompt_mc->prompt_tag; 
-               xmc = xmc->next) {
-            if (xmc->overflow)
-              offset++;
-          }
-          c->common_next_meta -= offset;
-        }
-        p->meta_continuation = prompt_mc->next;
-        p->stack_start = prompt_mc->overflow->stack_start;
-        p->decompose_mc = prompt_mc;
-        scheme_longjmpup(&prompt_mc->overflow->jmp->cont);
-      } else if ((!prompt->boundary_overflow_id && !p->overflow)
-                 || (prompt->boundary_overflow_id
-                     && (prompt->boundary_overflow_id == p->overflow->id))) {
-        /* Jump directly to the prompt: destination is in
-           scheme_finish_apply_for_prompt() in fun.c. */
-        if (!p->meta_continuation)
-          scheme_signal_error("internal error: no meta-cont for escape");
-        if (p->meta_continuation->pseudo)
-          scheme_signal_error("internal error: trying to jump to a prompt in a meta-cont"
-                              " that starts with a pseudo prompt");
-        scheme_drop_prompt_meta_continuations(c->prompt_tag);
-        scheme_longjmp(*prompt->prompt_buf, 1);
-      } else {
-        /* Need to unwind overflows to get to the prompt. */
-        Scheme_Overflow *overflow;
-        scheme_drop_prompt_meta_continuations(c->prompt_tag);
-        overflow = p->overflow;
-        while (overflow->prev
-               && (!overflow->prev->id
-                   || (overflow->prev->id != prompt->boundary_overflow_id))) {
-          overflow = overflow->prev;
-        }
-        /* Immediate destination is in scheme_handle_stack_overflow().
-           Ultimate destination is in scheme_finish_apply_for_prompt()
-           in fun.c. */
-        p->overflow = overflow;
-        p->stack_start = overflow->stack_start;
-        scheme_longjmpup(&overflow->jmp->cont);
-      }
     }
-    return NULL;
   }
+
+  return NULL;
 }
 
 void scheme_escape_to_continuation(Scheme_Object *obj, int num_rands, Scheme_Object **rands, Scheme_Object *alt_full)
-- 
1.7.10.4


--nFreZHaLTZJo0R7j--

Posted on the dev mailing list.