@@ -1561,6 +1561,57 @@ static SgPromptNode *search_prompt_node(SgVM *vm, SgObject tag)
15611561 return NULL ;
15621562}
15631563
1564+ static int has_barrier_node (SgVM * vm , SgObject tag )
1565+ {
1566+ SgPromptNode * node = vm -> prompts ;
1567+
1568+ /* search tag */
1569+ while (node ) {
1570+ if (node -> prompt -> tag == tag ) return FALSE;
1571+ if (node -> prompt -> barrierP ) return TRUE;
1572+ node = node -> next ;
1573+ }
1574+ return FALSE;
1575+ }
1576+
1577+ /*
1578+ Check if invoking a continuation would enter a barrier from outside.
1579+ This happens when:
1580+ - The continuation was captured inside a barrier
1581+ - We're currently outside that barrier
1582+ - Invoking would restore to inside the barrier = "entering" = error
1583+
1584+ Returns the barrier prompt if entering would occur, NULL otherwise.
1585+ */
1586+ static SgPrompt * check_barrier_entry (SgVM * vm , SgContinuation * c )
1587+ {
1588+ SgContFrame * cont = c -> cont ;
1589+
1590+ /* Scan saved continuation frames for barrier prompts */
1591+ while (!bottom_cont_frame_p (vm , cont )) {
1592+ if (PROMPT_FRAME_MARK_P (cont )) {
1593+ SgPrompt * p = (SgPrompt * )cont -> pc ;
1594+ if (p -> barrierP ) {
1595+ /* Check if this barrier is in current prompt chain */
1596+ SgPromptNode * node = vm -> prompts ;
1597+ int found = FALSE;
1598+ while (node ) {
1599+ if (node -> prompt == p ) {
1600+ found = TRUE;
1601+ break ;
1602+ }
1603+ node = node -> next ;
1604+ }
1605+ if (!found ) {
1606+ /* Barrier in saved state but not current -> entering barrier */
1607+ return p ;
1608+ }
1609+ }
1610+ }
1611+ cont = cont -> prev ;
1612+ }
1613+ return NULL ; /* ok, no barrier entry */
1614+ }
15641615
15651616static int cont_prompt_match_p (SgContFrame * c , SgPrompt * prompt )
15661617{
@@ -1603,6 +1654,8 @@ static void install_prompt(SgVM *, SgPrompt *);
16031654static void remove_prompt (SgVM * , SgPrompt * );
16041655static SgPromptNode * remove_prompts (SgVM * , SgObject );
16051656static SgObject abort_body (SgPromptNode * node , SgObject winders , SgObject args );
1657+ static void continuation_violation (SgObject who , SgObject message ,
1658+ SgObject promptTag );
16061659
16071660static SgObject throw_delimited_continuation_body (SgObject ,
16081661 SgContinuation * ,
@@ -1858,6 +1911,15 @@ static SgObject throw_continuation(SgObject *argv, int argc, void *data)
18581911 SgObject handlers ;
18591912 SgVM * vm = Sg_VM ();
18601913 SgPrompt * prompt = (SgPrompt * )SG_CDR (data );
1914+ SgPrompt * barrier ;
1915+
1916+ /* Check if we're trying to enter a barrier from outside */
1917+ barrier = check_barrier_entry (vm , c );
1918+ if (barrier ) {
1919+ continuation_violation (SG_INTERN ("continuation" ),
1920+ SG_MAKE_STRING ("Cannot apply continuation across barrier" ),
1921+ barrier -> tag );
1922+ }
18611923
18621924 if (c -> cstack && vm -> cstack != c -> cstack ) {
18631925 SgCStack * cs ;
@@ -1984,8 +2046,14 @@ SgObject Sg_VMCallComp(SgObject proc, SgObject tag)
19842046 SgContinuation * cont ;
19852047 SgObject contproc ;
19862048 SgVM * vm = Sg_VM ();
1987- SgPromptNode * node = search_prompt_node ( vm , tag ) ;
2049+ SgPromptNode * node ;
19882050
2051+ if (has_barrier_node (vm , tag )) {
2052+ CONT_ERR ("call-with-composable-continuation" ,
2053+ "Cannot capture past continuation barrier" , tag );
2054+ }
2055+
2056+ node = search_prompt_node (vm , tag );
19892057 if (!node ) goto err ;
19902058 /*
19912059 NOT DOING IT FOR NOW.
@@ -2181,6 +2249,7 @@ static SgPrompt *make_prompt(SgObject tag, SgObject handler, SgVM *vm)
21812249 prompt -> handler = handler ;
21822250 prompt -> cstack = vm -> cstack ;
21832251 prompt -> winders = vm -> dynamicWinders ;
2252+ prompt -> barrierP = FALSE;
21842253 return prompt ;
21852254}
21862255
@@ -2226,6 +2295,11 @@ static SgPromptNode * remove_prompts(SgVM *vm, SgObject tag)
22262295 return cur_node ;
22272296}
22282297
2298+ static SgObject make_prompt_tag (SgObject name )
2299+ {
2300+ return SG_LIST1 (name );
2301+ }
2302+
22292303SgObject Sg_VMCallCP (SgObject proc , SgObject tag ,
22302304 SgObject handler , SgObject args )
22312305{
@@ -2244,6 +2318,28 @@ SgObject Sg_VMCallCP(SgObject proc, SgObject tag,
22442318 return Sg_VMApply (proc , args );
22452319}
22462320
2321+ static SgPrompt * make_barrier_prompt (SgVM * vm )
2322+ {
2323+ SgObject tag = make_prompt_tag (Sg_Gensym (SG_MAKE_STRING ("barrier" )));
2324+ SgPrompt * p = make_prompt (tag , SG_FALSE , vm );
2325+ p -> barrierP = TRUE;
2326+ return p ;
2327+ }
2328+
2329+ SgObject Sg_VMCallCB (SgObject thunk )
2330+ {
2331+ SgVM * vm = theVM ;
2332+ SgPrompt * prompt = make_barrier_prompt (vm );
2333+ CHECK_STACK (CONT_FRAME_SIZE , vm );
2334+ PUSH_PROMPT_CONT (vm , prompt );
2335+ install_prompt (vm , prompt );
2336+ return Sg_VMApply0 (thunk );
2337+ }
2338+
2339+ SgObject Sg_MakeContinuationPromptTag (SgObject name )
2340+ {
2341+ return make_prompt_tag (name );
2342+ }
22472343
22482344/* given load path must be unshifted.
22492345 NB: we don't check the validity of given path.
@@ -2746,7 +2842,8 @@ static SgObject abort_body(SgPromptNode *node, SgObject winders, SgObject args)
27462842 the captured node is not loger valid.
27472843 */
27482844 SgPromptNode * cur_node = remove_prompts (vm , node -> prompt -> tag );
2749- if (!cur_node ) Sg_Error (UC ("Stale prompt: %S" ), node -> prompt -> tag );
2845+ if (!cur_node )
2846+ CONT_ERR ("abort-current-continuation" , "Stale prompt" , node -> prompt -> tag );
27502847 SgPrompt * prompt = cur_node -> prompt ;
27512848
27522849 if (prompt -> cstack != vm -> cstack ) {
@@ -2774,7 +2871,7 @@ SgObject Sg_VMAbortCC(SgObject tag, SgObject args)
27742871 SgPromptNode * node = search_prompt_node (vm , tag );
27752872 SgContinuation c ;
27762873
2777- if (!node ) Sg_Error ( UC ( " No continuation tag: %S" ) , tag );
2874+ if (!node ) CONT_ERR ( "abort-current-continuation" , " No continuation tag" , tag );
27782875
27792876 /* compose fake continuation to compute winders */
27802877 c .winders = node -> prompt -> winders ;
0 commit comments