Here are some data that can be used to check the closure analysis of Assignment #1.
Program Function Expressions Escaping Variables ------- -------------------- -------- --------- adt.q 15 12 53 array.q 2 1 9 binarytree.q 24 14 75 fact.q 1 0 4 fib.q 2 0 9 permute.q 12 7 30 polymorph.q 1 1 2 primes.q 5 4 16 quicksort.q 22 11 63 rev.q 8 0 28 selectionsort.q 7 1 30 small0.q 0 0 1 small1.q 0 0 2 small2.q 0 0 1 small3.q 0 0 5 small4.q 0 0 5 small5.q 0 0 4 small6.q 0 0 4 small7.q 0 0 4 small8.q 0 0 8
Let's take a closer look at primes.q. This program contains 5 function expressions and 16 variables:
divides_1 in_9
x_2 k_10
counter_3 result_11
filter_4 in_12
primes_5 max_13
max_6 next_14
a_7 read_int
b_8 write_int
--
-- primes.q with explicit function expressions
--
{
proc (int, int) -> bool divides =
-- escapes
-- free: { }
function (int a, int b) -> bool {
(b/a) * a = b
};
ref int x = new 1;
proc () -> int counter() =
-- escapes
-- free: {x_2}
function () -> int {
x := x + 1;
x
};
proc (proc () -> int, int) -> proc () -> int filter =
-- escapes
-- free: {divides_1, filter_4}
function (proc () -> int in, int k) -> proc () -> int {
-- escapes
-- free: {divides_1, filter_4, in_9, k_10}
function () -> int {
int result = in();
if divides (k, result)
then (filter (in, k)) ()
else result
}
};
proc (proc () -> int, in) -> string primes =
-- does not escape
-- free: {filter_4, primes_5, write_int}
function (proc () -> int in, int max) -> string {
int next = in();
write_int(next);
if next < max
then primes (filter (in, next), max)
else "done"
};
int max = read_int();
primes (counter, max)
}
You have many choices for Assignment #2:
I implemented three levels of optimization:
; ; (qopt 0): No optimization. ; ; (qopt 1): ; ; Performs passive first order closure analysis to: ; find all function expressions; ; compute their free variables; ; mark all function expressions that escape; ; mark all variables that occur free in any function ; expression. ; Doesn't allocate a rib for blocks with no declarations. ; If none of the variables declared at the head of a block ; escapes, then they are allocated on the stack. ; Allocates formal parameters on the stack. ; Closes all function expressions by copying their free ; variables into the closure (or the rib containing the ; free variable, if it resides in a heap-allocated rib). ; ; (qopt 2): ; ; Closure analysis marks only those variables that occur ; free in a function expression that escapes. ; Variables that name function expressions that do not ; escape are marked as known. ; Function expressions that do not escape are not closed. ; Calls to known functions are compiled as in Ada83.
If a function expression occurs as the right hand side of
a declaration of some variable f, and f
occurs only in
call position, then the compiler can locate all calls to
the procedures that will result from evaluating the function
expression.
Let's call f a known procedure, because the
compiler knows exactly where f is called.
Lambda lifting is an optimization that
The primes.q program contains three known procedures:
divides, filter, and primes.
All three are already declared at the outermost block.
That means they have no free variables, so lambda lifting is
trivial.