Skip to content

Commit 6c50178

Browse files
committed
dynamic_wind: winders stored with thread context
1 parent c13e123 commit 6c50178

File tree

5 files changed

+99
-76
lines changed

5 files changed

+99
-76
lines changed

src/alloc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,15 @@ obj Msetb_continuation(obj prev, obj env, obj name) {
175175
return x;
176176
}
177177

178-
obj Mcallcc_continuation(obj prev, obj env) {
178+
obj Mcallcc_continuation(obj prev, obj env, obj winders) {
179179
obj x = GC_malloc(Mcontinuation_callcc_size);
180180
obj_type(x) = CONTINUATON_OBJ_TYPE;
181181
Mcontinuation_type(x) = CALLCC_CONT_TYPE;
182182
Mcontinuation_immutablep(x) = 0;
183183
Mcontinuation_capturedp(x) = 0;
184184
Mcontinuation_prev(x) = prev;
185185
Mcontinuation_env(x) = env;
186+
Mcontinuation_callcc_winders(x) = winders;
186187
return x;
187188
}
188189

@@ -230,6 +231,7 @@ obj Mthread_context(void) {
230231
obj x = GC_malloc(Mtc_size);
231232
obj_type(x) = THREAD_OBJ_TYPE;
232233
Mtc_cc(x) = Mnull;
234+
Mtc_wnd(x) = Mnull;
233235
Mtc_env(x) = Mnull;
234236
Mtc_vb(x) = GC_malloc(INIT_VALUES_BUFFER_LEN * sizeof(obj));
235237
Mtc_va(x) = INIT_VALUES_BUFFER_LEN;

src/continuation.c

Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ obj continuation_mutable(obj k) {
7474

7575
// call/cc expressions
7676
case CALLCC_CONT_TYPE:
77-
k2 = Mcallcc_continuation(Mcontinuation_prev(k), Mcontinuation_env(k));
77+
k2 = Mcallcc_continuation(
78+
Mcontinuation_prev(k),
79+
Mcontinuation_env(k),
80+
Mcontinuation_callcc_winders(k)
81+
);
7882
break;
7983

8084
// dynamic-wind expressions
@@ -101,86 +105,84 @@ obj continuation_mutable(obj k) {
101105
}
102106

103107
// Length of a continuation chain.
104-
static uptr continuation_length(obj k) {
105-
uptr l = 0;
106-
for (; Mcontinuationp(k); k = Mcontinuation_prev(k), ++l);
107-
return l;
108-
}
109-
110-
// Extracts the tail of a continuation chain.
111-
static obj continuation_tail(obj k, iptr l) {
112-
for (uptr i = 0; i < l; ++i, k = Mcontinuation_prev(k));
113-
return k;
114-
}
115-
116-
// Extracts the common tail of two continuation chains.
117-
static obj common_tail(obj k1, obj k2) {
118-
uptr l1, l2;
119-
120-
// eliminate excess frames
121-
l1 = continuation_length(k1);
122-
l2 = continuation_length(k2);
108+
// static uptr continuation_length(obj k) {
109+
// uptr l = 0;
110+
// for (; Mcontinuationp(k); k = Mcontinuation_prev(k), ++l);
111+
// return l;
112+
// }
113+
114+
// // Extracts the tail of a continuation chain.
115+
// static obj continuation_tail(obj k, iptr l) {
116+
// for (uptr i = 0; i < l; ++i, k = Mcontinuation_prev(k));
117+
// return k;
118+
// }
119+
120+
// Extracts the common tail of two winder lists
121+
static obj common_tail(obj xs, obj ys) {
122+
iptr l1, l2;
123+
124+
// eliminate excess winders
125+
l1 = list_length(xs);
126+
l2 = list_length(ys);
123127
if (l1 > l2) {
124-
k1 = continuation_tail(k1, l1 - l2);
128+
xs = list_tail(xs, l1 - l2);
125129
} else if (l2 > l1) {
126-
k2 = continuation_tail(k2, l2 - l1);
130+
ys = list_tail(ys, l2 - l1);
127131
}
128132

129-
// unwind both until a common ancestor is found
130-
while (Mcontinuationp(k1)) {
131-
if (k1 == k2)
132-
return k1;
133+
// walk back along tails until a common ancestor
134+
while (!Mnullp(xs)) {
135+
if (xs == ys)
136+
return xs;
133137

134-
k1 = Mcontinuation_prev(k1);
135-
k2 = Mcontinuation_prev(k2);
138+
xs = Mcdr(xs);
139+
ys = Mcdr(ys);
136140
}
137141

138-
return k1;
142+
return xs;
139143
}
140144

141-
// Restores a continuation.
142-
// The result is a new continuation chain formed by merging
143-
// the common ancestors of the continuation and current continuation.
144-
obj continuation_restore(obj cc, obj k) {
145-
obj tl, it, cc_winders, k_winders, winders;
145+
// Restores a continuation. The continuation must have been captured
146+
// by `call/cc`. May add a continuation frame to handle any winders
147+
// installed by `dynamic-wind`.
148+
obj continuation_restore(obj tc, obj k) {
149+
obj cc_winders, k_winders, tl, it, unwind, wind, winders;
146150

147151
// check that continuation was captured by call/cc
148152
if (!Mcontinuation_capturedp(k)) {
149153
minim_error1("continuation_restore()", "can only restored captured continuations", k);
150154
}
151155

152-
153-
tl = common_tail(cc, k);
154-
if (tl == k) {
155-
// edge case: `tl` is just `k` so nothing to do
156-
return tl;
156+
// compute common tail of winders
157+
cc_winders = Mtc_wnd(tc);
158+
k_winders = Mcontinuation_callcc_winders(k);
159+
tl = common_tail(cc_winders, k_winders);
160+
161+
// winders are the same, just restore the continuation
162+
if (tl == k_winders) {
163+
return k;
157164
}
158-
159-
// unwind `cc` to the tail and restore `k`
160-
// need to track winders and possibly create a continuation to execute them
161-
cc_winders = Mnull;
162-
for (it = cc; it != tl; it = Mcontinuation_prev(it)) {
163-
if (Mcontinuation_dynwindp(it) && Mcontinuation_dynwind_state(it) == DYNWIND_VAL) {
164-
// unwinding active dynamic wind => need to execute post thunk
165-
cc_winders = Mcons(Mcontinuation_dynwind_post(it), cc_winders);
166-
}
165+
166+
// find all winders in `cc` that need to be unwound
167+
unwind = Mnull;
168+
for (it = cc_winders; it != tl; it = Mcdr(it)) {
169+
// unwinding => need to execute post thunk
170+
unwind = Mcons(Mcdar(it), unwind);
167171
}
168172

169-
k_winders = Mnull;
170-
for (it = k; it != tl; it = Mcontinuation_prev(it)) {
171-
if (Mcontinuation_dynwindp(cc) && Mcontinuation_dynwind_state(cc) == DYNWIND_VAL) {
172-
// restoring active dynamic wind => need to execute pre thunk
173-
k_winders = Mcons(Mcontinuation_dynwind_pre(it), k_winders);
174-
}
173+
wind = Mnull;
174+
for (it = k_winders; it != tl; it = Mcdr(it)) {
175+
// winding => need to execute pre thunk
176+
wind = Mcons(Mcaar(it), wind);
175177
}
176178

177-
// cc_winders first, in reverse order, then k_winders
178-
winders = Mappend(Mreverse(cc_winders), k_winders);
179+
// unwind, in reverse order, than wind
180+
winders = Mappend(Mreverse(unwind), wind);
179181
if (!Mnullp(winders)) {
180182
// any winders => need to execute them before anything else
181183
k = Mwinders_continuation(k, Mcontinuation_env(k), winders);
182184
}
183-
185+
184186
return k;
185187
}
186188

src/eval.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ static obj eval_k(obj e) {
344344
} else if (hd == Mcallcc_symbol) {
345345
// call/cc
346346
continuation_set_immutable(Mtc_cc(tc)); // freeze the continuation chain
347-
Mtc_cc(tc) = Mcallcc_continuation(Mtc_cc(tc), Mtc_env(tc));
347+
Mtc_cc(tc) = Mcallcc_continuation(Mtc_cc(tc), Mtc_env(tc), Mtc_wnd(tc));
348348
e = Mcadr(e);
349349
goto loop;
350350
} else if (hd == Mcallwv_symbol) {
@@ -403,7 +403,7 @@ static obj eval_k(obj e) {
403403
Mtc_env(tc) = do_closure(f, args);
404404
goto loop;
405405
} else if (Mcontinuationp(f)) {
406-
Mtc_cc(tc) = continuation_restore(Mtc_cc(tc), f);
406+
Mtc_cc(tc) = continuation_restore(tc, f);
407407
x = do_values(args);
408408
goto do_k;
409409
} else {
@@ -466,6 +466,7 @@ static obj eval_k(obj e) {
466466
case CALLCC_CONT_TYPE:
467467
if (Mcontinuation_capturedp(Mtc_cc(tc))) {
468468
// restoring captured continuation
469+
Mtc_wnd(tc) = Mcontinuation_callcc_winders(Mtc_cc(tc));
469470
Mtc_cc(tc) = Mcontinuation_prev(Mtc_cc(tc));
470471
goto do_k;
471472
} else {
@@ -525,6 +526,7 @@ static obj eval_k(obj e) {
525526

526527
// dynamic-wind expressions
527528
case DYNWIND_CONT_TYPE:
529+
Mtc_cc(tc) = continuation_mutable(Mtc_cc(tc));
528530
switch (Mcontinuation_dynwind_state(Mtc_cc(tc))) {
529531
// unevaluated dynamic-wind
530532
case DYNWIND_NEW:
@@ -561,8 +563,15 @@ static obj eval_k(obj e) {
561563

562564
// evaluated pre thunk
563565
case DYNWIND_PRE:
564-
assert_single_value(Mtc_cc(tc), x);
565566
Mcontinuation_dynwind_state(Mtc_cc(tc)) = DYNWIND_VAL;
567+
Mtc_wnd(tc) = Mcons(
568+
Mcons(
569+
Mcontinuation_dynwind_pre(Mtc_cc(tc)),
570+
Mcontinuation_dynwind_post(Mtc_cc(tc))
571+
),
572+
Mtc_wnd(tc)
573+
);
574+
566575
Mtc_env(tc) = Mcontinuation_env(Mtc_cc(tc));
567576
f = Mcontinuation_dynwind_val(Mtc_cc(tc));
568577
args = Mnull;
@@ -577,6 +586,7 @@ static obj eval_k(obj e) {
577586
Mcontinuation_dynwind_val(Mtc_cc(tc)) = Mlist1(x);
578587
}
579588

589+
Mtc_wnd(tc) = Mcdr(Mtc_wnd(tc));
580590
Mcontinuation_dynwind_state(Mtc_cc(tc)) = DYNWIND_POST;
581591
Mtc_env(tc) = Mcontinuation_env(Mtc_cc(tc));
582592
f = Mcontinuation_dynwind_post(Mtc_cc(tc));

src/list.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,8 @@ obj Mappend(obj x, obj y) {
5151
return hd;
5252
}
5353
}
54+
55+
obj list_tail(obj x, iptr i) {
56+
for (; i > 0; i--, x = Mcdr(x));
57+
return x;
58+
}

src/minim.h

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,9 @@ typedef enum {
279279
#define Mcontinuation_setbp(o) (Mcontinuation_type(o) == SETB_CONT_TYPE)
280280
#define Mcontinuation_setb_name(o) (*((obj*) ptr_add(o, 3 * ptr_size)))
281281

282-
#define Mcontinuation_callcc_size Mcontinuation_size(0)
282+
#define Mcontinuation_callcc_size Mcontinuation_size(1)
283283
#define Mcontinuation_callccp(o) (Mcontinuation_type(o) == CALLCC_CONT_TYPE)
284+
#define Mcontinuation_callcc_winders(o) (*((obj*) ptr_add(o, 3 * ptr_size)))
284285

285286
#define Mcontinuation_callwv_size Mcontinuation_size(2)
286287
#define Mcontinuation_callwvp(o) (Mcontinuation_type(o) == CALLWV_CONT_TYPE)
@@ -308,7 +309,7 @@ obj Mcond_continuation(obj prev, obj env, obj ift, obj iff);
308309
obj Mseq_continuation(obj prev, obj env, obj seq);
309310
obj Mlet_continuation(obj prev, obj env, obj bindings, obj body);
310311
obj Msetb_continuation(obj prev, obj env, obj name);
311-
obj Mcallcc_continuation(obj prev, obj env);
312+
obj Mcallcc_continuation(obj prev, obj env, obj winders);
312313
obj Mcallwv_continuation(obj prev, obj env, obj producer);
313314
obj Mdynwind_continuation(obj prev, obj env, obj val, obj post);
314315
obj Mwinders_continuation(obj prev, obj env, obj winders);
@@ -344,18 +345,20 @@ void port_write(int c, obj p);
344345
// +------------+
345346
// | type | [0, 1)
346347
// | cc | [8, 16) // current continuation
347-
// | env | [16, 24)
348-
// | vb | [24, 32) // values buffer
349-
// | va | [24, 32) // values buffer allocation size
350-
// | vc | [32, 40) // values buffer count
348+
// | winders | [16, 24) // current winders
349+
// | env | [24, 32) // current environment
350+
// | vb | [32, 40) // values buffer
351+
// | va | [40, 48) // values buffer allocation size
352+
// | vc | [48, 56) // values buffer count
351353
// +------------+
352-
#define Mtc_size (6 * ptr_size)
354+
#define Mtc_size (7 * ptr_size)
353355
#define Mtcp(o) (obj_type(o) == THREAD_OBJ_TYPE)
354356
#define Mtc_cc(o) (*((obj*) ptr_add(o, ptr_size)))
355-
#define Mtc_env(o) (*((obj*) ptr_add(o, 2 * ptr_size)))
356-
#define Mtc_vb(o) (*((obj**) ptr_add(o, 3 * ptr_size)))
357-
#define Mtc_va(o) (*((uptr*) ptr_add(o, 4 * ptr_size)))
358-
#define Mtc_vc(o) (*((uptr*) ptr_add(o, 5 * ptr_size)))
357+
#define Mtc_wnd(o) (*((obj*) ptr_add(o, 2 * ptr_size)))
358+
#define Mtc_env(o) (*((obj*) ptr_add(o, 3 * ptr_size)))
359+
#define Mtc_vb(o) (*((obj**) ptr_add(o, 4 * ptr_size)))
360+
#define Mtc_va(o) (*((uptr*) ptr_add(o, 5 * ptr_size)))
361+
#define Mtc_vc(o) (*((uptr*) ptr_add(o, 6 * ptr_size)))
359362

360363
obj Mthread_context(void);
361364

@@ -400,6 +403,7 @@ iptr list_length(obj x);
400403
obj Mlength(obj x);
401404
obj Mreverse(obj x);
402405
obj Mappend(obj x, obj y);
406+
obj list_tail(obj x, iptr i);
403407

404408
// Continuations
405409

@@ -413,10 +417,10 @@ void continuation_set_immutable(obj k);
413417
// Otherwise, the argument is returned.
414418
obj continuation_mutable(obj k);
415419

416-
// Restores a continuation.
417-
// The result is a new continuation chain formed by merging
418-
// the common ancestors of the continuation and current continuation.
419-
obj continuation_restore(obj cc, obj k);
420+
// Restores a continuation. The continuation must have been captured
421+
// by `call/cc`. May add a continuation frame to handle any winders
422+
// installed by `dynamic-wind`.
423+
obj continuation_restore(obj tc, obj k);
420424

421425
// For debugging
422426
void print_continuation(obj cc);

0 commit comments

Comments
 (0)