Skip to content

Commit d1d282b

Browse files
committed
Fix one prompt failure case on built-in call/delimited-cc
1 parent 83d3bcc commit d1d282b

File tree

1 file changed

+81
-48
lines changed

1 file changed

+81
-48
lines changed

src/vm.c

Lines changed: 81 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,7 @@ SgObject Sg_VMEnvironment(SgObject lib, SgObject spec)
957957
}
958958

959959
static void print_frames(SgVM *vm, SgContFrame *cont);
960+
static void print_prompts(SgVM *vm, SgPromptNode *node);
960961
static void expand_stack(SgVM *vm);
961962

962963
/* it does not improve performance */
@@ -1580,8 +1581,9 @@ static SgObject capture_prompt_winders(SgPrompt *, SgObject);
15801581

15811582
/* Forward declarations for delimited call/cc support */
15821583
static SgPrompt *make_prompt(SgObject tag, SgObject handler, SgVM *vm);
1583-
static void install_prompt(SgVM *vm, SgPrompt *prompt);
1584-
static void remove_prompt(SgVM *vm, SgPrompt *prompt);
1584+
static void install_prompt(SgVM *, SgPrompt *);
1585+
static void remove_prompt(SgVM *, SgPrompt *);
1586+
static SgPromptNode * remove_prompts(SgVM *, SgObject);
15851587
static SgObject abort_body(SgPromptNode *node, SgObject winders, SgObject args);
15861588

