CLOSURES

In languages (such as C) without nested functions, the run-time representation of a function value can be the address of the machine code for that function. This address can be passed as an argument, stored in a variable, and so on; when it is time to call the function, the address is loaded into a machine register, and the "call to address contained in register" instruction is used. In the Tree intermediate representation, this is easy to express. Suppose the function starts at label L123; we assign the address into a variable t57 using

MOVE(TEMP(t57) NAME(L123))

and then call the function with something like

CALL(TEMP(t57),... parameters ...).

But this will not work for nested functions; if we represent the h function by an address, in what outer frame can it access the variable n? Similarly, how does the g function access the variable f? The solution is to represent a function variable as a closure: a record that contains the machine-code pointer and a way to access the necessary nonlocal variables. This is very much like an object with a single method (the machine-code pointer) and several instance variables. The portion of the closure giving access to values of variables is often called the environment. Closures need not be based on objects; any other data structure that gives access to nonlocal variables will do. However, in this chapter we will use objects for simplicity.

HEAP-ALLOCATED ACTIVATION RECORDS

The local variables for add must not be destroyed when add returns, because n is still needed for the execution of h. To solve this problem, we can create a heap-allocated object to hold each function's local variables; then we rely on the garbage collector to reclaim the object when all references (including inner-nested function values) have disappeared. A refinement of this technique is to save on the heap only those variables that escape (that are used by inner-nested functions). The stack frame will hold spilled registers, return address, and so on, and also a pointer to the escaping-variable record. The escaping-variable record holds (1) any local variables that an inner-nested procedure might need and (2) a pointer to the environment (escaping-variable record) provided by the enclosing function. This pointer from one closure to the closure of the statically enclosing function is called the static link; see .
Image 15.2: Closures for execution of twice(add(5)). SL=static link; RV=return value; EP=escaping-variables-pointer or environment-pointer.