This is a first in a series of patches implementing hashtables.

This patch allows the creation of variable-sized Buffer subclasses via
new_tracked_header(). It automatically creates a new Resource_Pool for
each size requested. For fast access and easy implementation, the
resource pools are kept in an array that is resized as needed.

This patch also adds mark_used() to the resources.h interface (it is
needed for custom mark routines), and adds a new flag
BUFFER_report_FLAG that may be set on a buffer to generate a debugging
printout whenever the buffer is encountered during compaction. They're
not related to the rest of the patch, but they were in the same file
and were pretty small, so I slipped them in.

Note that this patch aims at minimal invasiveness. If the idea is
accepted, then probably all Buffer subclasses (including non-constant
STRINGs) that are subject to collection should be placed into the
sized pools, and arena_base->*_header_pool should just be cached
aliases of the appropriate pool. That would eliminate a bunch of
duplicated code in resources.c. It's a trivial change; I'll send a
revised patch if people like the idea.

All tests still pass with this applied. Unsurprising, since nothing
calls the code at this point.

Index: resources.c
===================================================================
RCS file: /home/perlcvs/parrot/resources.c,v
retrieving revision 1.53
diff -p -u -b -r1.53 resources.c
--- resources.c 6 May 2002 04:18:00 -0000       1.53
+++ resources.c 14 May 2002 21:47:03 -0000
@@ -12,6 +12,7 @@
  *  References:
  */
 
+#include <assert.h>
 #include "parrot/parrot.h"
 
 #define BUFFER_ALIGNMENT 16
@@ -177,14 +178,6 @@ free_pmc(PMC *pmc)
     }
 }
 
-Buffer *
-new_tracked_header(struct Parrot_Interp *interpreter, size_t size)
-{
-    UNUSED(interpreter);
-    return (Buffer *)mem_sys_allocate(size);
-}
-
-
 /* We have no more headers on the free header pool. Go allocate more
  * and put them on */
 static void
@@ -637,6 +630,58 @@ Parrot_initialize_resource_pools(struct 
                           alloc_more_buffer_headers);
 }
 
+INLINE static UINTVAL
+sized_index(size_t unit_size)
+{
+    return (unit_size - sizeof(Buffer)) / sizeof(void*);
+}
+
+/* unit_size must be a multiple of sizeof(void*), for no particular reason
+ * other than to shrink the size of the array of pools. */
+static struct Resource_Pool *
+new_sized_resource_pool(struct Parrot_Interp *interpreter,
+                        size_t unit_size)
+{
+    UINTVAL idx = sized_index(unit_size);
+    UINTVAL num_old = interpreter->arena_base->num_sized;
+    struct Resource_Pool** sized_pools =
+        interpreter->arena_base->sized_header_pools;
+    assert(unit_size % sizeof(void*) == 0);
+
+    /* Expand the array of sized resource pools, if necessary */
+    if (num_old <= idx) {
+        UINTVAL num_new = idx + 1;
+        sized_pools = mem_sys_realloc(sized_pools, num_new * sizeof(void*));
+        memset(sized_pools + num_old, 0, sizeof(void*) * (num_new - num_old));
+        interpreter->arena_base->sized_header_pools = sized_pools;
+        interpreter->arena_base->num_sized = num_new;
+    }
+
+    if (sized_pools[idx] == NULL)
+        sized_pools[idx] = new_resource_pool(interpreter, 256, unit_size,
+                                             SIZED_HEADERS_PER_ALLOC,
+                                             alloc_more_buffer_headers);
+
+    return sized_pools[idx];
+    /* FIXME! Sized buffer headers are currently not collected! */
+}
+
+Buffer *
+new_tracked_header(struct Parrot_Interp *interpreter, size_t size)
+{
+    struct Resource_Pool* pool;
+    Buffer * buffer;
+    size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+    pool = new_sized_resource_pool(interpreter, size);
+    
+    buffer = get_from_free_pool(interpreter, pool);
+    interpreter->active_Buffers++;
+    buffer->flags = BUFFER_live_FLAG;
+    buffer->bufstart = NULL;
+    buffer->buflen = 0;
+    return buffer;
+}
+
 /* Figure out how much memory's been allocated total for buffered
  * things */
 static UINTVAL
