Herewith are some brief notes on garbage collection, current on 2012-07-16:
Right now cowjac has no garbage collection (which means garbage accrues indefinitely), but most of the hooks are in place for some. Actually adding a simple mark/sweep collector should be easy.
The basic setup is:
- A manual chain of stackframes is maintained by the compiler, so whenever a method is called, a new stackframe object is allocated (on the stack) and added to the chain. Whenever a reference-like local variable is modified, a copy gets stored in this object.
- A manual list of root objects is also maintained (via ContainsGlobalReferences). Each thread's root stackframe is one of these.
- All objects that contain references implement a mark() which recursively marks all contained references (if not already marked). Stackframes count here: when a stackframe is marked it marks its reference-like locals and then calls mark() on the next frame on the stack.
- A third list of all allocated objects is maintained by the root object constructor and destructor.
- Objects may be marked, and may be immutable.
In order to do a collection, then, all we need to do is:
- Stop all threads at a safe point. (How to be determined later.)
- Traverse the list of all objects and clear the mark.
- Traverse the list and mark all immutable objects.
- Traverse the list of roots and mark all references recursively. (Including stackframes.)
- Now, any object which is not marked is garbage, so traverse the list again and delete it.
- Resume threads.
This is a stop-the-world collector, and is not necessarily that efficient. But it should be simple to implement, reasonably easy to debug, and may stand a chance of working.
Note that there a couple of places in cowjac where live references aren't anchored: exceptions in flight, for example. This imposes certain constraints on what we can do. These can probably all be fixed later, but for now this approach should be fine.