cvsuser 03/06/27 03:09:33
Modified: . debug.c dod.c interpreter.c method_util.c stacks.c
Log:
COW stacks by chunk
Revision Changes Path
1.83 +2 -2 parrot/debug.c
Index: debug.c
===================================================================
RCS file: /cvs/public/parrot/debug.c,v
retrieving revision 1.82
retrieving revision 1.83
diff -u -w -r1.82 -r1.83
--- debug.c 21 Jun 2003 10:40:29 -0000 1.82
+++ debug.c 27 Jun 2003 10:09:33 -0000 1.83
@@ -2,7 +2,7 @@
* debug.c
*
* CVS Info
- * $Id: debug.c,v 1.82 2003/06/21 10:40:29 leo Exp $
+ * $Id: debug.c,v 1.83 2003/06/27 10:09:33 leo Exp $
* Overview:
* Parrot debugger
* History:
@@ -1928,7 +1928,7 @@
valid_chunk(chunk, command, depth, STACK_CHUNK_DEPTH, i);
- entry = (Stack_Entry_t *)(chunk->buffer->bufstart) + depth;
+ entry = (Stack_Entry_t *)(chunk->items.bufstart) + depth;
switch (entry->entry_type) {
case STACK_ENTRY_INT:
1.61 +5 -6 parrot/dod.c
Index: dod.c
===================================================================
RCS file: /cvs/public/parrot/dod.c,v
retrieving revision 1.60
retrieving revision 1.61
diff -u -w -r1.60 -r1.61
--- dod.c 14 Jun 2003 17:48:31 -0000 1.60
+++ dod.c 27 Jun 2003 10:09:33 -0000 1.61
@@ -1,7 +1,7 @@
/* dod.c
* Copyright: (When this is determined...it will go here)
* CVS Info
- * $Id: dod.c,v 1.60 2003/06/14 17:48:31 dan Exp $
+ * $Id: dod.c,v 1.61 2003/06/27 10:09:33 leo Exp $
* Overview:
* Handles dead object destruction of the various headers
* Data Structure and Algorithms:
@@ -290,8 +290,7 @@
Buffer *b;
int *refcount;
- /* clear refcount for COWable objects. As these are STRINGs only these
- * have _is_string_FLAG set */
+ /* clear refcount for COWable objects. */
for (cur_arena = pool->last_Arena;
NULL != cur_arena; cur_arena = cur_arena->prev) {
b = cur_arena->start_objects;
@@ -308,7 +307,7 @@
PObj_live_CLEAR(b);
}
- if (PObj_is_string_TEST(b) && b->bufstart &&
+ if (PObj_COW_TEST(b) && b->bufstart &&
!PObj_external_TEST(b)) {
refcount = ((int *)b->bufstart);
*refcount = 0;
@@ -335,7 +334,7 @@
b = cur_arena->start_objects;
for (i = 0; i < cur_arena->used; i++) {
if (!PObj_on_free_list_TEST(b) &&
- PObj_is_string_TEST(b) &&
+ PObj_COW_TEST(b) &&
b->bufstart &&
!PObj_external_TEST(b)) {
refcount = ((int *)b->bufstart);
@@ -533,7 +532,7 @@
* but not if it is used COW or external
*/
if (b->bufstart && !PObj_is_external_or_free_TESTALL(b)) {
- if (PObj_is_string_TEST(b)) {
+ if (PObj_COW_TEST(b)) {
int *refcount = ((int *)b->bufstart);
if (!--(*refcount))
1.162 +2 -5 parrot/interpreter.c
Index: interpreter.c
===================================================================
RCS file: /cvs/public/parrot/interpreter.c,v
retrieving revision 1.161
retrieving revision 1.162
diff -u -w -r1.161 -r1.162
--- interpreter.c 24 Jun 2003 08:35:18 -0000 1.161
+++ interpreter.c 27 Jun 2003 10:09:33 -0000 1.162
@@ -1,7 +1,7 @@
/* interpreter.c
* Copyright: (When this is determined...it will go here)
* CVS Info
- * $Id: interpreter.c,v 1.161 2003/06/24 08:35:18 leo Exp $
+ * $Id: interpreter.c,v 1.162 2003/06/27 10:09:33 leo Exp $
* Overview:
* The interpreter api handles running the operations
* Data Structure and Algorithms:
@@ -542,18 +542,15 @@
Parrot_clear_s(interpreter);
Parrot_clear_p(interpreter);
+ stack_system_init(interpreter);
/* Stack for lexical pads */
interpreter->ctx.pad_stack = new_stack(interpreter, "Pad");
/* Need a user stack */
interpreter->ctx.user_stack = new_stack(interpreter, "User");
- assert(interpreter->ctx.user_stack->buffer !=
- interpreter->ctx.pad_stack->buffer);
/* And a control stack */
interpreter->ctx.control_stack = new_stack(interpreter, "Control");
- assert(interpreter->ctx.control_stack->buffer !=
- interpreter->ctx.user_stack->buffer);
/* A regex stack would be nice too. */
interpreter->ctx.intstack = intstack_new(interpreter);
1.14 +3 -5 parrot/method_util.c
Index: method_util.c
===================================================================
RCS file: /cvs/public/parrot/method_util.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -w -r1.13 -r1.14
--- method_util.c 14 Jun 2003 17:48:31 -0000 1.13
+++ method_util.c 27 Jun 2003 10:09:33 -0000 1.14
@@ -1,7 +1,7 @@
/* method_util.c
* Copyright: (When this is determined...it will go here)
* CVS Info
- * $Id: method_util.c,v 1.13 2003/06/14 17:48:31 dan Exp $
+ * $Id: method_util.c,v 1.14 2003/06/27 10:09:33 leo Exp $
* Overview:
* Utility functions to handle Parrot calling conventions, lookup
* methods, etc.
@@ -152,11 +152,9 @@
size_t i;
for (; cur_stack; cur_stack = cur_stack->prev) {
- if (cur_stack->buffer == NULL)
- continue;
- pobject_lives(interpreter, (PObj *)cur_stack->buffer);
- entry = (Stack_Entry_t *)(cur_stack->buffer->bufstart);
+ pobject_lives(interpreter, (PObj *)cur_stack);
+ entry = (Stack_Entry_t *)(cur_stack->items.bufstart);
for (i = 0; i < cur_stack->used; i++) {
if ((STACK_ENTRY_PMC == entry[i].entry_type ||
STACK_ENTRY_STRING == entry[i].entry_type) &&
1.56 +95 -120 parrot/stacks.c
Index: stacks.c
===================================================================
RCS file: /cvs/public/parrot/stacks.c,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -w -r1.55 -r1.56
--- stacks.c 24 Jun 2003 08:35:18 -0000 1.55
+++ stacks.c 27 Jun 2003 10:09:33 -0000 1.56
@@ -1,7 +1,7 @@
/* stacks.c
* Copyright: (When this is determined...it will go here)
* CVS Info
- * $Id: stacks.c,v 1.55 2003/06/24 08:35:18 leo Exp $
+ * $Id: stacks.c,v 1.56 2003/06/27 10:09:33 leo Exp $
* Overview:
* Stack handling routines for Parrot
* Data Structure and Algorithms:
@@ -10,6 +10,11 @@
* entries. The invariant maintained is that there is always room
* for another entry; if a chunk is filled, a new chunk is added
* onto the list before returning.
+ *
+ * A stack chunk is a bufferlike structure and may be GCed or COWed.
+ * As top chunks are COWed on usage, its only safe to walk the stack
+ * from top down via the prev pointers.
+ *
* History:
* Notes:
* References: */
@@ -17,28 +22,28 @@
#include "parrot/parrot.h"
#include <assert.h>
+void stack_system_init(Interp *interpreter)
+{
+ make_bufferlike_pool(interpreter, sizeof(Stack_Chunk_t));
+}
+
Stack_Chunk_t *
new_stack(Interp *interpreter, const char *name)
{
- Stack_Chunk_t *chunk = mem_sys_allocate_zeroed(sizeof(Stack_Chunk_t));
- Stack_t *stack = mem_sys_allocate_zeroed(sizeof(Stack_t));
+ Stack_Chunk_t *chunk = new_bufferlike_header(interpreter,
+ sizeof(Stack_Chunk_t));
- chunk->flags = NO_STACK_CHUNK_FLAGS;
+ SET_NULL(chunk->items);
SET_NULL(chunk->next);
SET_NULL(chunk->prev);
- SET_NULL(chunk->buffer);
- chunk->stack = stack;
- stack->top = stack->base = chunk;
- stack->n_chunks = 1;
- stack->chunk_limit = STACK_CHUNK_LIMIT;
- stack->name = name;
+ chunk->n_chunks = 1;
+ chunk->chunk_limit = STACK_CHUNK_LIMIT;
+ chunk->name = name;
- chunk->buffer = new_buffer_header(interpreter);
-
- /* Block DOD from murdering our newly allocated stack->buffer. */
+ /* Block DOD from murdering our newly allocated stack buffer. */
Parrot_block_DOD(interpreter);
- Parrot_allocate(interpreter, chunk->buffer,
+ Parrot_allocate(interpreter, (Buffer *)chunk,
sizeof(Stack_Entry_t) * STACK_CHUNK_DEPTH);
Parrot_unblock_DOD(interpreter);
@@ -48,27 +53,15 @@
void
stack_destroy(Stack_Chunk_t * top)
{
- mem_sys_free(top->stack);
- while (top->next)
- top = top->next;
- while(top) {
- Stack_Chunk_t *next = top->prev;
- mem_sys_free(top);
- top = next;
- }
+ /* GC does it all */
}
+/* mark a stack COW */
void
-stack_mark_cow(Stack_Chunk_t *stack)
+stack_mark_cow(Stack_Chunk_t *top)
{
- Stack_Chunk_t *chunk = stack;
- /* Skip it all if we're already COW'd */
- if (chunk->flags & STACK_CHUNK_COW_FLAG) {
- return;
- }
- chunk->flags |= STACK_CHUNK_COW_FLAG;
- for (chunk = chunk->prev; chunk && !(chunk->flags& STACK_CHUNK_COW_FLAG); chunk
= chunk->prev)
- chunk->flags |= STACK_CHUNK_COW_FLAG;
+ for ( ; top ; top = top->prev)
+ PObj_COW_SET( (Buffer *) top);
}
/* Returns the height of the stack. The maximum "depth" is height - 1 */
@@ -80,28 +73,24 @@
for (chunk = top->prev; chunk; chunk = chunk->prev)
height += chunk->used;
- assert(height == (top->stack->n_chunks - 1) * STACK_CHUNK_DEPTH +
+ assert(height == (top->n_chunks - 1) * STACK_CHUNK_DEPTH +
top->used);
return height;
}
-/* Copy a stack (probably with COW flag) to a private writable stack.
- * We currently copy the whole stack. After we get rid of the circular
- * references, fix this to do COW by chunk.
+/* Copy COWed chunk(s) from top down depth entries
+ * return new top of stack
*/
-Stack_Chunk_t *
-stack_copy(struct Parrot_Interp *interp, Stack_Chunk_t *old_top)
+static Stack_Chunk_t *
+chunk_copy(struct Parrot_Interp *interp, Stack_Chunk_t *old_top, int depth)
{
Stack_Chunk_t *old_chunk = old_top;
Stack_Chunk_t *new_chunk;
Stack_Chunk_t *new_top = NULL;
Stack_Chunk_t *last = NULL;
- Stack_t *stack = mem_sys_allocate_zeroed(sizeof(Stack_t));
- stack->n_chunks = 0;
- stack->name = old_top->stack->name;
do {
- new_chunk = mem_sys_allocate(sizeof(Stack_Chunk_t));
+ new_chunk = new_bufferlike_header(interp, sizeof(Stack_Chunk_t));
if (new_top == NULL) {
new_top = new_chunk;
new_top->next = NULL;
@@ -115,25 +104,21 @@
last = new_chunk;
}
new_chunk->used = old_chunk->used;
-
- /* Can't do bit arithmetic directly on enums, must cast via ints. */
- new_chunk->flags = (Stack_chunk_flags)((int)old_chunk->flags
- & ~(int)STACK_CHUNK_COW_FLAG);
-
- /* Copy stack buffer */
- new_chunk->buffer = NULL;
- new_chunk->buffer = new_buffer_header(interp);
- Parrot_allocate(interp, new_chunk->buffer,
+ new_chunk->n_chunks = old_chunk->n_chunks;
+ new_chunk->chunk_limit = old_chunk->chunk_limit;
+ new_chunk->name = old_chunk->name;
+ depth -= new_chunk->used;
+
+ SET_NULL(new_chunk->items);
+ Parrot_block_DOD(interp);
+ Parrot_allocate(interp, (Buffer *)new_chunk,
sizeof(Stack_Entry_t) * STACK_CHUNK_DEPTH);
- memcpy(new_chunk->buffer->bufstart, old_chunk->buffer->bufstart,
- old_chunk->buffer->buflen);
+ Parrot_unblock_DOD(interp);
+ memcpy(new_chunk->items.bufstart, old_chunk->items.bufstart,
+ old_chunk->items.buflen);
old_chunk = old_chunk->prev;
- stack->n_chunks++;
- stack->base = new_chunk;
}
- while (old_chunk);
- new_top->stack = stack;
- stack->top = new_top;
+ while (old_chunk && depth >= 0);
return new_top;
}
@@ -164,7 +149,7 @@
if (chunk == NULL)
return NULL;
if (offset < chunk->used) {
- entry = (Stack_Entry_t *)chunk->buffer->bufstart +
+ entry = (Stack_Entry_t *)chunk->items.bufstart +
chunk->used - offset - 1;
}
return entry;
@@ -185,10 +170,6 @@
if (num_entries >= -1 && num_entries <= 1) {
return;
}
- /* If stack is copy-on-write, copy it before we can execute on it */
- if (stack->flags & STACK_CHUNK_COW_FLAG) {
- *stack_p = stack = stack_copy(interpreter, stack);
- }
if (num_entries < 0) {
num_entries = -num_entries;
@@ -197,6 +178,9 @@
if (stack_height(interpreter, stack) < (size_t)num_entries) {
internal_exception(ERROR_STACK_SHALLOW, "Stack too shallow!\n");
}
+ /* If stack is copy-on-write, copy it before we can execute on it */
+ if (PObj_COW_TEST( (Buffer *) stack))
+ *stack_p = stack = chunk_copy(interpreter, stack, depth);
temp = *stack_entry(interpreter, stack, depth);
for (i = depth; i > 0; i--) {
@@ -211,6 +195,8 @@
if (stack_height(interpreter, stack) < (size_t)num_entries) {
internal_exception(ERROR_STACK_SHALLOW, "Stack too shallow!\n");
}
+ if (PObj_COW_TEST( (Buffer *) stack))
+ *stack_p = stack = chunk_copy(interpreter, stack, depth);
temp = *stack_entry(interpreter, stack, 0);
for (i = 0; i < depth; i++) {
@@ -235,48 +221,45 @@
stack_push(Interp *interpreter, Stack_Chunk_t **stack_p,
void *thing, Stack_entry_type type, Stack_cleanup_method cleanup)
{
- Stack_Chunk_t *stack = *stack_p;
- Stack_Chunk_t *chunk;
+ Stack_Chunk_t *chunk = *stack_p;
Stack_Entry_t *entry;
- /* If stack is copy-on-write, copy it before we can execute on it */
- if (stack->flags & STACK_CHUNK_COW_FLAG) {
- *stack_p = stack = stack_copy(interpreter, stack);
- }
-
- chunk = stack;
/* Do we need a new chunk? */
if (chunk->used == STACK_CHUNK_DEPTH) {
if (chunk->next == NULL) {
/* Need to add a new chunk */
- Stack_Chunk_t *new_chunk = mem_sys_allocate_zeroed(
- sizeof(Stack_Chunk_t));
+ Stack_Chunk_t *new_chunk =
+ new_bufferlike_header(interpreter, sizeof(Stack_Chunk_t));
SET_NULL(new_chunk->next);
new_chunk->prev = chunk;
chunk->next = new_chunk;
- new_chunk->stack = chunk->stack;
- new_chunk->stack->n_chunks++;
- if (new_chunk->stack->n_chunks == new_chunk->stack->chunk_limit)
+ new_chunk->n_chunks = chunk->n_chunks + 1;
+ new_chunk->chunk_limit = chunk->chunk_limit;
+ new_chunk->name = chunk->name;
+ if (new_chunk->n_chunks == new_chunk->chunk_limit)
internal_exception(1, "Stack '%s' too deep\n",
- chunk->stack->name);
+ chunk->name);
*stack_p = chunk = new_chunk;
- SET_NULL(new_chunk->buffer);
- new_chunk->buffer = new_buffer_header(interpreter);
+ SET_NULL(new_chunk->items);
- Parrot_allocate(interpreter, new_chunk->buffer,
+ Parrot_block_DOD(interpreter);
+ Parrot_allocate(interpreter, (Buffer *)new_chunk,
sizeof(Stack_Entry_t) * STACK_CHUNK_DEPTH);
+ Parrot_unblock_DOD(interpreter);
}
else {
/* Reuse the spare chunk we kept */
chunk = chunk->next;
+ assert(!PObj_COW_TEST( (Buffer *) chunk));
*stack_p = chunk;
- chunk->stack->n_chunks++;
}
- chunk->stack->top = chunk;
}
+ /* If stack is copy-on-write, copy it before we can execute on it */
+ else if (PObj_COW_TEST( (Buffer *) chunk))
+ *stack_p = chunk = chunk_copy(interpreter, chunk, 0);
- entry = (Stack_Entry_t *)(chunk->buffer->bufstart) + chunk->used;
+ entry = (Stack_Entry_t *)(chunk->items.bufstart) + chunk->used++;
/* Remember the type */
entry->entry_type = type;
@@ -307,8 +290,6 @@
"Invalid Stack_Entry_type!\n");
break;
}
-
- chunk->used++;
}
/* Pop off an entry and return a pointer to the contents */
@@ -316,16 +297,12 @@
stack_pop(Interp *interpreter, Stack_Chunk_t **stack_p,
void *where, Stack_entry_type type)
{
- Stack_Chunk_t *stack = *stack_p;
+ Stack_Chunk_t *chunk = *stack_p;
Stack_Entry_t *entry;
- Stack_Chunk_t *chunk;
/* If stack is copy-on-write, copy it before we can execute on it */
- if (stack->flags & STACK_CHUNK_COW_FLAG) {
- *stack_p = stack = stack_copy(interpreter, stack);
- }
-
- chunk = stack;
+ if (PObj_COW_TEST( (Buffer *) chunk))
+ *stack_p = chunk = chunk_copy(interpreter, chunk, 0);
/* We may have an empty chunk at the end of the list */
if (chunk->used == 0 && chunk->prev != NULL) {
@@ -336,8 +313,7 @@
* on the stack then we make it the last chunk - the GC will clean
* up any chunks that are discarded by this operation. */
if (chunk->next) {
- /* FIXME: Free this while GC isn't collecting stacks */
- mem_sys_free(chunk->next);
+ /* GC will collect it */
chunk->next = NULL;
}
@@ -345,19 +321,18 @@
* just emptied around for now in case we need it again. */
chunk = chunk->prev;
*stack_p = chunk;
- chunk->stack->top = chunk;
- chunk->stack->n_chunks--;
}
/* Quick sanity check */
if (chunk->used == 0) {
internal_exception(ERROR_STACK_EMPTY, "No entries on stack!\n");
}
+ assert(!PObj_COW_TEST( (Buffer *) chunk));
/* Now decrement the SP */
chunk->used--;
- entry = (Stack_Entry_t *)(chunk->buffer->bufstart) + chunk->used;
+ entry = (Stack_Entry_t *)(chunk->items.bufstart) + chunk->used;
/* Types of 0 mean we don't care */
if (type && entry->entry_type != type) {