# Oberon's garbage collector

This garbage collector is used for pointers to dynamically allocated records.
It's pretty different from [mem/cons], the other GC in Dusk, because allocation
sizes varies. It's not an easy 8 bytes across the board.

This GC is implemented as one big linked list where elements have this
structure:

+00 link to next
+04 used?
+08 link to type
... record data

This structure allows us to use "element+0c" as an address that serves as a
record pointer. When we want to dynamically access our type, we use "pointer-4".

When NEW is called, we look in the LL for an unused element of a matching type.
If there is none, we allocate a new one and add it to the list. We never free
that memory, only mark it as used or unused. We don't reassign that memory to
another type either. Such memory is always reserved for memory of that
particular type.

Having to traverse a linked list makes this GC slower than [mem/cons], but
that's the price to pay to have heterogenous sizes.

## GC slot

For the collection mechanism to work, we need to have a list of all addresses
that point to GC-able data. We call these GC slots.

Whenever a global variable is added, we potentially add one or more GC slot,
depending on the type of the variable.

## Collecting

The collection mechanism is designed to be ran in an idle loop. It doesn't scan
PS or RS, only global variables of all modules.

When comes the time to collect, we begin by setting all "used?" flags to false.
Then, we traverse all GC slots and set "pointer-8" to 1. Then, we scan the
structure and recurse this process for each record pointer.

## API

addgcslot ( addr -- )
  Register "addr" as a POINTER holder, that is a GC slot.

?addgcslot ( type addr -- )
  If "type" is a POINTER, call "addgcslot".

  If "type" is a struct, recurse "?addgcslot" for each field.

  If type is an ARRAY, we recursively call "?addgcslot" for each element.

newptr ( type -- a )
  If a free slot of the specified type exists, mark it as used and yield its
  address. Otherwise, allocate a new pointer of the specified type and yield it.

gc ( -- )
  Collect the garbage as described above.

.gc ( -- )
  Prints a list of addresses, along with their type, currently marked as used
  by the GC.

resetgc ( -- )
  Remove all slots and pointers. This leaks all pointers.

  There's no good reason to use this except for testing.
