EECS 395 Programming Languages: Homework 7

Due: Wednesday, February 24th, 2010, 5pm

Part 1 – Two Space Collection

Implement a two space copying collector, as described in lecture 11. Use four state variables in your collector: the allocation pointer, the active semi-space, and two pointers that you use only during collection, one pointing to the left and one to the right side of the queue for copying the data. (It is possible to do this with only three state variables, and it might be possible with only two, but I recommend four.)

Part 2 – Constants

You allocator should keep (at least) the values empty (aka '()), #t, #f, and the first 3 natural numbers (0, 1, and 2) in a fixed place in the heap.

You may assume that your heap size is a multiple of 2 and contains at least 12 cells.

Part 3 – Quality

You collector must be able to run these three programs without running out of space:

#lang planet plai/plai:1:20/mutator
(allocator-setup "gc.ss" 200)
(define (count-down n)
  (cond
    [(zero? n) (count-down 20)]
    [else (count-down (- n 1))]))
(count-down 0)

#lang planet plai/plai:1:20/mutator
(allocator-setup "gc.ss" 200)
(define (mk-list n)
  (cond
    [(zero? n) '()]
    [else (cons n (mk-list (- n 1)))]))
(define (forever)
  (mk-list 10)
  (forever))
(forever)

#lang planet plai/plai:1:20/mutator
(allocator-setup "gc.ss" 200)
(define (proc-lst n)
  (cond
    [(zero? n) (lambda () 0)]
    [else (let ([n1 (proc-lst (- n 1))])
            (lambda () (+ (n1) n)))]))
(define (forever)
  ((proc-lst 10))
  (forever))
(forever)

PLAI Allocation: a No No

Your garbage collector may not do any PLAI-level allocation (except stack space). This means that the functions cons, map, and list are off limits. Similarly, the constructors generated by define-type are off limits (e.g., lam, id, num, add, and sub from earlier assignments). Closures also require allocation, so you can only define functions at the top-level of the file (no lambda expressions in nested scopes).

You may used a fixed number of global variables in your program (this is intended to simulate registers). Note that using zero such variables will make it easier to test, since with-heap will control the entire state of your collector.

The only exceptions: you may call procedure-roots and get-root-list, both of which allocate.

You may, of course, use functions that allocate in your tests to build up example heaps. For example, you may find functions like this to be helpful:

  (define prefix (list ....)) ;; contains some fixed set of values
  (define (vector/prefix . args)
    (apply vector (append prefix args)))
The vector/prefix function builds a vector with the elements from the list prefix at the beginning of the vector and the arguments passed to vector/prefix coming next. Note the . in the argument list of vector/prefix; that causes PLAI to package up all of the arguments into a list. You can also write things like (fname a b . c) as a function header; that is a function that takes at least two arguments, putting the first two into a and b and the packaging up the rest into a list in c.

If you are unsure what primitives allocate memory, ask.

Hint

If you insert calls to read in the middle of your collector, drscheme will pause until you type something and hit return in the interactions window. This allows you to see what is happening at various stages in the process of collection (or allocation) and thus can help you understand what is going on.

Even Better Hint

Only use the previous hint to help you formulate test cases. The edit/debug/fix cycle leads to much pain that the edit/debug/write-test-cases/fix cycle avoids. (And, of course, you only enter into this cycle with some baseline set of test cases that you've written up front.)

Template

Below is a list of the functions required to implement a garbage collector, along with their contracts and bogus implementations. Note that the contracts may appear to be false if your collector is broken.

;; init-allocator : -> void
(define (init-allocator) (void))

;; gc:deref : loc -> heap-value
;; must signal an error if fl-loc doesn't point to a flat value
(define (gc:deref fl-loc) #t)

;; gc:alloc-flat : heap-value -> loc
(define (gc:alloc-flat fv) 0)

;; gc:cons : loc loc -> loc
;; hd and tl are guaranteed to have been earlier
;; results from either gc:alloc-flat or gc:cons
(define (gc:cons hd tl) 0)

;; gc:first : loc -> loc
;; must signal an error of pr-loc does not point to a pair
(define (gc:first pr-loc) 0)

;; gc:rest : loc -> loc
;; must signal an error of pr-loc does not point to a pair
(define (gc:rest pr-loc) 0)

;; gc:flat? : loc -> boolean
;; loc is guaranteed to have been an earlier
;; result from either gc:alloc-flat or gc:cons
(define (gc:flat? loc) #t)

;; gc:cons? : loc -> boolean
;; loc is guaranteed to have been an earlier
;; result from either gc:alloc-flat or gc:cons
(define (gc:cons? loc) #f)

;; gc:set-first! : loc loc -> void
;; must signal an error of pr-loc does not point to a pair
(define (gc:set-first! pr-loc new) (void))

;; gc:set-rest! : loc loc -> void
;; must signal an error of pr-loc does not point to a pair
(define (gc:set-rest! pr-ptr new) (void))

Handin

Handin your garbage collector. It should begin with the line

#lang planet plai/plai:1:20/collector

(Upgrading to version 1:20 of plai will get you the heap GUI you saw in class, a random mutator generator and various bug fixes.)

Note that the handin server will not run any tests on your collector. This time it is your job to make sure you've tested well enough. Use unit testing, like we did in class. Use the example mutators above. Use the random mutator generator in PLAI.


Last update: Tuesday, February 23rd, 2010
robby@eecs.northwestern.edu