#endif
-#if 0
-#define MDBG_POOL
-#endif
-
#if DBG_MEM
int dbg_move_depth;
int dbg_mem = DBG_MEM_START;
}
}
-static uint16_t chunk_low;
+static uint16_t chunk_low, chunk_high;
static uint16_t chunk_first, chunk_last;
+static int chunk_busy;
static void
note_chunk(uint16_t addr, uint16_t size)
{
- int i;
+ int l, r;
- if (addr < chunk_low)
+ if (addr < chunk_low || chunk_high <= addr)
return;
- for (i = 0; i < AO_LISP_NCHUNK; i++) {
- if (ao_lisp_chunk[i].size && ao_lisp_chunk[i].old_addr == addr) {
+ /* Binary search for the location */
+ l = 0;
+ r = chunk_busy - 1;
+ while (l <= r) {
+ int m = (l + r) >> 1;
+ if (ao_lisp_chunk[m].old_addr < addr)
+ l = m + 1;
+ else
+ r = m - 1;
+ }
+ /*
+ * The correct location is always in 'l', with r = l-1 being
+ * the entry before the right one
+ */
+
#if DBG_MEM
- if (ao_lisp_chunk[i].size != size)
- ao_lisp_abort();
+ /* Off the right side */
+ if (l >= AO_LISP_NCHUNK)
+ ao_lisp_abort();
+
+ /* Off the left side */
+ if (l == 0 && chunk_busy && addr > ao_lisp_chunk[0].old_addr)
+ ao_lisp_abort();
#endif
- return;
- }
- if (ao_lisp_chunk[i].old_addr > addr) {
- memmove(&ao_lisp_chunk[i+1],
- &ao_lisp_chunk[i],
- (AO_LISP_NCHUNK - (i+1)) * sizeof (struct ao_lisp_chunk));
- ao_lisp_chunk[i].size = 0;
- }
- if (ao_lisp_chunk[i].size == 0) {
- ao_lisp_chunk[i].old_addr = addr;
- ao_lisp_chunk[i].size = size;
- return;
- }
- }
+
+ /* Shuffle existing entries right */
+ int end = min(AO_LISP_NCHUNK, chunk_busy + 1);
+
+ memmove(&ao_lisp_chunk[l+1],
+ &ao_lisp_chunk[l],
+ (end - (l+1)) * sizeof (struct ao_lisp_chunk));
+
+ /* Add new entry */
+ ao_lisp_chunk[l].old_addr = addr;
+ ao_lisp_chunk[l].size = size;
+
+ /* Increment the number of elements up to the size of the array */
+ if (chunk_busy < AO_LISP_NCHUNK)
+ chunk_busy++;
+
+ /* Set the top address if the array is full */
+ if (chunk_busy == AO_LISP_NCHUNK)
+ chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_addr +
+ ao_lisp_chunk[AO_LISP_NCHUNK-1].size;
+}
+
+static void
+reset_chunks(void)
+{
+ memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk));
+ chunk_high = ao_lisp_top;
+ chunk_busy = 0;
}
/*
return ao_lisp_poly_mark(*p, do_note_cons);
}
-int ao_lisp_collects;
+int ao_lisp_collects[2];
+int ao_lisp_freed[2];
+int ao_lisp_loops[2];
-void
-ao_lisp_collect(void)
+int ao_lisp_last_top;
+
+int
+ao_lisp_collect(uint8_t style)
{
+ int ret;
int i;
int top;
-#if DBG_MEM
int loops = 0;
+#if DBG_MEM
int marked;
int moved;
struct ao_lisp_record *mark_record = NULL, *move_record = NULL;
marked = moved = 0;
#endif
- ++ao_lisp_collects;
+ /* The first time through, we're doing a full collect */
+ if (ao_lisp_last_top == 0)
+ style = AO_LISP_COLLECT_FULL;
/* Clear references to all caches */
for (i = 0; i < (int) AO_LISP_CACHE; i++)
*ao_lisp_cache[i] = NULL;
- chunk_low = 0;
- top = 0;
+ if (style == AO_LISP_COLLECT_FULL) {
+ chunk_low = top = 0;
+ } else {
+ chunk_low = top = ao_lisp_last_top;
+ }
for (;;) {
- MDBG_DO(loops++);
+ loops++;
MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top);
/* Find the sizes of the first chunk of objects to move */
- memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk));
+ reset_chunks();
walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref);
#if DBG_MEM
marked = total_marked;
MDBG_MOVE("chunk %d %d not moving\n",
ao_lisp_chunk[i].old_addr,
ao_lisp_chunk[i].size);
- chunk_low = ao_lisp_chunk[i].old_addr + size;
}
chunk_first = i;
&ao_lisp_pool[ao_lisp_chunk[i].old_addr],
size);
top += size;
- chunk_low = ao_lisp_chunk[i].old_addr + size;
}
chunk_last = i;
if (chunk_last != AO_LISP_NCHUNK)
break;
+
+ chunk_low = chunk_high;
}
+
+ /* Compute amount of memory freed */
+ ret = ao_lisp_top - top;
+
+ /* Collect stats */
+ ++ao_lisp_collects[style];
+ ao_lisp_freed[style] += ret;
+ ao_lisp_loops[style] += loops;
+
ao_lisp_top = top;
+ if (style == AO_LISP_COLLECT_FULL)
+ ao_lisp_last_top = top;
MDBG_DO(memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk));
walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref));
-// printf ("collect. top %d loops %d\n", top, loops);
+ return ret;
}
/*
return ret;
}
-#ifdef MDBG_POOL
-static int AO_LISP_POOL_CUR = AO_LISP_POOL / 8;
-
-static void
-ao_lisp_poison(void)
-{
- int i;
-
- printf("poison\n");
- ao_lisp_mark_busy();
- for (i = 0; i < AO_LISP_POOL_CUR; i += 4) {
- uint32_t *a = (uint32_t *) &ao_lisp_pool[i];
- if (!busy_object(ao_lisp_busy, a))
- *a = 0xBEEFBEEF;
- }
- for (i = 0; i < AO_LISP_POOL_CUR; i += 2) {
- ao_poly *a = (uint16_t *) &ao_lisp_pool[i];
- ao_poly p = *a;
-
- if (!ao_lisp_is_const(p)) {
- void *r = ao_lisp_ref(p);
-
- if (ao_lisp_pool <= (uint8_t *) r &&
- (uint8_t *) r <= ao_lisp_pool + AO_LISP_POOL_CUR)
- {
- if (!busy_object(ao_lisp_busy, r)) {
- printf("missing reference from %d to %d\n",
- (int) ((uint8_t *) a - ao_lisp_pool),
- (int) ((uint8_t *) r - ao_lisp_pool));
- }
- }
- }
- }
-}
-
-#else
-#define AO_LISP_POOL_CUR AO_LISP_POOL
-#endif
-
#if DBG_MEM
void
ao_lisp_validate(void)
#endif
-
void *
ao_lisp_alloc(int size)
{
MDBG_DO(++dbg_allocs);
MDBG_DO(if (dbg_validate) ao_lisp_validate());
size = ao_lisp_size_round(size);
- if (ao_lisp_top + size > AO_LISP_POOL_CUR) {
-#ifdef MDBG_POOL
- if (AO_LISP_POOL_CUR < AO_LISP_POOL) {
- AO_LISP_POOL_CUR += AO_LISP_POOL / 8;
- ao_lisp_poison();
- } else
-#endif
- ao_lisp_collect();
-#ifdef MDBG_POOL
+ if (ao_lisp_top + size > AO_LISP_POOL) {
+ if (!ao_lisp_collect(AO_LISP_COLLECT_INCREMENTAL) &&
+ !ao_lisp_collect(AO_LISP_COLLECT_FULL))
{
- int i;
-
- for (i = ao_lisp_top; i < AO_LISP_POOL; i += 4) {
- uint32_t *p = (uint32_t *) &ao_lisp_pool[i];
- *p = 0xbeefbeef;
- }
- }
-#endif
-
- if (ao_lisp_top + size > AO_LISP_POOL) {
ao_lisp_error(AO_LISP_OOM, "out of memory");
return NULL;
}