Version 2, 2002-11-2 23:55
In this assignment, you will write two garbage collectors. First,
though, you need to write a function that will generate garbage:
Write the function tree-add1, which consumes a binary tree
of numbers, and returns a similar tree where each number is
incremented by one.
Convert this code to CPS, and then an explicit stack representation.
The code for tree-sum from the 2002-10-21 notes should be
Convert the function to use low-level representations of the stack
and heap, as done in the 2002-10-23 notes. You will
need to make one small change as compared to the notes: any value on
the stack that refers to a heap location should be stored in a box,
since the garbage collector may need to change its value.
Next, you will implement two garbage collectors: mark & sweep, and
stop & copy. The garbage collector should run whenever a memory
allocation fails, so you need to modify the functions that allot cells
on the heap.
You should submit two files, one for each garbage collector. Each
file should define the following variables and functions so that we
can evaluate your implementation:
|HEAP-SIZE : number
||number of cells in the heap
|alloc/empty-tree : (listof loc) -> loc
consumes a list of extra roots (see second bullet below), allocates an
empty tree on the heap, returns its location
|alloc/node : number loc loc (listof loc) -> loc
consumes a list of extra roots (see second bullet below) allocates an tree node on the heap, returns its location
|tree-add1 : loc -> loc
consumes the location of a tree, and returns the location of the
|location->tree : loc -> sexp
consumes the location of a tree, and returns some representation
of the tree
You will almost certainly want to use numbers for the loc
type above, but you're allowed to choose some other representation.
Finally, you should print a representation of the heap before and
after every garbage collection. You can use the Scheme
(printf "Before: Heap is ~s~n" Heap)
Some final words of advice:
You will want to test your program with small heap sizes, so that
the garbage collector runs frequently.
The garbage collector consumes a root set of live
references that includes both references on the stack and variables
in scope. Although we're explicitly modeling the stack, we don't
model variables explicitly. Therefore, you will need to pass
any variables containing heap references as an argument to the
garbage collector. Furthermore, since the garbage collector may
change the values of these references, you should pass them as a
list of boxed locations.
You may find it convenient to use the Scheme construct
set!, which allows you to mutate a variable without using
boxes. We recommend you use this feature only in one instance: when
swapping the semispaces in the stop & copy collector. This will
save you the trouble of unboxing the heap every time you use it.
- Is it ok to maintain the freelist as a list of pairs?
You are supposed to maintain the 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 free list.) You may
need to adjust your allocation accordingly to have enough space to
maintain free list pointers!
- Do we have to compact memory in mark-and-sweep?
- Can we assume that there will always be enough heap space
to allocate the initial input tree?
No, you can't assume there will be enough heap space for the initial
tree. Of course, any time there is not enough free memory to allocate
the number of cells needed (after garbage collection), the program
should terminate with an "out of memory" error.
- What changed between versions 1 and 2?
The interface to alloc/empty-tree and alloc/node.
They now accept one more parameter: a list of extra roots. Note
that we will still allow submissions that conform to the previous
- How should we signal an out-of-memory error?
Call the Scheme function error. (If you're following the
newsgroup, please ignore any messages on using let/cc for