This patch re-implements the register backing stacks as PObjs (so they
can be garbage-collected), honors their COW flags, and adds them to the
interpreter context (where they should be, honest!).

As a healthy side-effect, it encapsulates their behavior nicely into
register.c, when before their guts were splattered all over the source.

Luke

Index: classes/continuation.pmc
===================================================================
RCS file: /cvs/public/parrot/classes/continuation.pmc,v
retrieving revision 1.17
diff -u -r1.17 continuation.pmc
--- classes/continuation.pmc    19 Dec 2003 10:01:36 -0000      1.17
+++ classes/continuation.pmc    8 Jan 2004 03:04:01 -0000
@@ -26,8 +26,7 @@
     void mark () {
         struct Parrot_Sub * cc
             = (struct Parrot_Sub*)PMC_sub(SELF);
-       mark_stack(INTERP, cc->ctx.user_stack);
-       mark_stack(INTERP, cc->ctx.control_stack);
+        mark_context(INTERP, &cc->ctx);
        SUPER();        /* mark pad_stack, warns in closure */
     }
 
Index: imcc/t/syn/pcc.t
===================================================================
RCS file: /cvs/public/parrot/imcc/t/syn/pcc.t,v
retrieving revision 1.28
diff -u -r1.28 pcc.t
--- imcc/t/syn/pcc.t    16 Dec 2003 08:53:44 -0000      1.28
+++ imcc/t/syn/pcc.t    8 Jan 2004 03:04:01 -0000
@@ -738,7 +738,7 @@
 .pcc_sub _sub1 non_prototyped
     .local pmc res1               # (visitReturn:528)
     find_lex $P2, 'g'             # (callingExpression:325)
-    newsub $P3, .Continuation, ret0 # (callingExpression:331)
+    newsub $P3, .RetContinuation, ret0 # (callingExpression:331)
     .pcc_begin non_prototyped     # (callingExpression:332)
     .pcc_call $P2, $P3            # (callingExpression:335)
 ret0:
Index: include/parrot/interpreter.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/interpreter.h,v
retrieving revision 1.114
diff -u -r1.114 interpreter.h
--- include/parrot/interpreter.h        2 Jan 2004 14:09:32 -0000       1.114
+++ include/parrot/interpreter.h        8 Jan 2004 03:04:01 -0000
@@ -125,12 +125,10 @@
 struct _imc_info_t;
 
 typedef struct Parrot_Context {
-    struct IRegChunk *int_reg_top;    /* Current top chunk of int reg stack */
-    struct NRegChunk *num_reg_top;    /* Current top chunk of the float reg
-                                       * stack */
-    struct SRegChunk *string_reg_top; /* Current top chunk of the string
-                                       * stack */
-    struct PRegChunk *pmc_reg_top;    /* Current top chunk of the PMC stack */
+    struct RegStack int_reg_stack;
+    struct RegStack num_reg_stack;
+    struct RegStack string_reg_stack;
+    struct RegStack pmc_reg_stack;
 
     struct Stack_Chunk *pad_stack;      /* Base of the lex pad stack */
     struct Stack_Chunk *user_stack;     /* Base of the scratch stack */
Index: include/parrot/register.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/register.h,v
retrieving revision 1.17
diff -u -r1.17 register.h
--- include/parrot/register.h   21 Jul 2003 18:00:42 -0000      1.17
+++ include/parrot/register.h   8 Jan 2004 03:04:01 -0000
@@ -48,38 +48,43 @@
     PMC *registers[NUM_REGISTERS/2];
 };
 
