In a previous log entry, I discussed setting up a set()
function to help with keeping reference-counted objects in a garbage collection system in line. While I did play around with that for a while, I determined that what I needed to do to fix my reference-counting problems first was probably to write some form of consistency check. To that end, I wrote the following function. For reference, gc_list
points to the head of a singly-linked list (of cons cells) pointing to all allocated atoms in the system.
void __debug_gc_consistency(void) { assert(gc_list); atom_t *outer = gc_list; while (outer != nil) { if (ATOM_REFS(outer->car) == 0 && !(ATOM_FLAGS(outer->car) & FPROT) && outer->car != nil) { while (inner != nil) { if (inner->car != outer->car && (AS_ATOM(inner->car)->car == outer->car || AS_ATOM(inner->car)->cdr == outer->car)) { char *irep = atom_repr(inner->car); char *orep = atom_repr(outer->car); printf("\n%s still refers to %s\n", irep, orep); free(irep); free(orep); } inner = inner->cdr; } } outer = outer->cdr; } }
Ignoring the presence of the nasty ATOM_x
and AS_ATOM
macros (which I intend to change soon), the code amounts to a loop within a loop, such that all pairs of two atoms are checked to see if one is due to be garbage collected with another still pointing at it. Using this function, I have already eliminated a few bugs from the language's reader code, and I intend to apply it to the evaluation and macro systems as well. It will probably get cleaned up some in the process, as it is a bit rough-looking right now (and, for instance, still prints to stdout
instead of something more sane like stderr
).