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');