You have two options for this assignment:
Write your garbage collectors in the GC Collector Scheme language level. This language defines an interface to a program's stack and heap that you will use to implement garbage collection.
Your garbage collectors must implement the following functions:
init-allocator :: -> void The mutator implicitly calls this
function after initializing the heap and before calling any allocation
routines. It is essentially a callback into the allocator indicating that the
heap is ready.gc:cons :: first-addr rest-addr -> cons-addr returns the
address of a new cons cell with the given field addresses; the field addresses
are presumed to be already allocatedgc:cons? :: addr -> boolean returns a boolean that indicates
whether the given address refers to a cons cellgc:first :: cons-addr -> first-addr and gc:rest ::
cons-addr -> rest-addr return the fields of a given consgc:set-first! :: cons-addr first-addr -> void and
gc:set-rest! :: cons-addr rest-addr -> void set the addresses of the first and last pointers of a cons cellgc:alloc-flat :: atomic -> number allocates space for a flat value and returns the base address of the allocated blockgc:flat? :: addr -> boolean
returns a boolean that indicates whether the given address refers to
an atomic valuegc:deref :: addr -> atomic returns the atomic value stored at
the given addressTo help you write these functions, the GC Collector Scheme language defines an interface for the heap and the roots (the roots is the set of pointers into the heap from the stack):
heap-size :: -> number the size of the heapheap-offset :: -> addr the base address of the heap where allocation should beginheap-set! :: addr atomic -> void stores a value at the specified addressheap-ref :: addr -> atomic returns the value at the specified addressget-root-set :: -> listof root returns the roots of the collectionread-root :: root -> addr returns the address the root
referencesset-root! :: root addr -> void updates the root to reference the specified addressYou may write programs that exercise your garbage collectors using the GC Mutator Scheme language. This language is a subset of Scheme that uses a garbage collector that you specify. The first line of a test program must be:
(allocator-setup "collector.ss" heap-size heap-offset)
"collector.ss" must be the name of your collector's file. heap-size is the size of the heap your collector will use. heap-offset is the base address on the heap where allocation should start (usually 0).
The remainder of the program is in a subset of Scheme with numbers, symbols, lists, etc. The primitives of the language map directly to the procedures you define in your garbage collector.
To get you started, here are a sample mutator and a trivial collector that signals an error when the heap fills up. (this collector does signal an error with this mutator, if you don't increase the size of the heap.)
Store bookkeeping data for your collector on the heap provided by GC Collector Scheme. You may store 2-3 atomic values, such as addresses into the heap (for the semispaces) as variables in your garbage collector. We will assume they represent machine registers. However, all compound data structures must be on the heap.
Some final words of advice:
In the mark & sweep collector, maintain a free list in the heap. That is, you should not use any auxiliary data structure; instead, use the available space in the heap to keep track of the free list. You may use one extra box (“register”) to point to the start of the free list. You may need to adjust your allocation accordingly to have enough space to maintain free list pointers!
Include 3 generations, where the generation for new data (herein called G0) has two semispaces (as in stop & copy). G1 should consist of a single semispace.
Move data from G0 to G1 every third collection in G0. Move data from G1 to G2 whenever G1 fills up. You can reuse stop & copy for this collection.
To handle collection in G2, you may either divide G2 into semispaces and reuse stop & copy, or implement a compacting mark & sweep (described in the Wilson paper) for this generation. The latter is more realistic, but the former saves you from implementing another collection algorithm. Document your choice as a comment in your file.
Maintain the set of "dirty" references (from older to younger generations) in the heap, not as a Scheme variable.
Submit a separate file for each collector you implement, as well as two examples of test/mutator files that you used to test your collectors. Include a comment in each mutator file describing what it was designed to test. You only need to turn in printouts of the collectors.