15871589
static SgObject throw_delimited_continuation_body(SgObject,
@@ -1807,6 +1809,7 @@ static SgObject throw_cont_compute_handlers(SgContinuation *c,
18071809
SG_APPEND1(h, t, Sg_Cons(SG_CDAR(p), SG_CDR(p)));
18081810
}
18091811
}
1812+
18101813
SG_FOR_EACH(p, target) {
18111814
SgObject chain = Sg_Memq(SG_CAR(p), escapes);
18121815
SgObject next_winders = SG_CDR(chain);
@@ -1846,17 +1849,18 @@ static SgObject throw_continuation(SgObject *argv, int argc, void *data)
18461849
save_cont(vm);
18471850
}
18481851
if (c->type == SG_DELIMIETED_CONTINUATION) {
1852+
/* here we emulate abort/cc */
18491853
SgContinuation abort_c;
18501854
SgPromptNode *node = search_prompt_node_by_tag(vm, prompt->tag);
18511855
abort_c.winders = node->prompt->winders;
1852-
abort_c.cstack = node->prompt->cstack; /* Non-null to enable post-thunks */
1853-
abort_c.cont = NULL;
1854-
abort_c.prev = NULL;
1855-
abort_c.ehandler = SG_FALSE;
1856+
abort_c.cstack = node->prompt->cstack;
18561857
handlers = throw_cont_compute_handlers(&abort_c, node->prompt, vm);
18571858
return throw_delimited_continuation_body(handlers, c, argv[0], prompt);
18581859
} else {
18591860
handlers = throw_cont_compute_handlers(c, prompt, vm);
1861+
/* Sg_Printf(Sg_StandardErrorPort(), UC("comp: vm->dw: %A\n"), vm->dynamicWinders); */
1862+
/* Sg_Printf(Sg_StandardErrorPort(), UC("comp: c->dw: %A\n"), c->winders); */
1863+
/* Sg_Printf(Sg_StandardErrorPort(), UC("comp: hndlrs: %A\n"), handlers); */
18601864
return throw_continuation_body(handlers, c, argv[0], prompt);
18611865
}
18621866
}
@@ -1959,8 +1963,7 @@ static SgObject throw_delimited_continuation_body(SgObject handlers,
19591963
SgObject args,
19601964
SgPrompt *prompt)
19611965
{
1962-
SgVM *vm = Sg_VM();
1963-
1966+
SgVM *vm = theVM;
19641967
/* Process abort handlers (post-thunks for unwinding) */
19651968
if (SG_PAIRP(handlers)) {
19661969
SgObject handler, chain;
@@ -1982,52 +1985,67 @@ static SgObject throw_delimited_continuation_body(SgObject handlers,
19821985
2. Compute wind-in handlers (pre-thunks) to restore the continuation's
19831986
dynamic extent
19841987
3. Run those handlers, then apply the continuation */
1985-
1986-
SgPrompt *new_prompt;
1987-
SgPromptNode *node = search_prompt_node_by_tag(vm, prompt->tag);
1988-
1988+
SgPromptNode *node = remove_prompts(vm, prompt->tag);
19891989
if (!node) {
19901990
Sg_Error(UC("Stale prompt in delimited continuation: %S"), prompt->tag);
19911991
}
19921992

1993-
/* Pop continuation frames up to and including the prompt frame */
1994-
SgContFrame *cont_frame = vm->cont;
1995-
while (!cont_prompt_match_p(cont_frame, node->prompt)) {
1996-
if (PROMPT_FRAME_MARK_P(cont_frame)) {
1997-
remove_prompt(vm, (SgPrompt *)cont_frame->pc);
1998-
}
1999-
cont_frame = cont_frame->prev;
2000-
}
2001-
20021993
/* Remove the original prompt and set continuation to just before
20031994
the prompt */
20041995
remove_prompt(vm, node->prompt);
20051996
vm->cont = node->frame->prev;
2006-
1997+
20071998
/* Create a new prompt for the continuation */
2008-
new_prompt = make_prompt(prompt->tag, SG_FALSE, vm);
1999+
SgPrompt *new_prompt = make_prompt(prompt->tag, SG_FALSE, vm);
20092000

20102001
CHECK_STACK(CONT_FRAME_SIZE, vm);
20112002
PUSH_PROMPT_CONT(vm, new_prompt);
20122003
install_prompt(vm, new_prompt);
2013-
2004+
20142005
/* Now compute and run wind-in handlers using the composable
20152006
continuation path. We've already aborted to the prompt, so
20162007
current vm->dynamicWinders is at the prompt's level. We need to
20172008
wind into c's winders. */
20182009
SgObject wind_handlers = throw_cont_compute_handlers(c, prompt, vm);
2010+
2011+
/* Sg_Printf(Sg_StandardErrorPort(), UC("delim: vm->dw: %A\n"), vm->dynamicWinders); */
2012+
/* Sg_Printf(Sg_StandardErrorPort(), UC("delim: c->dw: %A\n"), c->winders); */
2013+
/* Sg_Printf(Sg_StandardErrorPort(), UC("delim: hndlrs: %A\n"), wind_handlers); */
2014+
20192015
/* Use the regular composable continuation body to process these handlers */
20202016
return throw_continuation_body(wind_handlers, c, args, prompt);
20212017
}
20222018
}
20232019

2020+
/* Strip the delimited cc handlers.
2021+
If the cont frame is captured, then the captured frame may contain
2022+
outside of the prompt chain.
2023+
The VM dynamicWinders should contain only the prompt winders,
2024+
so the handler is not in the winders, we should strip it.
2025+
*/
2026+
static SgObject strip_delimied_cc_handlers(SgObject handlers)
2027+
{
2028+
SgVM *vm = theVM;
2029+
while (!SG_NULLP(handlers)) {
2030+
SgObject handler = SG_CAAR(handlers);
2031+
SgObject cp;
2032+
SG_FOR_EACH(cp, vm->dynamicWinders) {
2033+
if (SG_EQ(SG_CAAR(cp), handler) || SG_EQ(SG_CDAR(cp), handler)) goto end;
2034+
}
2035+
handlers = SG_CDR(handlers);
2036+
}
2037+
end:
2038+
return handlers;
2039+
}
2040+
20242041
static SgObject throw_delimited_continuation_cc(SgObject result, void **data)
20252042
{
20262043
SgObject handlers = SG_OBJ(data[0]);
20272044
SgContinuation *c = (SgContinuation*)data[1];
20282045
SgObject args = SG_OBJ(data[2]);
20292046
SgPrompt *prompt = (SgPrompt*)data[3];
2030-
return throw_delimited_continuation_body(handlers, c, args, prompt);
2047+
return throw_delimited_continuation_body(strip_delimied_cc_handlers(handlers),
2048+
c, args, prompt);
20312049
}
20322050

20332051
/* call-with-current-continuation with prompt delimiting (Racket-like call/cc) */
@@ -2043,10 +2061,10 @@ SgObject Sg_VMCallDelimitedCC(SgObject proc, SgObject tag)
20432061
save_cont(vm);
20442062

20452063
cont = SG_NEW(SgContinuation);
2046-
/* Use capture_prompt_winders to only include winders installed AFTER the prompt.
2047-
Unlike take_prompt_winders which returns a tail, this returns a NEW list
2048-
containing only the winders not in prompt->winders, stopping at the first
2049-
common winder. */
2064+
/* Use capture_prompt_winders to only include winders installed
2065+
AFTER the prompt. Unlike take_prompt_winders which returns a
2066+
tail, this returns a NEW list containing only the winders not in
2067+
prompt->winders, stopping at the first common winder. */
20502068
cont->winders = capture_prompt_winders(node->prompt, vm->dynamicWinders);
20512069
cont->cont = vm->cont;
20522070
cont->prev = NULL;
@@ -2104,6 +2122,22 @@ static void remove_prompt(SgVM *vm, SgPrompt *prompt)
21042122
}
21052123
}
21062124

