#include "ao_lisp.h"
#include <stdio.h>
-uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4)));
-
#ifdef AO_LISP_MAKE_CONST
#include <stdlib.h>
uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));
+#define ao_lisp_pool ao_lisp_const
+#undef AO_LISP_POOL
+#define AO_LISP_POOL AO_LISP_POOL_CONST
+#else
+uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4)));
+#endif
+
+#if 0
+#define DBG_DUMP
+#define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool))
+#define DBG(...) printf(__VA_ARGS__)
+static int move_dump;
+static int move_depth;
+#define DBG_RESET() (move_depth = 0)
+#define DBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0)
+#define DBG_MOVE_IN() (move_depth++)
+#define DBG_MOVE_OUT() (move_depth--)
+#else
+#define DBG(...)
+#define DBG_RESET()
+#define DBG_MOVE(...)
+#define DBG_MOVE_IN()
+#define DBG_MOVE_OUT()
#endif
uint8_t ao_lisp_exception;
return 0;
}
+static int
+busy_object(uint8_t *tag, void *addr) {
+ int base;
+
+ if (!addr)
+ return 1;
+
+ if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr)
+ return 1;
+
+ base = (uint8_t *) addr - ao_lisp_pool;
+ base = limit(base);
+ if (busy(tag, base))
+ return 1;
+ return 0;
+}
+
static void *move_old, *move_new;
static int move_size;
{
int i;
+ DBG_RESET();
+ DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new));
+ DBG_MOVE_IN();
memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving));
for (i = 0; i < AO_LISP_ROOT; i++)
- if (ao_lisp_root[i].addr) {
+ if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) {
void *new;
+ DBG_MOVE("root %d\n", DBG_OFFSET(*ao_lisp_root[i].addr));
new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr);
if (new)
*ao_lisp_root[i].addr = new;
}
+ DBG_MOVE_OUT();
+ DBG_MOVE("move done\n");
}
+#ifdef DBG_DUMP
static void
-collect(void)
+dump_busy(void)
+{
+ int i;
+ printf("busy:");
+ for (i = 0; i < ao_lisp_top; i += 4) {
+ if ((i & 0xff) == 0)
+ printf("\n");
+ else if ((i & 0x1f) == 0)
+ printf(" ");
+ if (busy(ao_lisp_busy, i))
+ putchar('*');
+ else
+ putchar('-');
+ }
+ printf ("\n");
+}
+#define DUMP_BUSY() dump_busy()
+#else
+#define DUMP_BUSY()
+#endif
+
+void
+ao_lisp_collect(void)
{
int i;
+ int top;
/* Mark */
memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy));
+ DBG("mark\n");
for (i = 0; i < AO_LISP_ROOT; i++)
- if (ao_lisp_root[i].addr)
+ if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) {
+ DBG("root %p\n", *ao_lisp_root[i].addr);
ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr);
+ }
+ DUMP_BUSY();
/* Compact */
- ao_lisp_top = 0;
- for (i = 0; i < AO_LISP_POOL; i += 4) {
+ DBG("find first busy\n");
+ for (i = 0; i < ao_lisp_top; i += 4) {
if (!busy(ao_lisp_busy, i))
break;
}
- ao_lisp_top = i;
- while(i < AO_LISP_POOL) {
+ top = i;
+ while(i < ao_lisp_top) {
if (busy(ao_lisp_busy, i)) {
+ DBG("busy %d -> %d\n", i, top);
move_old = &ao_lisp_pool[i];
- move_new = &ao_lisp_pool[ao_lisp_top];
+ move_new = &ao_lisp_pool[top];
move_size = 0;
move_object();
+ DBG("\tbusy size %d\n", move_size);
+ if (move_size == 0)
+ abort();
clear_object(ao_lisp_busy, move_old, move_size);
+ mark_object(ao_lisp_busy, move_new, move_size);
i += move_size;
- ao_lisp_top += move_size;
+ top += move_size;
+ DUMP_BUSY();
} else {
i += 4;
}
}
+ ao_lisp_top = top;
}
void
ao_lisp_mark(const struct ao_lisp_type *type, void *addr)
{
+ if (!addr)
+ return;
if (mark_object(ao_lisp_busy, addr, type->size(addr)))
return;
type->mark(addr);
return mark_object(ao_lisp_busy, addr, size);
}
+/*
+ * After the object has been moved, we have to reference it
+ * in the new location. This is only relevant for ao_lisp_poly_move
+ * as it needs to fetch the type byte from the object, which
+ * may have been overwritten by the copy
+ */
+void *
+ao_lisp_move_map(void *addr)
+{
+ if (addr == move_old) {
+ if (busy_object(ao_lisp_moving, addr))
+ return move_new;
+ }
+ return addr;
+}
+
static void *
check_move(void *addr, int size)
{
if (addr == move_old) {
- memmove(move_new, move_old, size);
- move_size = (size + 3) & ~3;
+ DBG_MOVE("mapping %d -> %d\n", DBG_OFFSET(addr), DBG_OFFSET(move_new));
+ if (!busy_object(ao_lisp_moving, addr)) {
+ DBG_MOVE(" copy %d\n", size);
+ memmove(move_new, move_old, size);
+ move_size = (size + 3) & ~3;
+ }
addr = move_new;
}
return addr;
void *
ao_lisp_move(const struct ao_lisp_type *type, void *addr)
{
+ uint8_t *a = addr;
int size = type->size(addr);
if (!addr)
return NULL;
+#ifndef AO_LISP_MAKE_CONST
+ if (AO_LISP_IS_CONST(addr))
+ return addr;
+#endif
+ DBG_MOVE("object %d\n", DBG_OFFSET(addr));
+ if (a < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= a)
+ abort();
+ DBG_MOVE_IN();
addr = check_move(addr, size);
- if (mark_object(ao_lisp_moving, addr, size))
+ if (mark_object(ao_lisp_moving, addr, size)) {
+ DBG_MOVE("already moved\n");
+ DBG_MOVE_OUT();
return addr;
+ }
+ DBG_MOVE_OUT();
+ DBG_MOVE("recursing...\n");
+ DBG_MOVE_IN();
type->move(addr);
+ DBG_MOVE_OUT();
+ DBG_MOVE("done %d\n", DBG_OFFSET(addr));
return addr;
}
if (!addr)
return NULL;
+ DBG_MOVE("memory %d\n", DBG_OFFSET(addr));
+ DBG_MOVE_IN();
addr = check_move(addr, size);
- if (mark_object(ao_lisp_moving, addr, size))
- return NULL;
+ if (mark_object(ao_lisp_moving, addr, size)) {
+ DBG_MOVE("already moved\n");
+ DBG_MOVE_OUT();
+ return addr;
+ }
+ DBG_MOVE_OUT();
return addr;
}
void *addr;
size = ao_lisp_mem_round(size);
-#ifdef AO_LISP_MAKE_CONST
- if (ao_lisp_top + size > AO_LISP_POOL_CONST) {
- fprintf(stderr, "Too much constant data, increase AO_LISP_POOL_CONST\n");
- exit(1);
- }
- addr = ao_lisp_const + ao_lisp_top;
-#else
if (ao_lisp_top + size > AO_LISP_POOL) {
- collect();
+ ao_lisp_collect();
if (ao_lisp_top + size > AO_LISP_POOL) {
ao_lisp_exception |= AO_LISP_OOM;
return NULL;
}
}
addr = ao_lisp_pool + ao_lisp_top;
-#endif
ao_lisp_top += size;
return addr;
}
ao_lisp_root_add(const struct ao_lisp_type *type, void *addr)
{
int i;
+ DBG("add root type %p addr %p\n", type, addr);
for (i = 0; i < AO_LISP_ROOT; i++) {
if (!ao_lisp_root[i].addr) {
ao_lisp_root[i].addr = addr;
return 1;
}
}
+ abort();
return 0;
}