/* Perform a mark_and_compact garbage collection, moving all live objects * to the start of the heap. Anything that we don't mark is dead. * * 1. Walk object graph starting from roots, marking live objects. * * 2. Walk all live objects and compute their forwarding addresses starting from start_of_heap. * * 3. Alter all non-NULL roots to point to the object's forwarding address. * * 4. For each live object: * a) alter all non-NULL managed pointer fields to point to the forwarding addresses. * b) unmark object * * 5. Physically move object to forwarding address towards front of heap and reset marked. * * This phase must be last as the object stores the forwarding address. When we move, * we overwrite objects and could kill a forwarding address in a live object. */ void gc() { if (DEBUG) printf("GC\n"); gc_mark(); // TODO: add next_live field to heap_object to avoid walking all objects to find live // oops actually must move objects from low to high ptr addresses. // reallocate all live objects starting from start_of_heap if (DEBUG) printf("FORWARD\n"); next_free_forwarding = heap; foreach_live(realloc_object); // for each marked (live) object, record forwarding address // make sure all roots point at new object addresses update_roots(); // can't move objects before updating roots; roots point at *old* location if (DEBUG) printf("UPDATE PTR FIELDS\n"); foreach_live(update_ptr_fields); // Now that we know where to move objects, update and move objects if (DEBUG) printf("COMPACT\n"); // TODO: can this be foreach_live()? foreach_object(move_live_objects_to_forwarding_addr); // also visits the dead to wack p->magic // reset highwater mark *after* we've moved everything around; foreach_object() uses next_free next_free = next_free_forwarding; // next object to be allocated would occur here if (DEBUG) printf("DONE GC\n"); }
void unmark() { foreach_object(unmark_object); }
void gc_unmark() { if (DEBUG) printf("UNMARK\n"); foreach_object(unmark_object); }