In this assignment, you will implement a simulation of semi-space garbage collection.
Semi-space collectors are copy collectors, they work by partitioning the available memory into two equal halves, known as "to-space" and "from-space." New objects are allocated into from-space at the next available byte (an incrementing "bump pointer" keeps track of this location).
If the next allocation would not fit in the remaining from-space, garbage collection is triggered. The collector copies all objects reachable from a "root set" of variables into to-space, updating pointers to point at the objects' new locations. Copies, like allocations, are always made at the next available byte, with a bump pointer tracking the next free byte. Once garbage collection is complete, the designations of "from-space" and "to-space" are swapped, the allocation is made into the new from-space (if there is enough room), and the program continues.
You are provided with an interpreter for a toy language, which only supports the creation of three types of objects - Foo, Bar and Baz.
Each of the structures has pointers to other structures, which may be nil
. The language allows the user to instantiate objects, modify their pointer fields, and bind objects to variables.
Here are a couple of examples of programs in the language, which should be very self explanatory. Available commands are listed below.
x = Foo
y = Bar
z = Baz
x.c = Baz
x.d = y
PRINT
w = x.d
y = NULL
PRINT
The code above creates an object Foo (which is allocated on our heap), and binds it to x
.
It then allocates a Bar, and binds it to y
. Foo, Bar and Baz have member pointers that
can point to other objects, so on the fourth line we assign a new Baz to the field c
of x
(x.c = Baz
). After a sequence of operations, we call PRINT
to print the current state of the
heap, which contains a list of object IDs and their type.
As a sequence of allocations happen, the heap will run out of space. At this point, garbage collection will take place. Your job is to implement allocate() and collect(), everything else is implemented for you. The methods look like this:
-
obj_ptr Heap::allocate(int32_t size)
This method should allocatesize
bytes of space and return anobj_ptr
which contains the offset of the allocated space from the beginning of from-space. If there is not initially enough space, this method should callHeap::collect()
before allocating. If there is still not enough space, it should throw anOutOfMemoryException
. -
void Heap::collect()
This method should implement the actual semi-space garbage collection. Take extra care that you update pointers inside objects - ifx.c
is pointing to an object, and the object gets moved, the underlyingx.c
pointer must point to the new location. -
void Heap::debug()
This method is just a stub, provided for your convenience. It is run whenever the program encounters theDEBUG
command in its input. This command will never occur in the tests we use for grading, so use it to output anything you think will be useful when testing.
The language supports the following:
x = Foo
,x = Baz
instantiates an object of appropriate type, binding it to a variablex.c = y
allows you to set inner pointers in an object to point to other objectsx.d = NULL
allows setting a pointer to NULL. This can be used to 'lose` reference of an object, making it a candidate for garbage collection.PRINT
dumps the objects currently in the from space. It prints their unique id and their type.DEBUG
will call your debug method.COLLECT
can be used to force garbage collection. This won't be used in tests, we expect that allocating until there is not enough space will automatically trigger a garbage collection.
Your assignment will be graded by running a large number of generated programs, and checking the output against our reference implementation. We expect that you will test your garbage collector with input programs you write yourself, but take care to test all possible edge cases.
Finally, to compile the program, run make
, or manually compile all the .cpp
files.
You can feed program to your interpreter using ./a.out < example.program
.