compiler-constructionssa

SSA representation of updating a variable in enclosing scope


When a compiler is using SSA form to represent code, updates to local variables become new variables. But this doesn't always work when the variable is in an enclosing scope, e.g. (using JavaScript syntax for illustration, the situation could occur in many languages):

function f() {
    var x = 1;
    function g() {
        x++;
    }
    ...
}

What's the usual way to represent this?


Solution

  • A mutable free variable used in a closure (x in your example) needs to be implicitly "boxed".

    There are two issues to consider. First, lifetime: the variable might outlive the scope in which it was created. (f could return g, or store it in a persistent container.) Second, sharing: the variable may be modified by f, g, or any other function created by f.

    The simplest solution is to change the variable to a "box" (a container of one object which is the variable's value). The box itself is immutable (that is, the name always refers to the same box). Modification of and reference to the value of the variable become container setter and getter methods. Of course, the storage for the value must be dynamically allocated and reclaimed when no longer needed (as with any container).

    There are optimisations available in some cases -- possibly even most cases.

    First, if the variable is never modified, it may be possible to give each closure a copy of the value instead of boxing the value.

    Second, if the variable is unshared -- it is not closed by any other function created by the execution of f and it is not referenced by f after the creation of g -- the variable could simply be moved into g's closure.

    In effect, in both the above cases, the closure itself becomes the box, but this has the advantage of not requiring a separate dynamic allocation.

    Proving the validity of these optimisations in a particular program requires good static analysis. The first one is straightforward, since modification is easy to detect syntactically, but the second one requires flow analysis (at least).

    In the above, I used a conservative description of the circumstances in which the optimisation might be applied which requires only simple flow analysis; detecting other possible applications is more complicated.