2125+
/* remove prompts up to the tag */
2126+
static SgPromptNode * remove_prompts(SgVM *vm, SgObject tag)
2127+
{
2128+
SgPromptNode *cur_node = search_prompt_node_by_tag(vm, tag);
2129+
if (!cur_node) return NULL;
2130+
SgPrompt *prompt = cur_node->prompt;
2131+
SgContFrame *cont = vm->cont;
2132+
2133+
/* remove the prompt in the aborting cont frame from the chain */
2134+
while (!cont_prompt_match_p(cont, prompt)) {
2135+
if (PROMPT_FRAME_MARK_P(cont)) remove_prompt(vm, (SgPrompt *)cont->pc);
2136+
cont = cont->prev;
2137+
}
2138+
return cur_node;
2139+
}
2140+
21072141
SgObject Sg_VMCallCP(SgObject proc, SgObject tag,
21082142
SgObject handler, SgObject args)
21092143
{
@@ -2623,16 +2657,10 @@ static SgObject abort_body(SgPromptNode *node, SgObject winders, SgObject args)
26232657
NOTE: when this abort_cc frame is captured in a continuation,
26242658
the captured node is not loger valid.
26252659
*/
2626-
SgPromptNode *cur_node = search_prompt_node_by_tag(vm, node->prompt->tag);
2660+
SgPromptNode *cur_node = remove_prompts(vm, node->prompt->tag);
26272661
if (!cur_node) Sg_Error(UC("Stale prompt: %S"), node->prompt->tag);
26282662
SgPrompt *prompt = cur_node->prompt;
2629-
SgContFrame *cont = vm->cont;
26302663

2631-
/* remove the prompt in the aborting cont frame from the chain */
2632-
while (!cont_prompt_match_p(cont, prompt)) {
2633-
if (PROMPT_FRAME_MARK_P(cont)) remove_prompt(vm, (SgPrompt *)cont->pc);
2634-
cont = cont->prev;
2635-
}
26362664
if (prompt->cstack != vm->cstack) {
26372665
vm->escapeReason = SG_VM_ESCAPE_ABORT;
26382666
vm->escapeData[0] = cur_node;
@@ -3150,6 +3178,22 @@ static SgContFrame * print_cont1(SgContFrame *cont, SgVM *vm)
31503178
return cont->prev;
31513179
}
31523180

3181+
static void print_prompts(SgVM *vm, SgPromptNode *node)
3182+
{
3183+
if (node) {
3184+
Sg_Printf(vm->logPort, UC(";; Prompt chain\n"));
3185+
Sg_Printf(vm->logPort, UC(";; [%S:%S %p]"),
3186+
node->prompt->tag, node->prompt->handler, node->prompt);
3187+
node = node->next;
3188+
while (node) {
3189+
Sg_Printf(vm->logPort, UC(" => [%S:%S %p]"),
3190+
node->prompt->tag, node->prompt->handler, node->prompt);
3191+
node = node->next;
3192+
}
3193+
Sg_Printf(vm->logPort, UC("\n"));
3194+
}
3195+
}
3196+
31533197
static void print_frames(SgVM *vm, SgContFrame *cont)
31543198
{
31553199
SgObject *stack = vm->stack, *sp = SP(vm);
@@ -3172,18 +3216,7 @@ static void print_frames(SgVM *vm, SgContFrame *cont)
31723216
UC(";; %p +---------------------------------------------+ < bottom\n"),
31733217
stack);
31743218

3175-
if (node) {
3176-
Sg_Printf(vm->logPort, UC(";; Prompt chain\n"));
3177-
Sg_Printf(vm->logPort, UC(";; [%S:%S %p]"),
3178-
node->prompt->tag, node->prompt->handler, node->prompt);
3179-
node = node->next;
3180-
while (node) {
3181-
Sg_Printf(vm->logPort, UC(" => [%S:%S %p]"),
3182-
node->prompt->tag, node->prompt->handler, node->prompt);
3183-
node = node->next;
3184-
}
3185-
Sg_Printf(vm->logPort, UC("\n"));
3186-
}
3219+
print_prompts(vm, node);
31873220

31883221
}
31893222

0 commit comments

Comments
 (0)