@@ -662,6 +707,7 @@ compact_buffer_pool(struct Parrot_Interp
     struct Buffer_Arena *cur_buffer_arena;
     struct Resource_Pool *header_pool;
     Buffer *b;   /* temporary tidy-up for free pool collection */
+    INTVAL j;
 
     /* Bail if we're blocked */
     if (interpreter->GC_block_level) {
@@ -715,24 +761,54 @@ compact_buffer_pool(struct Parrot_Interp
     cur_size = (cur_size + pool->align_1) & ~pool->align_1;
     cur_spot += cur_size;
 
+    /* And finally the sized buffer header pools */
+    for (j = 0; j < (INTVAL) interpreter->arena_base->num_sized; j++) {
+        struct Resource_Pool* sized_pool;
+        sized_pool = interpreter->arena_base->sized_header_pools[j];
+        if (sized_pool == NULL) continue;
+
+        b = &sized_pool->free_pool_buffer;
+        memcpy(cur_spot, b->bufstart, b->buflen);
+        b->bufstart = cur_spot;
+        cur_size = b->buflen;
+        cur_size = (cur_size + pool->align_1) & ~pool->align_1;
+        cur_spot += cur_size;
+    }
+
     /* Run through all the Buffer header pools and copy */
-    header_pool = interpreter->arena_base->buffer_header_pool;
+    for (j = -1; j < (INTVAL) interpreter->arena_base->num_sized; j++) {
+        if (j == -1) header_pool = interpreter->arena_base->buffer_header_pool;
+        else header_pool = interpreter->arena_base->sized_header_pools[j];
+        if (header_pool == NULL) continue;
+                 
     for (cur_buffer_arena = header_pool->last_Arena;
          NULL != cur_buffer_arena;
-         cur_buffer_arena = cur_buffer_arena->prev) {
-        UINTVAL i;
+             cur_buffer_arena = cur_buffer_arena->prev)
+        {
         Buffer *buffer_array = cur_buffer_arena->start_Buffer;
+            UINTVAL i;
         for (i = 0; i < cur_buffer_arena->used; i++) {
+                Buffer *buffer = (Buffer*)((char*)cur_buffer_arena->start_Buffer + i 
+* header_pool->unit_size);
+
             /* Is the string live, and can we move it? */
-            if (buffer_array[i].flags & BUFFER_live_FLAG
-                && !(buffer_array[i].flags & BUFFER_immobile_FLAG)
-                && buffer_array[i].bufstart) {
-                memcpy(cur_spot, buffer_array[i].bufstart,
-                       buffer_array[i].buflen);
-                buffer_array[i].bufstart = cur_spot;
-                cur_size = buffer_array[i].buflen;
+                if (buffer->flags & BUFFER_live_FLAG
+                    && !(buffer->flags & BUFFER_immobile_FLAG)
+                    && buffer->bufstart)
+                {
+                    if (buffer->flags & BUFFER_report_FLAG) {
+                        fprintf(stderr, "  copying buffer %p+%ld -> %p\n",
+                                buffer->bufstart, buffer->buflen, cur_spot);
+                    }
+                    memcpy(cur_spot, buffer->bufstart, buffer->buflen);
+                    buffer->bufstart = cur_spot;
+                    cur_size = buffer->buflen;
                 cur_size = (cur_size + pool->align_1) & ~pool->align_1;
                 cur_spot += cur_size;
+                } else if (buffer->flags & BUFFER_report_FLAG) {
+                    if (buffer->bufstart != NULL)
+                        fprintf(stderr, "  not copying buffer %p+%ld\n",
+                                buffer->bufstart, buffer->buflen);
+                }
             }
         }
     }
Index: include/parrot/resources.h
===================================================================
RCS file: /home/perlcvs/parrot/include/parrot/resources.h,v
retrieving revision 1.29
diff -p -u -b -r1.29 resources.h
--- include/parrot/resources.h  4 May 2002 22:27:45 -0000       1.29
+++ include/parrot/resources.h  14 May 2002 21:47:03 -0000
@@ -54,6 +54,8 @@ void Parrot_go_collect(struct Parrot_Int
 void *Parrot_reallocate(struct Parrot_Interp *interpreter, void *from, size_t tosize);
 void *Parrot_reallocate_string(struct Parrot_Interp *interpreter, STRING *, size_t 
tosize);
 
+/* Functions needed for custom DOD routines */
+PMC * mark_used(PMC *used_pmc, PMC *current_end_of_list);
 void buffer_lives(Buffer *);
 
 void Parrot_initialize_resource_pools(struct Parrot_Interp *);
@@ -62,6 +64,7 @@ void Parrot_initialize_memory_pools(stru
 #define STRING_HEADERS_PER_ALLOC 128
 #define PMC_HEADERS_PER_ALLOC 128
 #define BUFFER_HEADERS_PER_ALLOC 128
+#define SIZED_HEADERS_PER_ALLOC 128
 
 struct PMC_Arena {
     size_t used;         /* Count of PMCs in this arena */
@@ -96,6 +99,8 @@ struct Arenas {
     struct Resource_Pool *pmc_pool;
     struct Resource_Pool *buffer_header_pool;
     struct Resource_Pool *constant_string_header_pool;
+    struct Resource_Pool **sized_header_pools;
+    size_t num_sized;
 };
 
 struct Stash {
Index: include/parrot/string.h
===================================================================
RCS file: /home/perlcvs/parrot/include/parrot/string.h,v
retrieving revision 1.37
diff -p -u -b -r1.37 string.h
--- include/parrot/string.h     5 May 2002 04:03:08 -0000       1.37
+++ include/parrot/string.h     14 May 2002 21:47:03 -0000
@@ -70,7 +70,9 @@ typedef enum BUFFER_flag {
     /* Mark the buffer as on the free list */
     BUFFER_on_free_list_FLAG = 1 << 14,
     /* This is a constant--don't kill it! */
-    BUFFER_constant_FLAG = 1 << 15
+    BUFFER_constant_FLAG = 1 << 15,
+    /* For debugging, report when this buffer gets moved around */
+    BUFFER_report_FLAG = 1 << 16
 } BUFFER_flags;
 
 /* stringinfo parameters */

Reply via email to