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; }
 

Reply via email to