Next: , Previous: , Up: compiler   [Index]


17.19 Introducing closure makers

We can think of clambda structs as representing code that, once compiled, becomes the machine code stored in code objects implementing Scheme functions. This compiler pass wraps each clambda struct into a closure-maker struct, which represents code that, executed at run–time, builds and returns a closure object using the clambda’s code object as implementation. While wrapping clambda, a list of variable references that are free in the body of the clambda is gathered for future use.

NOTE The true purpose of this compiler pass is to gather lists of free variables referenced by clambda bodies. We might introduce the closure makers at a later pass and store the lists of free variables in the clambda structs; we introduce the closure makers here because it helps a bit in reasoning about the transformations.

Upon entering this compiler pass:

This compiler pass transforms:

(fix ((?lhs ?clambda-rhs) ...) ?body)

into:

(fix ((?lhs (closure-maker ?clambda-rhs)) ...) ?body)

The following bindings are exported by the library (vicare compiler).

Function: pass-introduce-closure-makers input

Perform code transformations traversing the whole hierarchy in input, which must be a struct instance representing recordised code, and building a new hierarchy of recordised code; return the new hierarchy.

This function wraps each clambda struct in the input recordised code into closure-maker structures, compiling a list of free variables referenced by each clambda.

Examples

This example generates a function with no free variables:

(lambda () '1)
→ (fix ((tmp_0 (closure-maker (lambda () (constant 1))
                                no-freevars)))
      tmp_0)

This example generates a multi–clause function with no free variables:

(case-lambda
 (() '1)
 ((a) a))
→ (fix ((tmp_0 (closure-maker (case-lambda
                                 (()    (constant 1))
                                 ((a_0) a_0))
                                no-freevars)))
      tmp_0)

This example generates a function with a free variable:

(let ((a ((primitive read))))
  (lambda () a))
→ (bind ((a_0 (funcall (primref read))))
      (fix ((tmp_0 (closure-maker (lambda () a_0)
                                  (freevars: a_0))))
        tmp_0))

This example generates a recursive function with no free variables other than the reference to itself:

(letrec ((f (lambda () (f))))
  f)
→ (fix ((f_0 (closure-maker
                  (lambda ()
                    (jmpcall asmlabel:f:clambda:case-0 f_0))
                  (freevars: f_0))))
      f_0)

The core language form:

(library-letrec*
    ((a a.loc (lambda () '1))
     (b b.loc (lambda () '2))
     (c c.loc (lambda () '3))
     (d d.loc '4))
  (quote #!void))

is transformed into:

(fix ((a_0 (closure-maker (lambda () (constant 1)) no-freevars))
      (b_0 (closure-maker (lambda () (constant 2)) no-freevars))
      (c_0 (closure-maker (lambda () (constant 3)) no-freevars)))
  (seq
    (funcall (primref $set-symbol-value/proc!)
             (constant a.loc) a_0)
    (funcall (primref $init-symbol-value!)
             (constant b.loc) b_0)
    (funcall (primref $init-symbol-value!)
             (constant c.loc) c_0)
    (bind ((d_0 (constant 4)))
      (seq
        (funcall (primref $init-symbol-value!)
                 (constant d.loc) d_0)
        (constant #!void)))))

Next: , Previous: , Up: compiler   [Index]