Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCH] Continuations now close over register stacks

9 views
Skip to first unread message

Luke Palmer

unread,
Jan 7, 2004, 10:10:30 PM1/7/04
to Internals List
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');

Leopold Toetsch

unread,
Jan 12, 2004, 4:48:56 AM1/12/04
to Luke Palmer, perl6-i...@perl.org
Luke Palmer <fibo...@babylonia.flatirons.org> wrote:
> 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.

Applied, thanks.

Some remarks WRT the patch:
1) struct RegStack doesn't need the chunk_size data member
top->data.buflen has the exact size
So ctx.<type>_reg_stack could be a general StackChunkBuf
2) pad, control and user stacks could very likely use the same
stack infrastructure. COW copying of these is still b0rken but
needed as well.
3) The LEA allocators implementation does only handle COW copying
of string memory. This should be fixed, that is, allocate one
sizeof(int) + the requested memory and consider the memory at
buffer+size as the refcount (used during DOD) - or increment
bufstart by sizeof(int), so that the actual allocated memory
ptr is at bufstart - sizeof(int). But that has to be consistent
for strings and plain buffers.
4) Several Parrot_allocate_zeroed could be just Parrot_allocate
as the memory is either copied over or initialized later.

And finally a remark WRT COWed Buffers:

5) cow_copy_context() could still be wrong. Both contexts share the
same Buffer header. When now this shared buffer header is marked COW
each change to the context would unshare the buffer by creating a
distinct copy. This also means, that if the COWed stack copy isn't
changed in the Sub and after return from the Sub an item is pushed
on that stack, it would be copied.

I know that I did this for other buffers in the context
but it is wrong somehow - IMHO.

COWed strings also seem to suffer from that problem. Both buffer
headers are marked COW. Even if the shared copy goes out of scope,
the COW flag remains - so changing that string later would do a
copy of the buffer first, which isn't needed as there is only one
user of the buffer left.

It could be simpler if we have an explicit refcount for COWed objects.
We need that during DOD anyway with some overhead.

Takers for these steps wanted, please drop a short note.

thanks,
leo

0 new messages