-struct IRegChunk {
+struct RegStack {
+    struct RegisterChunkBuf* top;
+    size_t chunk_size;
+};
+
+/* Base class for the RegChunk types */
+struct RegisterChunkBuf {
+    Buffer data;
     size_t used;
-    Stack_chunk_flags flags;
-    struct IRegChunk *next;
-    struct IRegChunk *prev;
+    struct RegisterChunkBuf* next;
+};
+
+struct IRegChunkBuf {
     struct IRegFrame IRegFrame[FRAMES_PER_CHUNK];
 };
 
-struct NRegChunk {
-    size_t used;
-    Stack_chunk_flags flags;
-    struct NRegChunk *next;
-    struct NRegChunk *prev;
+struct NRegChunkBuf {
     struct NRegFrame NRegFrame[FRAMES_PER_CHUNK];
 };
 
-struct SRegChunk {
-    size_t used;
-    Stack_chunk_flags flags;
-    struct SRegChunk *next;
-    struct SRegChunk *prev;
+struct SRegChunkBuf {
     struct SRegFrame SRegFrame[FRAMES_PER_CHUNK];
 };
 
-struct PRegChunk {
-    size_t used;
-    Stack_chunk_flags flags;
-    struct PRegChunk *next;
-    struct PRegChunk *prev;
+struct PRegChunkBuf {
     struct PRegFrame PRegFrame[FRAMES_PER_CHUNK];
 };
 
+void setup_register_stacks(struct Parrot_Interp* interpreter);
+void mark_register_stack_cow(struct Parrot_Interp* interpreter,
+                             struct RegStack* stack);
+void mark_pmc_register_stack(struct Parrot_Interp* interpreter, 
+                             struct RegStack* stack);
+void mark_string_register_stack(struct Parrot_Interp* interpreter,
+                                struct RegStack* stack);
+void mark_register_stack(struct Parrot_Interp* interpreter,
+                         struct RegStack* stack);
 
 #endif /* PARROT_REGISTER_H */
 
Index: include/parrot/sub.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/sub.h,v
retrieving revision 1.25
diff -u -r1.25 sub.h
--- include/parrot/sub.h        2 Oct 2003 07:41:55 -0000       1.25
+++ include/parrot/sub.h        8 Jan 2004 03:04:01 -0000
@@ -59,6 +59,7 @@
 void cow_copy_context(struct Parrot_Interp* , struct Parrot_Context *);
 void swap_context(struct Parrot_Interp *, PMC *);
 void restore_context(struct Parrot_Interp *, struct Parrot_Context *);
+void mark_context(struct Parrot_Interp *, struct Parrot_Context *);
 
 PMC * scratchpad_new(struct Parrot_Interp * interp, PMC * base, INTVAL depth);
 
Index: src/debug.c
===================================================================
RCS file: /cvs/public/parrot/src/debug.c,v
retrieving revision 1.117
diff -u -r1.117 debug.c
--- src/debug.c 5 Jan 2004 14:44:52 -0000       1.117
+++ src/debug.c 8 Jan 2004 03:04:02 -0000
@@ -1808,9 +1808,10 @@
 PDB_print_stack_int(struct Parrot_Interp *interpreter, const char *command)
 {
     unsigned long depth = 0, i = 0;
-    struct IRegChunk *chunk = interpreter->ctx.int_reg_top;
+    struct RegisterChunkBuf *chunk = interpreter->ctx.int_reg_stack.top;
 
-    valid_chunk(chunk, command, depth, FRAMES_PER_INT_REG_CHUNK, i);
+    valid_chunk(chunk, command, depth, 
+                FRAMES_PER_INT_REG_CHUNK, i);
 
     if (!chunk) {
         i = depth / FRAMES_PER_INT_REG_CHUNK;
@@ -1822,8 +1823,9 @@
                 i, depth);
 
     na(command);
-    PDB_print_int_frame(interpreter, &chunk->IRegFrame[depth],
-            atoi(command));
+    PDB_print_int_frame(interpreter, 
+                &((struct IRegChunkBuf*)chunk->data.bufstart)->IRegFrame[depth], 
+                atoi(command));
 }
 
 /* PDB_print_stack_num
@@ -1833,9 +1835,10 @@
 PDB_print_stack_num(struct Parrot_Interp *interpreter, const char *command)
 {
     unsigned long depth = 0, i = 0;
-    struct NRegChunk *chunk = interpreter->ctx.num_reg_top;
+    struct RegisterChunkBuf *chunk = interpreter->ctx.num_reg_stack.top;
 
-    valid_chunk(chunk, command, depth, FRAMES_PER_NUM_REG_CHUNK, i);
+    valid_chunk(chunk, command, depth, 
+                FRAMES_PER_NUM_REG_CHUNK, i);
 
     if (!chunk) {
         i = depth / FRAMES_PER_NUM_REG_CHUNK;
@@ -1846,8 +1849,9 @@
     PIO_eprintf(interpreter, "Float stack, frame %li, depth %li\n", i, depth);
 
     na(command);
-    PDB_print_num_frame(interpreter, &chunk->NRegFrame[depth],
-            atoi(command));
+    PDB_print_num_frame(interpreter, 
+                &((struct NRegChunkBuf*)chunk->data.bufstart)->NRegFrame[depth],
+                atoi(command));
 }
 
 /* PDB_print_stack_string
@@ -1857,9 +1861,10 @@
 PDB_print_stack_string(struct Parrot_Interp *interpreter, const char *command)
 {
     unsigned long depth = 0, i = 0;
-    struct SRegChunk *chunk = interpreter->ctx.string_reg_top;
+    struct RegisterChunkBuf *chunk = interpreter->ctx.string_reg_stack.top;
 
-    valid_chunk(chunk, command, depth, FRAMES_PER_STR_REG_CHUNK, i);
+    valid_chunk(chunk, command, depth, 
+                FRAMES_PER_STR_REG_CHUNK, i);
 
     if (!chunk) {
         i = depth / FRAMES_PER_STR_REG_CHUNK;
@@ -1871,8 +1876,9 @@
                 i, depth);
 
     na(command);
-    PDB_print_string_frame(interpreter, &chunk->SRegFrame[depth],
-            atoi(command));
+    PDB_print_string_frame(interpreter, 
+                &((struct SRegChunkBuf*)chunk->data.bufstart)->SRegFrame[depth],
+                atoi(command));
 }
 
 /* PDB_print_stack_pmc
@@ -1882,9 +1888,10 @@
 PDB_print_stack_pmc(struct Parrot_Interp *interpreter, const char *command)
 {
     unsigned long depth = 0, i = 0;
-    struct PRegChunk *chunk = interpreter->ctx.pmc_reg_top;
+    struct RegisterChunkBuf *chunk = interpreter->ctx.pmc_reg_stack.top;
 
-    valid_chunk(chunk, command, depth, FRAMES_PER_PMC_REG_CHUNK, i);
+    valid_chunk(chunk, command, depth, 
+                FRAMES_PER_PMC_REG_CHUNK, i);
 
     if (!chunk) {
         i = depth / FRAMES_PER_PMC_REG_CHUNK;
@@ -1895,8 +1902,9 @@
     PIO_eprintf(interpreter, "PMC stack, frame %li, depth %li\n", i, depth);
 
     na(command);
-    PDB_print_pmc_frame(interpreter, &chunk->PRegFrame[depth],
-            atoi(command), NULL);
+    PDB_print_pmc_frame(interpreter, 
+                &((struct PRegChunkBuf*)chunk->data.bufstart)->PRegFrame[depth],
+                atoi(command), NULL);
 }
 
 static void
Index: src/dod.c
===================================================================
RCS file: /cvs/public/parrot/src/dod.c,v
retrieving revision 1.78
diff -u -r1.78 dod.c
--- src/dod.c   2 Jan 2004 14:09:38 -0000       1.78
+++ src/dod.c   8 Jan 2004 03:04:02 -0000
@@ -130,7 +130,6 @@
      * note: adding locals here did cause increased DOD runs
      */
     unsigned int i = 0, j = 0;
-    struct PRegChunk *cur_chunk = 0;
     struct Stash *stash = 0;
 
     /* We have to start somewhere, the interpreter globals is a good place */
@@ -162,31 +161,8 @@
     if (interpreter->DOD_registry)
         pobject_lives(interpreter, (PObj *)interpreter->DOD_registry);
 
-    /* Now walk the pmc stack. Make sure to walk from top down since stack may
-     * have segments above top that we shouldn't walk. */
-    for (cur_chunk = interpreter->ctx.pmc_reg_top; cur_chunk;
-            cur_chunk = cur_chunk->prev) {
-        for (j = 0; j < cur_chunk->used; j++) {
-            for (i = 0; i < NUM_REGISTERS/2; i++) {
-                if (cur_chunk->PRegFrame[j].registers[i]) {
-                    pobject_lives(interpreter,
-                            (PObj *)cur_chunk->PRegFrame[j].registers[i]);
-                }
-            }
-        }
-    }
-
-    /* Walk all stacks: lexical pad, user and control */
-    {
-        Stack_Chunk_t *stacks[3];
-
-        stacks[0] = interpreter->ctx.pad_stack;
-        stacks[1] = interpreter->ctx.user_stack;
-        stacks[2] = interpreter->ctx.control_stack;
-        for (j = 0; j < 3; j++)
-            mark_stack(interpreter, stacks[j]);
-
-    }
+    /* Walk all stacks */
+    mark_context(interpreter, &interpreter->ctx);
 
     /* Walk the iodata */
     Parrot_IOData_mark(interpreter, interpreter->piodata);
@@ -262,7 +238,6 @@
 trace_active_buffers(struct Parrot_Interp *interpreter)
 {
     UINTVAL i, j;
-    struct SRegChunk *cur_chunk;
 
     /* First mark the current set. We assume that all pointers in S registers
      * are pointing to valid buffers. This is not a good assumption, but it'll
@@ -279,20 +254,6 @@
         pobject_lives(interpreter, (PObj *)interpreter->current_file);
     if (interpreter->current_package)
         pobject_lives(interpreter, (PObj *)interpreter->current_package);
-
-    /* Now walk the string stack. Make sure to walk from top down since stack
-     * may have segments above top that we shouldn't walk. */
-    for (cur_chunk = interpreter->ctx.string_reg_top;
-            cur_chunk; cur_chunk = cur_chunk->prev) {
-        for (j = 0; j < cur_chunk->used; j++) {
-            for (i = 0; i < NUM_REGISTERS/2; i++) {
-                Buffer *reg = (Buffer *)cur_chunk->SRegFrame[j].registers[i];
-
-                if (reg)
-                    pobject_lives(interpreter, reg);
-            }
-        }
-    }
 }
 
 #ifdef GC_IS_MALLOC
Index: src/interpreter.c
===================================================================
RCS file: /cvs/public/parrot/src/interpreter.c,v
retrieving revision 1.252
diff -u -r1.252 interpreter.c
--- src/interpreter.c   2 Jan 2004 14:09:38 -0000       1.252
+++ src/interpreter.c   8 Jan 2004 03:04:02 -0000
@@ -995,14 +995,7 @@
     PARROT_WARNINGS_off(interpreter, PARROT_WARNINGS_ALL_FLAG);
 
     /* Set up the initial register chunks */
-    interpreter->ctx.int_reg_top =
-        mem_sys_allocate_zeroed(sizeof(struct IRegChunk));
-    interpreter->ctx.num_reg_top =
-        mem_sys_allocate_zeroed(sizeof(struct NRegChunk));
-    interpreter->ctx.string_reg_top =
-        mem_sys_allocate_zeroed(sizeof(struct SRegChunk));
-    interpreter->ctx.pmc_reg_top =
-        mem_sys_allocate_zeroed(sizeof(struct PRegChunk));
+    setup_register_stacks(interpreter);
 
     /* the SET_NULL macros are only for systems where a NULL pointer
      * isn't represented by zeroes, so don't use these for resetting
@@ -1172,24 +1165,6 @@
 
     /* deinit op_lib */
     (void) PARROT_CORE_OPLIB_INIT(0);
-
-    /* XXX move this to register.c */
-    {
-        struct IRegChunk *stacks[4];
-        struct IRegChunk *top, *next;
-        stacks[0] = interpreter->ctx.int_reg_top;
-        stacks[1] = (struct IRegChunk*) interpreter->ctx.num_reg_top;
-        stacks[2] = (struct IRegChunk*) interpreter->ctx.string_reg_top;
-        stacks[3] = (struct IRegChunk*) interpreter->ctx.pmc_reg_top;
-        for (i = 0; i< 4; i++) {
-            top = stacks[i];
-            for (; top ; ) {
-                next = top->next;
-                mem_sys_free(top);
-                top = next;
-            }
-        }
-    }
 
     stack_destroy(interpreter->ctx.pad_stack);
     stack_destroy(interpreter->ctx.user_stack);
Index: src/register.c
===================================================================
RCS file: /cvs/public/parrot/src/register.c,v
retrieving revision 1.34
diff -u -r1.34 register.c
--- src/register.c      28 Oct 2003 03:13:06 -0000      1.34
+++ src/register.c      8 Jan 2004 03:04:02 -0000
@@ -12,62 +12,187 @@
 
 #include "parrot/parrot.h"
 
-/*=for api register Parrot_push_i
-  pushes a new integer register frame onto the corresponding frame stack
-*/
 void
-Parrot_push_i(struct Parrot_Interp *interpreter, void *where)
+setup_register_stacks(struct Parrot_Interp* interpreter)
+{
+    struct RegisterChunkBuf* buf;
+    make_bufferlike_pool(interpreter, sizeof(struct RegisterChunkBuf));
+
+    Parrot_block_DOD(interpreter);
+
+    buf = new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf));
+    Parrot_allocate_zeroed(interpreter, (PObj*)buf, sizeof(struct IRegChunkBuf));
+    interpreter->ctx.int_reg_stack.top = buf;
+    interpreter->ctx.int_reg_stack.chunk_size = sizeof(struct IRegChunkBuf);
+    
+    buf = new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf));
+    Parrot_allocate_zeroed(interpreter, (PObj*)buf, sizeof(struct SRegChunkBuf));
+    interpreter->ctx.string_reg_stack.top = buf;
+    interpreter->ctx.string_reg_stack.chunk_size = sizeof(struct SRegChunkBuf);
+    
+    buf = new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf));
+    Parrot_allocate_zeroed(interpreter, (PObj*)buf, sizeof(struct NRegChunkBuf));
+    interpreter->ctx.num_reg_stack.top = buf;
+    interpreter->ctx.num_reg_stack.chunk_size = sizeof(struct NRegChunkBuf);
+    
+    buf = new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf));
+    Parrot_allocate_zeroed(interpreter, (PObj*)buf, sizeof(struct PRegChunkBuf));
+    interpreter->ctx.pmc_reg_stack.top = buf;
+    interpreter->ctx.pmc_reg_stack.chunk_size = sizeof(struct PRegChunkBuf);
+    
+    Parrot_unblock_DOD(interpreter);
+}
+
+void
+mark_register_stack(struct Parrot_Interp* interpreter, struct RegStack* stack)
+{
+    struct RegisterChunkBuf* chunk;
+    for (chunk = stack->top; chunk; chunk = chunk->next) {
+        pobject_lives(interpreter, (PObj*)chunk);
+    }
+}
+
+void
+mark_pmc_register_stack(struct Parrot_Interp* interpreter, struct RegStack* stack)
+{
+    struct RegisterChunkBuf* chunk;
+    UINTVAL i, j;
+    for (chunk = stack->top; chunk;
+        chunk = chunk->next) {
+        pobject_lives(interpreter, (PObj*)chunk);
+        for (i = 0; i < chunk->used; i++) {
+            for (j = 0; j < NUM_REGISTERS/2; j++) {
+                if (((struct 
PRegChunkBuf*)chunk->data.bufstart)->PRegFrame[i].registers[j]) {
+                    pobject_lives(interpreter,
+                            (PObj*)((struct PRegChunkBuf*)chunk->data.bufstart)->
+                                PRegFrame[i].registers[j]);
+                }
+            }
+        }
+    }
+}
+
+void
+mark_string_register_stack(struct Parrot_Interp* interpreter, struct RegStack* stack)
+{
+    struct RegisterChunkBuf* chunk;
+    UINTVAL i, j;
+    for (chunk = stack->top; chunk; chunk = chunk->next) {
+        pobject_lives(interpreter, (PObj*)chunk);
+        for (i = 0; i < chunk->used; i++) {
+            for (j = 0; j < NUM_REGISTERS/2; j++) {
+                PObj* reg = (PObj*)((struct SRegChunkBuf*)chunk->data.bufstart)->
+                    SRegFrame[i].registers[j];
+                if (reg)
+                    pobject_lives(interpreter, reg);
+            }
+        }
+    }
+}
+
+void
+mark_register_stack_cow(struct Parrot_Interp* interpreter, struct RegStack* stack)
+{
+    struct RegisterChunkBuf* chunk;
+    for (chunk = stack->top; chunk; chunk = chunk->next) {
+        PObj_COW_SET((PObj*)chunk);
+    }
+}
+
+static struct RegisterChunkBuf* 
+regstack_copy_chunk(struct Parrot_Interp* interpreter, 
+                    struct RegisterChunkBuf* chunk,
+                    struct RegStack* stack)
+{
+    struct RegisterChunkBuf* buf = 
+            new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf));
+    *buf = *chunk;
+    
+    Parrot_block_DOD(interpreter);
+    Parrot_allocate_zeroed(interpreter, (PObj*)buf, stack->chunk_size);
+    Parrot_unblock_DOD(interpreter);
+    
+    memcpy(buf->data.bufstart, chunk->data.bufstart, stack->chunk_size);
+    return buf;
+}
+
+static void
+regstack_push_entry(struct Parrot_Interp* interpreter, struct RegStack* stack)
 {
-    /* Do we have any space in the current savestack? If so, memcpy
-     * down */
-    if (interpreter->ctx.int_reg_top->used < FRAMES_PER_CHUNK) {
-        memcpy(&interpreter->ctx.int_reg_top->
-               IRegFrame[interpreter->ctx.int_reg_top->used],
-               where, sizeof(struct IRegFrame));
-        interpreter->ctx.int_reg_top->used++;
+    struct RegisterChunkBuf* top = stack->top;
+    /* Before we change anything, is this a read-only stack? */
+    if (PObj_COW_TEST((PObj*)top))
+        top = stack->top = regstack_copy_chunk(interpreter, top, stack);
+    /* If we can stay in the current frame, we will.  Else make a new chunk */
+    if (top->used < FRAMES_PER_CHUNK) {
+        top->used++;
     }
-    /* Nope, so either move to next stack chunk or grow the stack */
     else {
-        struct IRegChunk *next_chunk;
-        if (interpreter->ctx.int_reg_top->next)
-            next_chunk = interpreter->ctx.int_reg_top->next;
+        struct RegisterChunkBuf* buf = new_bufferlike_header(interpreter, 
+                                sizeof(struct RegisterChunkBuf));
+
+        Parrot_block_DOD(interpreter);
+        Parrot_allocate_zeroed(interpreter, (PObj*)buf, stack->chunk_size);
+        Parrot_unblock_DOD(interpreter);
+        
+        buf->used = 1;
+        buf->next = top;
+
+        stack->top = buf;
+    }
+}
+
+static void
+regstack_pop_entry(struct Parrot_Interp* interpreter, struct RegStack* stack)
+{
+    struct RegisterChunkBuf* top = stack->top;
+    if (top->used > 1) {
+        /* Before we change anything, is this a read-only stack? */
+        if (PObj_COW_TEST((PObj*)top))
+            top = stack->top = regstack_copy_chunk(interpreter, stack->top, stack);
+        top->used--;
+    }
+    else {
+        /* XXX: If this isn't marked COW, we should keep it around to
+         * prevent thrashing */
+        if (top->next) {
+            stack->top = top->next;
+        }
         else {
-            next_chunk = mem_sys_allocate(sizeof(struct IRegChunk));
-            next_chunk->next = NULL;
-            next_chunk->prev = interpreter->ctx.int_reg_top;
-            interpreter->ctx.int_reg_top->next = next_chunk;
+            if (PObj_COW_TEST((PObj*)top))
+                top = stack->top = regstack_copy_chunk(interpreter, stack->top, 
stack);
+            top->used--;
         }
-        next_chunk->used = 1;
-        interpreter->ctx.int_reg_top = next_chunk;
-        memcpy(&next_chunk->IRegFrame[0],
-               where, sizeof(struct IRegFrame));
     }
 }
 
+/*=for api register Parrot_push_i
+  pushes a new integer register frame onto the corresponding frame stack
+*/
+void
+Parrot_push_i(struct Parrot_Interp *interpreter, void *where)
+{    
+    struct RegisterChunkBuf* top;
+    regstack_push_entry(interpreter, &interpreter->ctx.int_reg_stack);
+    top = interpreter->ctx.int_reg_stack.top;
+    memcpy(&((struct IRegChunkBuf*)top->data.bufstart)->
+                    IRegFrame[top->used-1].registers,
+           where, sizeof(struct IRegFrame));
+}
+
 /*=for api register Parrot_pop_i
   pops an integer register frame from the corresponding frame stack
 */
 void
 Parrot_pop_i(struct Parrot_Interp *interpreter, void *where)
 {
-    struct IRegChunk *top = interpreter->ctx.int_reg_top;
+    struct RegisterChunkBuf* top = interpreter->ctx.int_reg_stack.top;
     /* Do we even have anything? */
     if (top->used > 0) {
-        top->used--;
-        memcpy(where,
-               &top->IRegFrame[top->used], sizeof(struct IRegFrame));
-        /* Empty? */
-        if (!top->used) {
-            /* Yep, drop down a frame. Maybe */
-            if (top->prev) {
-                /* Keep one stack segment spare to avoid thrashing */
-                if (top->next) {
-                    mem_sys_free(top->next);
-                    top->next = NULL;
-                }
-                interpreter->ctx.int_reg_top = top->prev;
-            }
-        }
+        memcpy(where, 
+               &((struct IRegChunkBuf*)top->data.bufstart)->IRegFrame[top->used-1],
+               sizeof(struct IRegFrame));
+        regstack_pop_entry(interpreter, &interpreter->ctx.int_reg_stack);
     }
     /* Nope. So pitch a fit */
     else {
@@ -92,31 +217,13 @@
 */
 void
 Parrot_push_s(struct Parrot_Interp *interpreter, void *where)
-{
-    /* Do we have any space in the current savestack? If so, memcpy
-     * down */
-    if (interpreter->ctx.string_reg_top->used < FRAMES_PER_CHUNK) {
-        memcpy(&interpreter->ctx.string_reg_top->
-               SRegFrame[interpreter->ctx.string_reg_top->used],
-               where, sizeof(struct SRegFrame));
-        interpreter->ctx.string_reg_top->used++;
-    }
-    /* Nope, so either move to next stack chunk or grow the stack */
-    else {
-        struct SRegChunk *next_chunk;
-        if (interpreter->ctx.string_reg_top->next)
-            next_chunk = interpreter->ctx.string_reg_top->next;
-        else {
-            next_chunk = mem_sys_allocate(sizeof(struct SRegChunk));
-            next_chunk->next = NULL;
-            next_chunk->prev = interpreter->ctx.string_reg_top;
-            interpreter->ctx.string_reg_top->next = next_chunk;
-        }
-        next_chunk->used = 1;
-        interpreter->ctx.string_reg_top = next_chunk;
-        memcpy(&next_chunk->SRegFrame[0],
-               where, sizeof(struct SRegFrame));
-    }
+{    
+    struct RegisterChunkBuf* top;
+    regstack_push_entry(interpreter, &interpreter->ctx.string_reg_stack);
+    top = interpreter->ctx.string_reg_stack.top;
+    memcpy(&((struct SRegChunkBuf*)top->data.bufstart)->
+                    SRegFrame[top->used-1].registers,
+           where, sizeof(struct SRegFrame));
 }
 
 /*=for api register Parrot_pop_s
@@ -125,24 +232,15 @@
 void
 Parrot_pop_s(struct Parrot_Interp *interpreter, void *where)
 {
-    struct SRegChunk *top = interpreter->ctx.string_reg_top;
+    struct RegisterChunkBuf* top = interpreter->ctx.string_reg_stack.top;
     /* Do we even have anything? */
     if (top->used > 0) {
-        top->used--;
-        memcpy(where,
-               &top->SRegFrame[top->used], sizeof(struct SRegFrame));
-        /* Empty? */
-        if (!top->used) {
-            /* Yep, drop down a frame. Maybe */
-            if (top->prev) {
-                /* Keep one stack segment spare to avoid thrashing */
-                if (top->next) {
-                    mem_sys_free(top->next);
-                    top->next = NULL;
-                }
-                interpreter->ctx.string_reg_top = top->prev;
-            }
-        }
+        struct SRegFrame* irf = &((struct SRegChunkBuf*)top->data.bufstart)->
+                    SRegFrame[top->used-1];
+        memcpy(where, 
+               &irf->registers, 
+               sizeof(struct SRegFrame));
+        regstack_pop_entry(interpreter, &interpreter->ctx.string_reg_stack);
     }
     /* Nope. So pitch a fit */
     else {
@@ -167,31 +265,13 @@
 */
 void
 Parrot_push_n(struct Parrot_Interp *interpreter, void *where)
-{
-    /* Do we have any space in the current savestack? If so, memcpy
-     * down */
-    if (interpreter->ctx.num_reg_top->used < FRAMES_PER_CHUNK) {
-        memcpy(&interpreter->ctx.num_reg_top->
-               NRegFrame[interpreter->ctx.num_reg_top->used],
-               where, sizeof(struct NRegFrame));
-        interpreter->ctx.num_reg_top->used++;
-    }
-    /* Nope, so either move to next stack chunk or grow the stack */
-    else {
-        struct NRegChunk *next_chunk;
-        if (interpreter->ctx.num_reg_top->next)
-            next_chunk = interpreter->ctx.num_reg_top->next;
-        else {
-            next_chunk = mem_sys_allocate(sizeof(struct NRegChunk));
-            next_chunk->next = NULL;
-            next_chunk->prev = interpreter->ctx.num_reg_top;
-            interpreter->ctx.num_reg_top->next = next_chunk;
-        }
-        next_chunk->used = 1;
-        interpreter->ctx.num_reg_top = next_chunk;
-        memcpy(&next_chunk->NRegFrame[0],
-               where, sizeof(struct NRegFrame));
-    }
+{    
+    struct RegisterChunkBuf* top;
+    regstack_push_entry(interpreter, &interpreter->ctx.num_reg_stack);
+    top = interpreter->ctx.num_reg_stack.top;
+    memcpy(&((struct NRegChunkBuf*)top->data.bufstart)->
+                    NRegFrame[top->used-1].registers,
+           where, sizeof(struct NRegFrame));
 }
 
 /*=for api register Parrot_pop_n
@@ -200,24 +280,15 @@
 void
 Parrot_pop_n(struct Parrot_Interp *interpreter, void *where)
 {
-    struct NRegChunk *top = interpreter->ctx.num_reg_top;
+    struct RegisterChunkBuf* top = interpreter->ctx.num_reg_stack.top;
     /* Do we even have anything? */
     if (top->used > 0) {
-        top->used--;
-        memcpy(where,
-               &top->NRegFrame[top->used], sizeof(struct NRegFrame));
-        /* Empty? */
-        if (!top->used) {
-            /* Yep, drop down a frame. Maybe */
-            if (top->prev) {
-                /* Keep one stack segment spare to avoid thrashing */
-                if (top->next) {
-                    mem_sys_free(top->next);
-                    top->next = NULL;
-                }
-                interpreter->ctx.num_reg_top = top->prev;
-            }
-        }
+        struct NRegFrame* irf = &((struct NRegChunkBuf*)top->data.bufstart)->
+                    NRegFrame[top->used-1];
+        memcpy(where, 
+               &irf->registers, 
+               sizeof(struct NRegFrame));
+        regstack_pop_entry(interpreter, &interpreter->ctx.num_reg_stack);
     }
     /* Nope. So pitch a fit */
     else {
@@ -242,31 +313,13 @@
 */
 void
 Parrot_push_p(struct Parrot_Interp *interpreter, void *where)
-{
-    /* Do we have any space in the current savestack? If so, memcpy
-     * down */
-    if (interpreter->ctx.pmc_reg_top->used < FRAMES_PER_CHUNK) {
-        memcpy(&interpreter->ctx.pmc_reg_top->
-               PRegFrame[interpreter->ctx.pmc_reg_top->used],
-               where, sizeof(struct PRegFrame));
-        interpreter->ctx.pmc_reg_top->used++;
-    }
-    /* Nope, so either move to next stack chunk or grow the stack */
-    else {
-        struct PRegChunk *next_chunk;
-        if (interpreter->ctx.pmc_reg_top->next)
-            next_chunk = interpreter->ctx.pmc_reg_top->next;
-        else {
-            next_chunk = mem_sys_allocate(sizeof(struct PRegChunk));
-            next_chunk->next = NULL;
-            next_chunk->prev = interpreter->ctx.pmc_reg_top;
-            interpreter->ctx.pmc_reg_top->next = next_chunk;
-        }
-        next_chunk->used = 1;
-        interpreter->ctx.pmc_reg_top = next_chunk;
-        memcpy(&next_chunk->PRegFrame[0],
-               where, sizeof(struct PRegFrame));
-    }
+{    
+    struct RegisterChunkBuf* top;
+    regstack_push_entry(interpreter, &interpreter->ctx.pmc_reg_stack);
+    top = interpreter->ctx.pmc_reg_stack.top;
+    memcpy(&((struct PRegChunkBuf*)top->data.bufstart)->
+                    PRegFrame[top->used-1].registers,
+           where, sizeof(struct PRegFrame));
 }
 
 /*=for api register Parrot_pop_p
@@ -275,24 +328,15 @@
 void
 Parrot_pop_p(struct Parrot_Interp *interpreter, void *where)
 {
-    struct PRegChunk *top = interpreter->ctx.pmc_reg_top;
+    struct RegisterChunkBuf* top = interpreter->ctx.pmc_reg_stack.top;
     /* Do we even have anything? */
     if (top->used > 0) {
-        top->used--;
-        memcpy(where,
-               &top->PRegFrame[top->used], sizeof(struct PRegFrame));
-        /* Empty? */
-        if (!top->used) {
-            /* Yep, drop down a frame. Maybe */
-            if (top->prev) {
-                /* Keep one stack segment spare to avoid thrashing */
-                if (top->next) {
-                    mem_sys_free(top->next);
-                    top->next = NULL;
-                }
-                interpreter->ctx.pmc_reg_top = top->prev;
-            }
-        }
+        struct PRegFrame* irf = &((struct PRegChunkBuf*)top->data.bufstart)->
+                    PRegFrame[top->used-1];
+        memcpy(where, 
+               &irf->registers, 
+               sizeof(struct PRegFrame));
+        regstack_pop_entry(interpreter, &interpreter->ctx.pmc_reg_stack);
     }
     /* Nope. So pitch a fit */
     else {
Index: src/sub.c
===================================================================
RCS file: /cvs/public/parrot/src/sub.c,v
retrieving revision 1.40
diff -u -r1.40 sub.c
--- src/sub.c   25 Oct 2003 06:13:21 -0000      1.40
+++ src/sub.c   8 Jan 2004 03:04:02 -0000
@@ -12,6 +12,7 @@
  */
 
 #include "parrot/parrot.h"
+#include "parrot/method_util.h"
 
 
 /*
@@ -33,6 +34,10 @@
 cow_copy_context(struct Parrot_Interp *interp, struct Parrot_Context *ctx)
 {
     memcpy(ctx, &interp->ctx, sizeof(*ctx));
+    mark_register_stack_cow(interp, &ctx->int_reg_stack);
+    mark_register_stack_cow(interp, &ctx->num_reg_stack);
+    mark_register_stack_cow(interp, &ctx->string_reg_stack);
+    mark_register_stack_cow(interp, &ctx->pmc_reg_stack);
     stack_mark_cow(ctx->pad_stack);
     stack_mark_cow(ctx->user_stack);
     stack_mark_cow(ctx->control_stack);
@@ -46,6 +51,18 @@
 restore_context(struct Parrot_Interp *interp, struct Parrot_Context *ctx)
 {
     memcpy(&interp->ctx, ctx, sizeof(*ctx));
+}
+
+void
+mark_context(struct Parrot_Interp* interpreter, struct Parrot_Context* ctx)
+{
+    mark_stack(interpreter, ctx->pad_stack);
+    mark_stack(interpreter, ctx->user_stack);
+    mark_stack(interpreter, ctx->control_stack);
+    mark_register_stack(interpreter, &ctx->int_reg_stack);
+    mark_register_stack(interpreter, &ctx->num_reg_stack);
+    mark_string_register_stack(interpreter, &ctx->string_reg_stack);
+    mark_pmc_register_stack(interpreter, &ctx->pmc_reg_stack);
 }
 
 static void coro_error(Stack_Entry_t *e)
Index: t/pmc/sub.t
===================================================================
RCS file: /cvs/public/parrot/t/pmc/sub.t,v
retrieving revision 1.31
diff -u -r1.31 sub.t
--- t/pmc/sub.t 4 Dec 2003 10:30:38 -0000       1.31
+++ t/pmc/sub.t 8 Jan 2004 03:04:02 -0000
@@ -1,6 +1,6 @@
 #! perl -w
 
-use Parrot::Test tests => 47;
+use Parrot::Test tests => 49;
 use Test::More;
 use Parrot::Config;
 
@@ -708,6 +708,40 @@
 CODE
 ok 1
 ok 2
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "continuation close over register stacks");
+    set S20, "ok\n"
+    savetop
+    newsub P0, .Continuation, next
+    restoretop
+    concat S20, "not ", S20
+    invoke
+    print "bad\n"
+next:
+    restoretop
+    print S20
+    end
+CODE
+ok
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "DOD marks continuation's register stacks");
+    set S20, "ok\n"
+    savetop
+    newsub P0, .Continuation, next
+    restoretop
+    null S20
+    sweep 1
+    collect
+    invoke
+    print "bad\n"
+next:
+    restoretop
+    print S20
+    end
+CODE
+ok
 OUTPUT
 
 unlink($temp, 'temp.pbc');

Reply via email to