The good news is that the attached patch makes this work. The bad news is that it also breaks PGE, albeit in a small way. Six of the "<after>" tests (mostly, but not exclusively, involving "<!after>") in t/compilers/pge/p6rules/builtins.t seem to go into an infinite loop. I have been unable to figure this out, so I'm hoping it will be easy for someone who understands PGE. (Maybe there's something in PGE that assumes that returning from a sub restores the state of the user stack?) When (and if) that happens, we can decide whether this patch is worth doing. TIA,
-- Bob Rogers http://rgrjr.dyndns.org/
Index: src/ops/stack.ops =================================================================== --- src/ops/stack.ops (revision 11707) +++ src/ops/stack.ops (working copy) @@ -78,7 +78,7 @@ op entrytype(out INT, in INT) :base_core { Stack_Entry_t *entry; - entry = stack_entry(interpreter, CONTEXT(interpreter->ctx)->user_stack, $2); + entry = stack_entry(interpreter, interpreter->user_stack, $2); if (!entry) { internal_exception(99, "Stack Depth wrong"); } @@ -95,7 +95,7 @@ =cut inline op depth(out INT) :base_core { - $1 = stack_height(interpreter, CONTEXT(interpreter->ctx)->user_stack); + $1 = stack_height(interpreter, interpreter->user_stack); goto NEXT(); } @@ -118,7 +118,7 @@ op lookback(out INT, in INT) :base_core { Stack_Entry_t *entry = - stack_entry(interpreter, CONTEXT(interpreter->ctx)->user_stack, $2); + stack_entry(interpreter, interpreter->user_stack, $2); if (!entry) internal_exception(99, "Stack depth wrong"); if (entry->entry_type != STACK_ENTRY_INT) { @@ -131,7 +131,7 @@ op lookback(out STR, in INT) :base_core { Stack_Entry_t *entry = - stack_entry(interpreter, CONTEXT(interpreter->ctx)->user_stack, $2); + stack_entry(interpreter, interpreter->user_stack, $2); if (!entry) internal_exception(99, "Stack depth wrong"); if (entry->entry_type != STACK_ENTRY_STRING) { @@ -144,7 +144,7 @@ op lookback(out NUM, in INT) :base_core { Stack_Entry_t *entry = - stack_entry(interpreter, CONTEXT(interpreter->ctx)->user_stack, $2); + stack_entry(interpreter, interpreter->user_stack, $2); if (!entry) internal_exception(99, "Stack depth wrong"); if (entry->entry_type != STACK_ENTRY_FLOAT) { @@ -157,7 +157,7 @@ op lookback(out PMC, in INT) :base_core { Stack_Entry_t *entry = - stack_entry(interpreter, CONTEXT(interpreter->ctx)->user_stack, $2); + stack_entry(interpreter, interpreter->user_stack, $2); if (!entry) internal_exception(99, "Stack depth wrong"); if (entry->entry_type != STACK_ENTRY_PMC) { @@ -184,22 +184,22 @@ inline op save(in INT) :base_core { INTVAL i = $1; - stack_push(interpreter, &CONTEXT(interpreter->ctx)->user_stack, &i, STACK_ENTRY_INT, STACK_CLEANUP_NULL); + stack_push(interpreter, &interpreter->user_stack, &i, STACK_ENTRY_INT, STACK_CLEANUP_NULL); goto NEXT(); } inline op save(in NUM) :base_core { - stack_push(interpreter, &CONTEXT(interpreter->ctx)->user_stack, &($1), STACK_ENTRY_FLOAT, STACK_CLEANUP_NULL); + stack_push(interpreter, &interpreter->user_stack, &($1), STACK_ENTRY_FLOAT, STACK_CLEANUP_NULL); goto NEXT(); } inline op save(in PMC) :base_core { - stack_push(interpreter, &CONTEXT(interpreter->ctx)->user_stack, $1, STACK_ENTRY_PMC, STACK_CLEANUP_NULL); + stack_push(interpreter, &interpreter->user_stack, $1, STACK_ENTRY_PMC, STACK_CLEANUP_NULL); goto NEXT(); } inline op save(in STR) :base_core { - stack_push(interpreter, &CONTEXT(interpreter->ctx)->user_stack, $1, STACK_ENTRY_STRING, STACK_CLEANUP_NULL); + stack_push(interpreter, &interpreter->user_stack, $1, STACK_ENTRY_STRING, STACK_CLEANUP_NULL); goto NEXT(); } @@ -212,7 +212,7 @@ =cut inline op savec(in STR) :base_core { - stack_push(interpreter, &CONTEXT(interpreter->ctx)->user_stack, string_copy(interpreter, $1), STACK_ENTRY_STRING, STACK_CLEANUP_NULL); + stack_push(interpreter, &interpreter->user_stack, string_copy(interpreter, $1), STACK_ENTRY_STRING, STACK_CLEANUP_NULL); goto NEXT(); } @@ -231,25 +231,25 @@ =cut inline op restore(out INT) :base_core { - (void)stack_pop(interpreter, &CONTEXT(interpreter->ctx)->user_stack, &($1), + (void)stack_pop(interpreter, &interpreter->user_stack, &($1), STACK_ENTRY_INT); goto NEXT(); } inline op restore(out NUM) :base_core { - (void)stack_pop(interpreter, &CONTEXT(interpreter->ctx)->user_stack, &($1), + (void)stack_pop(interpreter, &interpreter->user_stack, &($1), STACK_ENTRY_FLOAT); goto NEXT(); } inline op restore(out PMC) :base_core { - (void)stack_pop(interpreter, &CONTEXT(interpreter->ctx)->user_stack, &($1), + (void)stack_pop(interpreter, &interpreter->user_stack, &($1), STACK_ENTRY_PMC); goto NEXT(); } inline op restore(out STR) :base_core { - (void)stack_pop(interpreter, &CONTEXT(interpreter->ctx)->user_stack, &($1), + (void)stack_pop(interpreter, &interpreter->user_stack, &($1), STACK_ENTRY_STRING); goto NEXT(); } @@ -269,7 +269,7 @@ =cut inline op rotate_up(in INT) :base_core { - rotate_entries(interpreter, &CONTEXT(interpreter->ctx)->user_stack, $1); + rotate_entries(interpreter, &interpreter->user_stack, $1); goto NEXT(); } Index: src/register.c =================================================================== --- src/register.c (revision 11707) +++ src/register.c (working copy) @@ -233,7 +233,6 @@ /* some items should better be COW copied */ ctx->constants = old->constants; ctx->reg_stack = old->reg_stack; /* XXX move into interpreter? */ - ctx->user_stack = old->user_stack; /* XXX move into interpreter? */ ctx->control_stack = old->control_stack; ctx->warns = old->warns; ctx->errors = old->errors; Index: src/debug.c =================================================================== --- src/debug.c (revision 11707) +++ src/debug.c (working copy) @@ -2098,7 +2098,7 @@ PDB_print_user_stack(Interp *interpreter, const char *command) { long depth = 0; - Stack_Chunk_t *chunk = CONTEXT(interpreter->ctx)->user_stack; + Stack_Chunk_t *chunk = interpreter->user_stack; Stack_Entry_t *entry; if (*command) { Index: src/dod.c =================================================================== --- src/dod.c (revision 11707) +++ src/dod.c (working copy) @@ -296,6 +296,9 @@ ctx = CONTEXT(interpreter->ctx); mark_context(interpreter, ctx); + /* mark the user stack. */ + mark_stack(interpreter, interpreter->user_stack); + /* * mark vtable->data * Index: src/inter_create.c =================================================================== --- src/inter_create.c (revision 11707) +++ src/inter_create.c (working copy) @@ -165,6 +165,9 @@ SET_NULL(interpreter->HLL_info); Parrot_init(interpreter); + /* Need a user stack */ + interpreter->user_stack = new_stack(interpreter, "User"); + /* context data */ /* Initialize interpreter's flags */ PARROT_WARNINGS_off(interpreter, PARROT_WARNINGS_ALL_FLAG); @@ -185,10 +188,7 @@ /* Set up the initial register chunks */ setup_register_stacks(interpreter); - /* Need a user stack */ - CONTEXT(interpreter->ctx)->user_stack = new_stack(interpreter, "User"); - - /* And a control stack */ + /* Need a control stack */ CONTEXT(interpreter->ctx)->control_stack = new_stack(interpreter, "Control"); /* clear context introspection vars */ @@ -392,7 +392,7 @@ /* deinit op_lib */ (void) PARROT_CORE_OPLIB_INIT(0); - stack_destroy(CONTEXT(interpreter->ctx)->user_stack); + stack_destroy(interpreter->user_stack); stack_destroy(CONTEXT(interpreter->ctx)->control_stack); destroy_context(interpreter); Index: src/stacks.c =================================================================== --- src/stacks.c (revision 11707) +++ src/stacks.c (working copy) @@ -150,7 +150,7 @@ /* For negative depths, look from the bottom of the stack up. */ if (depth < 0) { - depth = stack_height(interpreter, CONTEXT(interpreter->ctx)->user_stack) + depth; + depth = stack_height(interpreter, interpreter->user_stack) + depth; if (depth < 0) return NULL; offset = (size_t)depth; Index: src/sub.c =================================================================== --- src/sub.c (revision 11707) +++ src/sub.c (working copy) @@ -38,7 +38,6 @@ PObj *obj; int i; - mark_stack(interpreter, ctx->user_stack); mark_stack(interpreter, ctx->control_stack); mark_register_stack(interpreter, ctx->reg_stack); obj = (PObj*)ctx->current_sub; Index: include/parrot/interpreter.h =================================================================== --- include/parrot/interpreter.h (revision 11707) +++ include/parrot/interpreter.h (working copy) @@ -187,7 +187,6 @@ int ref_count; /* how often refered to */ struct Stack_Chunk *reg_stack; /* register stack */ - struct Stack_Chunk *user_stack; /* Base of the scratch stack */ struct Stack_Chunk *control_stack; /* Base of the flow control stack */ PMC *lex_pad; /* LexPad PMC */ struct Parrot_Context *outer_ctx; /* outer context, if a closure */ @@ -379,6 +378,7 @@ PMC *current_cont; /* the return continuation PMC */ PMC *current_object; /* current object if a method call */ STRING *current_method; /* name of method */ + struct Stack_Chunk *user_stack; /* Base of the scratch stack */ }; /* typedef struct parrot_interp_t Interp; done in parrot.h so that Index: t/op/stacks.t =================================================================== --- t/op/stacks.t (revision 11707) +++ t/op/stacks.t (working copy) @@ -605,9 +605,67 @@ Stack 'Control' too deep OUTPUT } + +pir_output_is(<<'CODE', <<'OUTPUT', "save/restore across contexts [1]"); +.sub main :main + $I0 = 11 + save $I0 + test_1() + restore $I0 + print $I0 + print "\n" +.end +.sub test_1 + save 22 +.end +CODE +22 +OUTPUT + +pir_output_is(<<'CODE', <<'OUTPUT', "save/restore across contexts [2]"); +.sub main :main + $I0 = 11 + save $I0 + inc $I0 + save $I0 + test_1() + restore $I0 + print $I0 + print "\n" +.end +.sub test_1 + restore $I22 +.end +CODE +11 +OUTPUT + +pir_output_is(<<'CODE', <<'OUTPUT', "stack memory use"); +## This does lots of pushes and pops, but should run in constant memory. +.sub main :main + $I0 = 1000000 + $I1 = 0 +push_loop: + inc $I1 + if $I1 >= $I0 goto ok + save $I1 + save $I1 + save $I1 + restore $I2 + restore $I2 + restore $I2 + if $I1 == $I2 goto push_loop + print "not " +ok: + print "ok\n" +.end +CODE +ok +OUTPUT + ############################## ## remember to change the number of tests :-) -BEGIN { plan tests => 24; } +BEGIN { plan tests => 27; }