[bitc-dev] Closure Conversion
Jonathan S. Shapiro
shap at eros-os.org
Thu Jul 7 15:55:30 EDT 2005
Swaroop:
I've been thinking about your closure conversion question, and I think
that we have had a small miscommunication.
First, a simple example:
(define f1
(let ((x 1))
(lambda () x)))
This needs to be rewritten into something like:
(define f1
(let ((x 1))
(make-closure (build-closure x) (lambda (closure) closure^.x))))
where BUILD-CLOSURE is part of the runtime and MAKE-CLOSURE is a closure
constructor. Neither BUILD-CLOSURE nor MAKE-CLOSURE can be expressed
within the language.
Having done this, we now hoist the (lambda ...) to:
(define **hoisted-5109764** (lambda (closure) closure^.x))
and rewrite f1 to:
(define f1
(let ((x 1))
(make-closure (build-closure x) **hoisted-5109764**)))
Ignoring optimization, BUILD-CLOSURE is first called to construct the
closure. This results in a reference to a runtime-internal closure type.
Let me imagine that the returned reference has the identity
**closure-234**. The return value of MAKE-CLOSURE is a reference to
heap-allocated *code*:
(lambda () (**hoisted-5109764** **closure-234**))
or in the more general case:
(lambda (args) (**hoisted-5109764** **closure-234** args))
If the lambda does not escape then the closure can be stack-allocated.
Closure conversion certainly should NOT be done blindly -- this
transform should only be done for procedures that require it.
Unfortunately, make-closure is syntax. When the variable that is closed
over is mutable, it is possible to construct cases where the closure
must contain a *reference* to the variable. In general, this can be done
by migrating the closed-over variable to the heap, but we would like to
avoid this for non-escaping closures. So for non-escaping closures, we
want the closure environment to contain an upward stack-ref.
Today, our rule is that stack-refs cannot appear in unions or structs,
so we cannot account for closures within the language.
An alternative would be to allow stack-refs within structs, but only if
the containing struct is itself stack-allocated and immutable. This
seems complex enough that I think we should handle make-closure as a
special case that builds a vector of special, internal refs.
shap
More information about the bitc-dev
mailing list