@@ -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
0 commit comments