+static const struct ao_lisp_type *ao_lisp_types[AO_LISP_NUM_TYPE] = {
+ [AO_LISP_CONS] = &ao_lisp_cons_type,
+ [AO_LISP_INT] = NULL,
+ [AO_LISP_STRING] = &ao_lisp_string_type,
+ [AO_LISP_OTHER] = (void *) 0x1,
+ [AO_LISP_ATOM] = &ao_lisp_atom_type,
+ [AO_LISP_BUILTIN] = &ao_lisp_builtin_type,
+ [AO_LISP_FRAME] = &ao_lisp_frame_type,
+ [AO_LISP_FRAME_VALS] = &ao_lisp_frame_vals_type,
+ [AO_LISP_LAMBDA] = &ao_lisp_lambda_type,
+ [AO_LISP_STACK] = &ao_lisp_stack_type,
+ [AO_LISP_BOOL] = &ao_lisp_bool_type,
+ [AO_LISP_BIGINT] = &ao_lisp_bigint_type,
+ [AO_LISP_FLOAT] = &ao_lisp_float_type,
+};
+
+static int
+ao_lisp_mark_ref(const struct ao_lisp_type *type, void **ref)
+{
+ return ao_lisp_mark(type, *ref);
+}
+
+static int
+ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons)
+{
+ return ao_lisp_poly_mark(*p, do_note_cons);
+}
+
+#if DBG_MEM_STATS
+int ao_lisp_collects[2];
+int ao_lisp_freed[2];
+int ao_lisp_loops[2];
+#endif
+
+int ao_lisp_last_top;
+
+int
+ao_lisp_collect(uint8_t style)
+{
+ int i;
+ int top;
+#if DBG_MEM_STATS
+ int loops = 0;
+#endif
+#if DBG_MEM
+ struct ao_lisp_record *mark_record = NULL, *move_record = NULL;
+
+ MDBG_MOVE("collect %d\n", ao_lisp_collects[style]);
+#endif
+ MDBG_DO(ao_lisp_frame_write(ao_lisp_frame_poly(ao_lisp_frame_global)));
+
+ /* 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;
+ if (style == AO_LISP_COLLECT_FULL) {
+ chunk_low = top = 0;
+ } else {
+ chunk_low = top = ao_lisp_last_top;
+ }
+ for (;;) {
+#if DBG_MEM_STATS
+ loops++;
+#endif
+ MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top);
+ /* Find the sizes of the first chunk of objects to move */
+ reset_chunks();
+ walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref);
+#if DBG_MEM
+
+ ao_lisp_record_free(mark_record);
+ mark_record = ao_lisp_record_save();
+ if (mark_record && move_record)
+ ao_lisp_record_compare("mark", move_record, mark_record);
+#endif
+
+ DUMP_BUSY();
+
+ /* Find the first moving object */
+ for (i = 0; i < chunk_last; i++) {
+ uint16_t size = ao_lisp_chunk[i].size;
+
+#if DBG_MEM
+ if (!size)
+ ao_lisp_abort();
+#endif
+
+ if (ao_lisp_chunk[i].old_offset > top)
+ break;
+
+ MDBG_MOVE("chunk %d %d not moving\n",
+ ao_lisp_chunk[i].old_offset,
+ ao_lisp_chunk[i].size);
+#if DBG_MEM
+ if (ao_lisp_chunk[i].old_offset != top)
+ ao_lisp_abort();
+#endif
+ top += size;
+ }
+
+ /*
+ * Limit amount of chunk array used in mapping moves
+ * to the active region
+ */
+ chunk_first = i;
+ chunk_low = ao_lisp_chunk[i].old_offset;
+
+ /* Copy all of the objects */
+ for (; i < chunk_last; i++) {
+ uint16_t size = ao_lisp_chunk[i].size;
+
+#if DBG_MEM
+ if (!size)
+ ao_lisp_abort();
+#endif
+
+ MDBG_MOVE("chunk %d %d -> %d\n",
+ ao_lisp_chunk[i].old_offset,
+ size,
+ top);
+ ao_lisp_chunk[i].new_offset = top;
+
+ memmove(&ao_lisp_pool[top],
+ &ao_lisp_pool[ao_lisp_chunk[i].old_offset],
+ size);
+
+ top += size;
+ }
+
+ if (chunk_first < chunk_last) {
+ /* Relocate all references to the objects */
+ walk(ao_lisp_move, ao_lisp_poly_move);
+
+#if DBG_MEM
+ ao_lisp_record_free(move_record);
+ move_record = ao_lisp_record_save();
+ if (mark_record && move_record)
+ ao_lisp_record_compare("move", mark_record, move_record);
+#endif
+ }
+
+ /* If we ran into the end of the heap, then
+ * there's no need to keep walking
+ */
+ if (chunk_last != AO_LISP_NCHUNK)