build-a-garbage-collector / lesson-05.md
Lesson 05 · The object model and heap

The root set

Reachability has to start somewhere. The roots are the objects the program can reach directly - the starting points of every trace. Today you build the root set so the collector knows where liveness begins.

The goal

Track a set of root references and report membership.

Start here - the target
TO DO
Scenario: The heap tracks which objects are roots
Givena heap with objects a, b, c allocated (ids 0, 1, 2)
WhenAddRoot(0) and AddRoot(2) are called
ThenIsRoot(0) and IsRoot(2) are true, IsRoot(1) is false, and Roots() returns [0, 2]
Andafter RemoveRoot(0), IsRoot(0) is false and Roots() returns [2]
Background

An object is live if the running program can still get to it. In a real runtime the starting points are the values on the stack, in registers, and in globals - the things the program holds directly. We model those directly-held references as the root set: a set of Refs the collector treats as reachable by definition. Anything reachable from a root by following fields is live; anything else is garbage.

Add a roots set to the heap (initialize it in NewHeap) with add, remove, and membership. Have Roots() return the members in ascending order so traces are deterministic. This is the other half of the reachability question: the census says what exists, the roots say where liveness begins. Next lesson you wire objects and roots into a real graph, and the chapter after that traces it.

Make it work
// a set of the objects the program holds directly
func (h *Heap) AddRoot(r Ref) { h.roots[r] = true }
func (h *Heap) RemoveRoot(r Ref) { delete(h.roots, r) }
func (h *Heap) IsRoot(r Ref) bool { return h.roots[r] }
func (h *Heap) Roots() []Ref { /* keys of h.roots, sorted ascending */ }
CheckpointDONE
The heap tracks its root set and reports membership. Commit and stop here.