I did a little benchmark test today that had some enlightening results. I'll explain what my goal was, then show you said results, and finally a patch (not meant to be committed) and the benchmark programs themselves.
I dearly wanted real Continuations to be faster, because I loathe RetContinuations. They suck. Honest. They're of no use as or with continuations -- they do little more than put a return value on the proverbial stack. And they can't be promoted without serious danger of the state being corrupted before this happens. So, I implemented a new register stack scheme without chunks. The register stack is now a linked list of single frames. This has the advantage that you *never* have to copy frames, nor do you have to mess with marking things COW. I figured it would be an improvement. I wrote it using Parrot's default small object allocator for each frame. I ran benchmark_1 (see below), and got these results (or around there, I idiotically didn't keep them around): % time parrot-sync benchmark_1.imc # Parrot from CVS parrot-sync benchmark_1.imc 0.87s user ... % time parrot benchmark_1.imc # My modified version parrot benchmark_1.imc 2.04s user ... Benchmark one is about raw save/restore speed, without respect for anything fancy. This was clearly unacceptable. I doesn't matter how much faster it makes continuations, this large a speed hit can't be compromised. I thought the problem might be in the small object allocator, as I couldn't imagine how the simple algorithms in my modification could possibly take so long. So I wrote my own small object allocator for the register stacks, and got: % time parrot benchmark_1.imc parrot benchmark_1.imc 1.11s user ... Much better. Didn't make me entirely happy, but a great improvement indeed. This could probably be improved with some careful and attentive coding. Here are the times for the other benchmarks: % time parrot-sync benchmark_2.imc parrot-sync benchmark_2.imc 0.78s user ... % time parrot benchmark_2.imc parrot benchmark_2.imc 0.89s user ... Benchmark 2 calls a sub many times, creating a RetContinuation each time. And finally the one with real continuations: % time parrot-sync benchmark_3.imc parrot-sync benchmark_3.imc 1.58s user ... % time parrot benchmark_3.imc parrot benchmark_3.imc 0.45s user ... Benchmark 3 does the same as benchmark 2, except that it creates a real Continuation each time. Note the number of iterations is half that of benchmark 2. Well, I achieved my goal for sure. Side results weren't so great. But the most enlightening thing is how much things improved by writing my own small object allocator -- even a quick and dirty one. Last time I was fishing through that subsystem, it seemed to have a lot of overhead. Are there things about it that require this overhead, or could it take an optimization run brining it near the overhead level of this little one? If so, we might have an opportunity to boost parrot's usual speed by a fine degree. Here are the benchmarks: benchmark_1.imc --------------- .sub _main $I0 = 500000 again: unless $I0 goto quit savetop restoretop dec $I0 goto again quit: end .end benchmark_2.imc --------------- .sub _main $I0 = 100000 newsub P0, .Sub, _other again: unless $I0 goto quit saveall newsub P1, .RetContinuation, back invokecc restoreall dec $I0 goto again quit: end .end .sub _other invoke P1 .end benchmark_3.imc --------------- .sub _main $I0 = 50000 newsub P0, .Sub, _other again: unless $I0 goto quit saveall newsub P1, .Continuation, back invokecc restoreall dec $I0 goto again quit: end .end .sub _other invoke P1 .end And the exemplary patch: Index: config/gen/config_h/config_h.in =================================================================== RCS file: /cvs/public/parrot/config/gen/config_h/config_h.in,v retrieving revision 1.20 diff -u -r1.20 config_h.in --- config/gen/config_h/config_h.in 24 Dec 2003 14:54:16 -0000 1.20 +++ config/gen/config_h/config_h.in 16 Jan 2004 10:08:56 -0000 @@ -100,15 +100,8 @@ /* typedef INTVAL *(*opcode_funcs)(void *, void *) OPFUNC; */ -#define FRAMES_PER_CHUNK 16 - /* Default amount of memory to allocate in one whack */ #define DEFAULT_SIZE 32768 - -#define FRAMES_PER_PMC_REG_CHUNK FRAMES_PER_CHUNK -#define FRAMES_PER_NUM_REG_CHUNK FRAMES_PER_CHUNK -#define FRAMES_PER_INT_REG_CHUNK FRAMES_PER_CHUNK -#define FRAMES_PER_STR_REG_CHUNK FRAMES_PER_CHUNK #define JIT_CPUARCH "${jitcpuarch}" #define JIT_OSNAME "${jitosname}" Index: imcc/pcc.c =================================================================== RCS file: /cvs/public/parrot/imcc/pcc.c,v retrieving revision 1.39 diff -u -r1.39 pcc.c --- imcc/pcc.c 16 Dec 2003 08:53:34 -0000 1.39 +++ imcc/pcc.c 16 Jan 2004 10:08:57 -0000 @@ -995,15 +995,17 @@ /* object: P2 */ #endif /* + * emit a savetop for now + */ + ins = insINS(interp, unit, ins, "savetop", regs, 0); + + /* * if we reuse the continuation, update it */ if (!sub->pcc_sub->nci) if (!need_cc) ins = insINS(interp, unit, ins, "updatecc", regs, 0); - /* - * emit a savetop for now - */ - ins = insINS(interp, unit, ins, "savetop", regs, 0); + ins = insINS(interp, unit, ins, need_cc ? "invokecc" : "invoke", regs, 0); ins->type |= ITPCCSUB; /* Index: include/parrot/debug.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/debug.h,v retrieving revision 1.29 diff -u -r1.29 debug.h --- include/parrot/debug.h 16 Aug 2003 12:41:24 -0000 1.29 +++ include/parrot/debug.h 16 Jan 2004 10:08:57 -0000 @@ -277,15 +277,11 @@ void PDB_help(struct Parrot_Interp *interpreter, const char *command); -#define valid_chunk(chunk,c,d,s,i) { \ - if (*c) { \ - d = atol(c); \ - if (d > s) { \ - i = d / s; \ - d = d % s; \ - while (i-- && chunk) \ - chunk = chunk->next; \ - } \ +#define valid_chunk(chunk,command,i) { \ + if (*command) { \ + i = atol(command); \ + while (i-- && chunk) \ + chunk = chunk->next; \ } \ } Index: include/parrot/register.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/register.h,v retrieving revision 1.18 diff -u -r1.18 register.h --- include/parrot/register.h 12 Jan 2004 09:50:24 -0000 1.18 +++ include/parrot/register.h 16 Jan 2004 10:08:57 -0000 @@ -48,43 +48,58 @@ PMC *registers[NUM_REGISTERS/2]; }; +enum regchunk_type { + int_reg, + num_reg, + string_reg, + pmc_reg +}; + struct RegStack { - struct RegisterChunkBuf* top; size_t chunk_size; + enum regchunk_type type; + struct RegChunk* top; }; -/* Base class for the RegChunk types */ -struct RegisterChunkBuf { - Buffer data; - size_t used; - struct RegisterChunkBuf* next; +struct RegChunk { + UINTVAL refcount; + enum regchunk_type type; + struct RegChunk* next; }; -struct IRegChunkBuf { - struct IRegFrame IRegFrame[FRAMES_PER_CHUNK]; +struct IRegChunk { + struct RegChunk base; + struct IRegFrame IRegFrame; }; -struct NRegChunkBuf { - struct NRegFrame NRegFrame[FRAMES_PER_CHUNK]; +struct NRegChunk { + struct RegChunk base; + struct NRegFrame NRegFrame; }; -struct SRegChunkBuf { - struct SRegFrame SRegFrame[FRAMES_PER_CHUNK]; +struct SRegChunk { + struct RegChunk base; + struct SRegFrame SRegFrame; }; -struct PRegChunkBuf { - struct PRegFrame PRegFrame[FRAMES_PER_CHUNK]; +struct PRegChunk { + struct RegChunk base; + struct PRegFrame PRegFrame; }; -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); +void regstack_setup(struct Parrot_Interp* interpreter); +void regstack_free(struct Parrot_Interp* interpreter, + struct RegChunk* chunk); +void regstack_mark_string(struct Parrot_Interp* interpreter, + struct RegStack* stack); +void regstack_mark_pmc(struct Parrot_Interp* interpreter, + struct RegStack* stack); + +#define REGSTACK_INC_REFCOUNT(chunk) ++chunk->refcount + +#define REGSTACK_DEC_REFCOUNT(chunk) \ + { if (!--chunk->refcount) \ + regstack_free(interpreter, chunk); } #endif /* PARROT_REGISTER_H */ Index: src/debug.c =================================================================== RCS file: /cvs/public/parrot/src/debug.c,v retrieving revision 1.118 diff -u -r1.118 debug.c --- src/debug.c 12 Jan 2004 09:50:26 -0000 1.118 +++ src/debug.c 16 Jan 2004 10:08:58 -0000 @@ -1807,25 +1807,21 @@ void PDB_print_stack_int(struct Parrot_Interp *interpreter, const char *command) { - unsigned long depth = 0, i = 0; - struct RegisterChunkBuf *chunk = interpreter->ctx.int_reg_stack.top; + unsigned long i = 0; + struct RegChunk *chunk = interpreter->ctx.int_reg_stack.top; - valid_chunk(chunk, command, depth, - FRAMES_PER_INT_REG_CHUNK, i); + valid_chunk(chunk, command, i); if (!chunk) { - i = depth / FRAMES_PER_INT_REG_CHUNK; PIO_eprintf(interpreter, "There are only %li frames\n",i); return; } - PIO_eprintf(interpreter, "Integer stack, frame %li, depth %li\n", - i, depth); + PIO_eprintf(interpreter, "Integer stack, frame %li\n",i); na(command); - PDB_print_int_frame(interpreter, - &((struct IRegChunkBuf*)chunk->data.bufstart)->IRegFrame[depth], - atoi(command)); + PDB_print_int_frame(interpreter, &((struct IRegChunk*)chunk)->IRegFrame, + atoi(command)); } /* PDB_print_stack_num @@ -1834,24 +1830,21 @@ void PDB_print_stack_num(struct Parrot_Interp *interpreter, const char *command) { - unsigned long depth = 0, i = 0; - struct RegisterChunkBuf *chunk = interpreter->ctx.num_reg_stack.top; + unsigned long i = 0; + struct RegChunk *chunk = interpreter->ctx.num_reg_stack.top; - valid_chunk(chunk, command, depth, - FRAMES_PER_NUM_REG_CHUNK, i); + valid_chunk(chunk, command, i); if (!chunk) { - i = depth / FRAMES_PER_NUM_REG_CHUNK; PIO_eprintf(interpreter, "There are only %li frames\n",i); return; } - PIO_eprintf(interpreter, "Float stack, frame %li, depth %li\n", i, depth); + PIO_eprintf(interpreter, "Integer stack, frame %li\n",i); na(command); - PDB_print_num_frame(interpreter, - &((struct NRegChunkBuf*)chunk->data.bufstart)->NRegFrame[depth], - atoi(command)); + PDB_print_num_frame(interpreter, &((struct NRegChunk*)chunk)->NRegFrame, + atoi(command)); } /* PDB_print_stack_string @@ -1860,25 +1853,21 @@ void PDB_print_stack_string(struct Parrot_Interp *interpreter, const char *command) { - unsigned long depth = 0, i = 0; - struct RegisterChunkBuf *chunk = interpreter->ctx.string_reg_stack.top; + unsigned long i = 0; + struct RegChunk *chunk = interpreter->ctx.string_reg_stack.top; - valid_chunk(chunk, command, depth, - FRAMES_PER_STR_REG_CHUNK, i); + valid_chunk(chunk, command, i); if (!chunk) { - i = depth / FRAMES_PER_STR_REG_CHUNK; PIO_eprintf(interpreter, "There are only %li frames\n",i); return; } - PIO_eprintf(interpreter, "String stack, frame %li, depth %li\n", - i, depth); + PIO_eprintf(interpreter, "Integer stack, frame %li\n",i); na(command); - PDB_print_string_frame(interpreter, - &((struct SRegChunkBuf*)chunk->data.bufstart)->SRegFrame[depth], - atoi(command)); + PDB_print_string_frame(interpreter, &((struct SRegChunk*)chunk)->SRegFrame, + atoi(command)); } /* PDB_print_stack_pmc @@ -1887,24 +1876,21 @@ void PDB_print_stack_pmc(struct Parrot_Interp *interpreter, const char *command) { - unsigned long depth = 0, i = 0; - struct RegisterChunkBuf *chunk = interpreter->ctx.pmc_reg_stack.top; + unsigned long i = 0; + struct RegChunk *chunk = interpreter->ctx.pmc_reg_stack.top; - valid_chunk(chunk, command, depth, - FRAMES_PER_PMC_REG_CHUNK, i); + valid_chunk(chunk, command, i); if (!chunk) { - i = depth / FRAMES_PER_PMC_REG_CHUNK; PIO_eprintf(interpreter, "There are only %li frames\n",i); return; } - PIO_eprintf(interpreter, "PMC stack, frame %li, depth %li\n", i, depth); + PIO_eprintf(interpreter, "Integer stack, frame %li\n",i); na(command); - PDB_print_pmc_frame(interpreter, - &((struct PRegChunkBuf*)chunk->data.bufstart)->PRegFrame[depth], - atoi(command), NULL); + PDB_print_pmc_frame(interpreter, &((struct PRegChunk*)chunk)->PRegFrame, + atoi(command), NULL); } static void Index: src/interpreter.c =================================================================== RCS file: /cvs/public/parrot/src/interpreter.c,v retrieving revision 1.256 diff -u -r1.256 interpreter.c --- src/interpreter.c 14 Jan 2004 10:21:06 -0000 1.256 +++ src/interpreter.c 16 Jan 2004 10:08:58 -0000 @@ -1004,7 +1004,7 @@ PARROT_WARNINGS_off(interpreter, PARROT_WARNINGS_ALL_FLAG); /* Set up the initial register chunks */ - setup_register_stacks(interpreter); + regstack_setup(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 Index: src/register.c =================================================================== RCS file: /cvs/public/parrot/src/register.c,v retrieving revision 1.37 diff -u -r1.37 register.c --- src/register.c 13 Jan 2004 11:03:19 -0000 1.37 +++ src/register.c 16 Jan 2004 10:08:58 -0000 @@ -12,165 +12,180 @@ #include "parrot/parrot.h" -void -setup_register_stacks(Parrot_Interp interpreter) -{ - struct RegisterChunkBuf* buf; - make_bufferlike_pool(interpreter, sizeof(struct RegisterChunkBuf)); +#define REGSTACK_POOL_SPACE 32 - Parrot_block_DOD(interpreter); +struct RegStack_Pool { + void* start; + void* head; + size_t size; + size_t objsize; + int used; +}; + +struct RegStack_Pool_List { + struct RegStack_Pool_Node* head; + size_t objsize; +}; + +struct RegStack_Pool_Node { + struct RegStack_Pool_Node* next; + struct RegStack_Pool pool; +}; + +static struct RegStack_Pool_List regstack_pools[4]; + +static void regstack_pool_make(Parrot_Interp interpreter, enum regchunk_type type) +{ + void* iter; + void* mem = mem_sys_allocate(sizeof(struct RegStack_Pool_Node) + + regstack_pools[type].objsize * REGSTACK_POOL_SPACE); + struct RegStack_Pool_Node* new_pool = mem; + void* pool_start = mem + sizeof(*new_pool); + new_pool->pool.start = pool_start; + new_pool->pool.size = regstack_pools[type].objsize * REGSTACK_POOL_SPACE; + new_pool->pool.objsize = regstack_pools[type].objsize; + new_pool->pool.used = 0; + new_pool->next = regstack_pools[type].head; + regstack_pools[type].head = new_pool; + + for (iter = new_pool->pool.start; + iter < new_pool->pool.start + (new_pool->pool.size - new_pool->pool.objsize); + iter += new_pool->pool.objsize) { + *((void**)iter) = iter + new_pool->pool.objsize; + } + *((void**)iter) = new_pool->pool.start; + new_pool->pool.head = new_pool->pool.start; +} + +static struct RegChunk* regstack_pool_allocate(Parrot_Interp interpreter, enum regchunk_type type) +{ + struct RegStack_Pool_Node* cptr = regstack_pools[type].head; + struct RegChunk* ret; + while (cptr) { + if (cptr->pool.used < REGSTACK_POOL_SPACE) { + ret = (struct RegChunk*)cptr->pool.head; + cptr->pool.head = *(void**)cptr->pool.head; + cptr->pool.used++; + ret->refcount = 1; + ret->type = type; + return ret; + } + cptr = cptr->next; + } + /* Haven't found one yet */ + regstack_pool_make(interpreter, type); + cptr = regstack_pools[type].head; + ret = (struct RegChunk*)cptr->pool.head; + cptr->pool.head = *(void**)cptr->pool.head; + cptr->pool.used++; + ret->refcount = 1; + ret->type = type; + return ret; +} + +static void regstack_pool_return(Parrot_Interp interpreter, struct RegChunk* mem) +{ + struct RegStack_Pool_Node* cptr = regstack_pools[mem->type].head; + + while (cptr) { + if (cptr->pool.start <= (void*)mem && + (void*)mem < cptr->pool.start + cptr->pool.size) { + *((void**)mem) = cptr->pool.head; + cptr->pool.head = (void*)mem; + cptr->pool.used--; + return; + } + cptr = cptr->next; + } + abort(); + internal_exception(ALLOCATION_ERROR, "Couldn't find correct free pool for %p\n", mem); +} - buf = new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf)); - Parrot_allocate_zeroed(interpreter, buf, sizeof(struct IRegChunkBuf)); - interpreter->ctx.int_reg_stack.top = buf; - interpreter->ctx.int_reg_stack.chunk_size = sizeof(struct IRegChunkBuf); +void +regstack_setup(Parrot_Interp interpreter) +{ + regstack_pools[int_reg].head = NULL; + regstack_pools[int_reg].objsize = sizeof(struct IRegChunk); - buf = new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf)); - Parrot_allocate_zeroed(interpreter, buf, sizeof(struct SRegChunkBuf)); - interpreter->ctx.string_reg_stack.top = buf; - interpreter->ctx.string_reg_stack.chunk_size = sizeof(struct SRegChunkBuf); + regstack_pools[num_reg].head = NULL; + regstack_pools[num_reg].objsize = sizeof(struct NRegChunk); - buf = new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf)); - Parrot_allocate_zeroed(interpreter, buf, sizeof(struct NRegChunkBuf)); - interpreter->ctx.num_reg_stack.top = buf; - interpreter->ctx.num_reg_stack.chunk_size = sizeof(struct NRegChunkBuf); + regstack_pools[string_reg].head = NULL; + regstack_pools[string_reg].objsize = sizeof(struct SRegChunk); - buf = new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf)); - Parrot_allocate_zeroed(interpreter, buf, sizeof(struct PRegChunkBuf)); - interpreter->ctx.pmc_reg_stack.top = buf; - interpreter->ctx.pmc_reg_stack.chunk_size = sizeof(struct PRegChunkBuf); + regstack_pools[pmc_reg].head = NULL; + regstack_pools[pmc_reg].objsize = sizeof(struct PRegChunk); - Parrot_unblock_DOD(interpreter); + interpreter->ctx.int_reg_stack.top = NULL; + interpreter->ctx.int_reg_stack.type = int_reg; + + interpreter->ctx.string_reg_stack.top = NULL; + interpreter->ctx.string_reg_stack.type = string_reg; + + interpreter->ctx.num_reg_stack.top = NULL; + interpreter->ctx.num_reg_stack.type = num_reg; + + interpreter->ctx.pmc_reg_stack.top = NULL; + interpreter->ctx.pmc_reg_stack.type = pmc_reg; } void -mark_register_stack(Parrot_Interp interpreter, struct RegStack* stack) +regstack_free(Parrot_Interp interpreter, + struct RegChunk* chunk) { - struct RegisterChunkBuf* chunk; - for (chunk = stack->top; chunk; chunk = chunk->next) { - pobject_lives(interpreter, (PObj*)chunk); - } + if (chunk->next) + REGSTACK_DEC_REFCOUNT(chunk->next); + regstack_pool_return(interpreter, chunk); } void -mark_pmc_register_stack(Parrot_Interp interpreter, struct RegStack* stack) +regstack_mark_string(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++) { - struct PRegFrame *pf = - ((struct PRegChunkBuf*)chunk->data.bufstart)->PRegFrame; - for (j = 0; j < NUM_REGISTERS/2; j++) { - PObj* reg = (PObj*) pf[i].registers[j]; - if (reg) - pobject_lives(interpreter, reg); - } - } + struct RegChunk* chunk = stack->top; + while (chunk) { + int i = 0; + STRING** registers = ((struct SRegChunk*)chunk)->SRegFrame.registers; + for (; i < NUM_REGISTERS/2; i++) + if (registers[i]) + pobject_lives(interpreter, (PObj*)registers[i]); + chunk = chunk->next; } } void -mark_string_register_stack(Parrot_Interp interpreter, struct RegStack* stack) +regstack_mark_pmc(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++) { - struct SRegFrame *sf = - ((struct SRegChunkBuf*)chunk->data.bufstart)->SRegFrame; - for (j = 0; j < NUM_REGISTERS/2; j++) { - PObj* reg = (PObj*) sf[i].registers[j]; - if (reg) - pobject_lives(interpreter, reg); - } - } + struct RegChunk* chunk = stack->top; + while (chunk) { + int i = 0; + PMC** registers = ((struct PRegChunk*)chunk)->PRegFrame.registers; + for (; i < NUM_REGISTERS/2; i++) + if (registers[i]) + pobject_lives(interpreter, (PObj*)registers[i]); + chunk = chunk->next; } } -void -mark_register_stack_cow(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(Parrot_Interp interpreter, - struct RegisterChunkBuf* chunk, - struct RegStack* stack) -{ - struct RegisterChunkBuf* buf = - new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf)); - *buf = *chunk; - - PObj_COW_CLEAR((PObj*) buf); - - Parrot_block_DOD(interpreter); - Parrot_allocate(interpreter, buf, stack->chunk_size); - Parrot_unblock_DOD(interpreter); - - memcpy(buf->data.bufstart, chunk->data.bufstart, stack->chunk_size); - return buf; -} - -static struct RegisterChunkBuf* +static struct RegChunk* regstack_push_entry(Parrot_Interp interpreter, struct RegStack* stack) { - 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++; - return top; - } - else { - 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; - return buf; - } + struct RegChunk* top = stack->top; + struct RegChunk* chunk = regstack_pool_allocate(interpreter, stack->type); + chunk->next = top; + stack->top = chunk; + return chunk; } static void regstack_pop_entry(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 { - if (PObj_COW_TEST((PObj*)top)) - top = stack->top = - regstack_copy_chunk(interpreter, stack->top, stack); - top->used--; - } - } + struct RegChunk* next = stack->top->next; + if (next) + REGSTACK_INC_REFCOUNT(next); + REGSTACK_DEC_REFCOUNT(stack->top); + stack->top = next; } /*=for api register Parrot_push_i @@ -179,11 +194,9 @@ void Parrot_push_i(struct Parrot_Interp *interpreter, void *where) { - struct RegisterChunkBuf* top; - top = regstack_push_entry(interpreter, &interpreter->ctx.int_reg_stack); - memcpy(&((struct IRegChunkBuf*)top->data.bufstart)-> - IRegFrame[top->used-1].registers, - where, sizeof(struct IRegFrame)); + struct IRegChunk* top = (struct IRegChunk*)regstack_push_entry( + interpreter, &interpreter->ctx.int_reg_stack); + memcpy(&top->IRegFrame, where, sizeof(struct IRegFrame)); } /*=for api register Parrot_pop_i @@ -192,19 +205,12 @@ void Parrot_pop_i(struct Parrot_Interp *interpreter, void *where) { - struct RegisterChunkBuf* top = interpreter->ctx.int_reg_stack.top; - /* Do we even have anything? */ - if (top->used > 0) { - 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 { - internal_exception(NO_REG_FRAMES, "No more I register frames to pop!"); + struct IRegChunk* top = (struct IRegChunk*)interpreter->ctx.int_reg_stack.top; + if (!top) { + internal_exception(NO_REG_FRAMES, "No more int register frames to pop\n"); } + memcpy(where, &top->IRegFrame, sizeof(struct IRegFrame)); + regstack_pop_entry(interpreter, &interpreter->ctx.int_reg_stack); } /*=for api register Parrot_clear_i @@ -225,11 +231,9 @@ void Parrot_push_s(struct Parrot_Interp *interpreter, void *where) { - struct RegisterChunkBuf* top; - top = regstack_push_entry(interpreter, &interpreter->ctx.string_reg_stack); - memcpy(&((struct SRegChunkBuf*)top->data.bufstart)-> - SRegFrame[top->used-1].registers, - where, sizeof(struct SRegFrame)); + struct SRegChunk* top = (struct SRegChunk*)regstack_push_entry( + interpreter, &interpreter->ctx.string_reg_stack); + memcpy(&top->SRegFrame, where, sizeof(struct SRegFrame)); } /*=for api register Parrot_pop_s @@ -238,20 +242,12 @@ void Parrot_pop_s(struct Parrot_Interp *interpreter, void *where) { - struct RegisterChunkBuf* top = interpreter->ctx.string_reg_stack.top; - /* Do we even have anything? */ - if (top->used > 0) { - 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 { - internal_exception(NO_REG_FRAMES, "No more S register frames to pop!"); + struct SRegChunk* top = (struct SRegChunk*)interpreter->ctx.string_reg_stack.top; + if (!top) { + internal_exception(NO_REG_FRAMES, "No more string register frames to pop\n"); } + memcpy(where, &top->SRegFrame, sizeof(struct SRegFrame)); + regstack_pop_entry(interpreter, &interpreter->ctx.string_reg_stack); } /*=for api register Parrot_clear_s @@ -272,11 +268,9 @@ void Parrot_push_n(struct Parrot_Interp *interpreter, void *where) { - struct RegisterChunkBuf* top; - top = regstack_push_entry(interpreter, &interpreter->ctx.num_reg_stack); - memcpy(&((struct NRegChunkBuf*)top->data.bufstart)-> - NRegFrame[top->used-1].registers, - where, sizeof(struct NRegFrame)); + struct NRegChunk* top = (struct NRegChunk*)regstack_push_entry( + interpreter, &interpreter->ctx.num_reg_stack); + memcpy(&top->NRegFrame, where, sizeof(struct NRegFrame)); } /*=for api register Parrot_pop_n @@ -285,20 +279,12 @@ void Parrot_pop_n(struct Parrot_Interp *interpreter, void *where) { - struct RegisterChunkBuf* top = interpreter->ctx.num_reg_stack.top; - /* Do we even have anything? */ - if (top->used > 0) { - 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 { - internal_exception(NO_REG_FRAMES, "No more N register frames to pop!"); + struct NRegChunk* top = (struct NRegChunk*)interpreter->ctx.num_reg_stack.top; + if (!top) { + internal_exception(NO_REG_FRAMES, "No more num register frames to pop\n"); } + memcpy(where, &top->NRegFrame, sizeof(struct NRegFrame)); + regstack_pop_entry(interpreter, &interpreter->ctx.num_reg_stack); } /*=for api register Parrot_clear_n @@ -319,11 +305,9 @@ void Parrot_push_p(struct Parrot_Interp *interpreter, void *where) { - struct RegisterChunkBuf* top; - top = regstack_push_entry(interpreter, &interpreter->ctx.pmc_reg_stack); - memcpy(&((struct PRegChunkBuf*)top->data.bufstart)-> - PRegFrame[top->used-1].registers, - where, sizeof(struct PRegFrame)); + struct PRegChunk* top = (struct PRegChunk*)regstack_push_entry( + interpreter, &interpreter->ctx.pmc_reg_stack); + memcpy(&top->PRegFrame, where, sizeof(struct PRegFrame)); } /*=for api register Parrot_pop_p @@ -332,20 +316,12 @@ void Parrot_pop_p(struct Parrot_Interp *interpreter, void *where) { - struct RegisterChunkBuf* top = interpreter->ctx.pmc_reg_stack.top; - /* Do we even have anything? */ - if (top->used > 0) { - 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 { - internal_exception(NO_REG_FRAMES, "No more P register frames to pop!"); + struct PRegChunk* top = (struct PRegChunk*)interpreter->ctx.pmc_reg_stack.top; + if (!top) { + internal_exception(NO_REG_FRAMES, "No more pmc register frames to pop\n"); } + memcpy(where, &top->PRegFrame, sizeof(struct PRegFrame)); + regstack_pop_entry(interpreter, &interpreter->ctx.pmc_reg_stack); } /*=for api register Parrot_clear_p Index: src/sub.c =================================================================== RCS file: /cvs/public/parrot/src/sub.c,v retrieving revision 1.42 diff -u -r1.42 sub.c --- src/sub.c 13 Jan 2004 09:45:21 -0000 1.42 +++ src/sub.c 16 Jan 2004 10:08:58 -0000 @@ -34,10 +34,6 @@ 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); @@ -59,10 +55,8 @@ 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); + regstack_mark_string(interpreter, &ctx->string_reg_stack); + regstack_mark_pmc(interpreter, &ctx->pmc_reg_stack); } static void coro_error(Stack_Entry_t *e) @@ -191,7 +185,7 @@ Buffer * warns; struct Parrot_Coroutine* co = (struct Parrot_Coroutine *)PMC_sub(sub); struct Parrot_Context *ctx = &co->ctx; - struct RegisterChunkBuf *reg_top; + struct RegChunk *reg_top; /* * Swap user stacks and warnings Index: t/op/stacks.t =================================================================== RCS file: /cvs/public/parrot/t/op/stacks.t,v retrieving revision 1.32 diff -u -r1.32 stacks.t --- t/op/stacks.t 6 Jan 2004 16:57:29 -0000 1.32 +++ t/op/stacks.t 16 Jan 2004 10:08:58 -0000 @@ -679,15 +679,15 @@ # Now, to make it do BAD THINGS! -output_is(<<"CODE",'No more I register frames to pop!','ENO I frames'); +output_is(<<"CODE","No more int register frames to pop\n",'ENO I frames'); popi end CODE -output_is(<<"CODE",'No more N register frames to pop!','ENO N frames'); +output_is(<<"CODE","No more num register frames to pop\n",'ENO N frames'); popn end CODE -output_is(<<"CODE",'No more S register frames to pop!','ENO S frames'); +output_is(<<"CODE","No more string register frames to pop\n",'ENO S frames'); pops end CODE