Next: compiler topics locbind, Up: compiler topics [Index]
Bindings defined by the core language form library-letrec* are
named top level bindings; they are akin to the C language “global
variables”. The form library-letrec* has the format:
(library-letrec* ((?lex ?loc ?init) ...) ?body)
in which: ?lex is a lexical gensym that uniquely identifies the
binding in the core language form; ?loc is a location gensym which
will be used at run–time to hold the current value of the binding in
its value slot; ?init is the initialisation expression.
References to top level bindings are represented by standalone
?lex gensyms; assignments to top level bindings are represented by
set! forms:
(set! ?lex ?rhs)
where the right–hand side expression ?rhs will, at run–time, evaluate to the new binding’s value.
The library-letrec* form is recordised into a rec*bind
form:
(rec*bind ((?prel ?init) ...) ?body)
in which ?prel is a prelex struct holding both the
?lex and ?loc gensyms. References to top level bindings are
represented by standalone prelex structs; assignments to top
level bindings are represented by assign structs:
(assign ?prel ?rhs)
Since the actual value of a top level binding is stored in the
value field of a loc gensym:
(funcall (primref $symbol-value) (constant ?loc))
which extracts the value from slot value of ?loc.
(funcall (primref $set-symbol-value!)
(constant ?loc)
?rhs)
which stores a new value in the slot value of ?loc.
(funcall (primref $init-symbol-value!)
(constant ?loc)
?rhs)
which stores a new value in the slot value of ?loc and,
only if the value is recognised at run–time as being closure object,
also stores value in the slot proc.
rec*bind formsA compiler pass takes care of performing “letrec optimisation”:
structs of type rec*bind are transformed into a nested
hierarchy of bind, fix and assign forms.
Different cases must be handled in different ways.
(bind ((?prel ?init)) ?body)
the transformation of references is straightforward. As example, let’s consider:
(library-letrec*
((a.lex a.loc '1)
(b.lex b.loc '2))
((primitive display) a.lex b.lex))
which is recordised and transformed into:
(bind ((a.lex_0 (constant 1)))
(bind ((b.lex_0 (constant 2)))
(funcall (primref display) (constant 1) (constant 2))))
in which the references to bindings are integrated by the source optimiser.
(bind ((?prel ?init)) ?body)
the transformation of references and assignments is straightforward. As example, let’s consider:
(library-letrec*
((a.lex a.loc '1)
(b.lex b.loc '2))
(begin
(set! a.lex '11)
(set! b.lex '22)
((primitive display) a.lex b.lex)))
which is recordised and transformed into:
(bind ((a.lex_0 (constant 1)))
(bind ((b.lex_0 (constant 2)))
(seq
(funcall (primref $set-symbol-value!)
(constant a.loc)
(constant 11))
(funcall (primref $set-symbol-value!)
(constant b.loc)
(constant 22))
(funcall (primref display)
(funcall (primref $symbol-value)
(constant a.loc))
(funcall (primref $symbol-value)
(constant b.loc))))))
(bind ((?prel (constant #<void>))) (assign ?prel ?init) ?body)
this might happen when the initialisation expressions in the original
rec*bind need to access the machine words in which the
bindings’ values are stored; so, at run–time, first we need to allocate
the loc gensyms and then we can evaluate the initialisation expressions
and store the resulting value in the gensym itself.
In this special case, since the binding is unassigned in the original
code, the assign struct is introduced by the compiler and it
is the only assignment for the binding. The compiler recognises this
case and transforms:
(assign ?prel ?init)
into:
(funcall (primref $init-symbol-value!)
(constant ?loc)
?init)
in which ?loc is the loc gensym of the binding.
clambda form: they end up being defined by
a fix struct; the letrec optimiser takes care of
recognising and handling such case. As example:
(library-letrec*
((a.lex a.loc (lambda () '1))
(b.lex a.loc (lambda () '2)))
((primitive display) (a.lex)))
is transformed into:
(fix ((a.lex_0 (lambda () (constant 1)))
(b.lex_0 (lambda () (constant 2))))
(funcall (primref display) (constant 1)))
in which the call to a.lex is integrated by the source optimiser.
Next: compiler topics locbind, Up: compiler topics [Index]