[gambit-list] Gambit's Linking Model
Marc Feeley
feeley at iro.umontreal.ca
Thu Jun 14 07:34:25 EDT 2007
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 13-Jun-07, at 11:02 PM, Guillaume Cartier wrote:
>>
>> Yes... if no declarations are used. If your code uses the
>> declaration
>> (declare (block)) then inter-procedural optimizations are possible
>> (such as inlining) within that file. Of course if you want to be
>> able
>> to redefine functions (as seems to be the case for Jazz) then you
>> cannot use this declaration.
> In fact it's the opposite. A method in Jazz cannot be redefined, so I
> was planning on generating for methods something like
> (begin
> (declare (block))
> (define (method-x) ...))
Let me explain what happens if you do this, so that you don't
misunderstand the consequences.
In Gambit each global variable is implemented with two cells: the
"value" cell and the "primitive" cell. The value cell is what is
accessed when you mutate a global variable and reference it with no
special declarations in effect. Both the value cell and the
primitive cell are initialized when a toplevel procedure definition
is evaluated *and* the (block) declaration is in effect. All of the
predefined procedures (cons, append, make-thread, ...) are defined in
the runtime library while the (block) declaration is in effect. The
Gambit compiler uses this fact when compiling Scheme code while the
(standard-bindings) and/or (extended-bindings) declarations are in
effect. In this case a call to a predefined procedure will reference
the primitive cell. This is faster because the compiler knows this
is a procedure, and can avoid the procedure? check. Note that a call
like (append X Y) in the context of a (standard-bindings) declaration
will call the append procedure in the runtime library even if the
user has mutated the append variable with a set! .
The (block) declaration also allows the compiler to perform
optimizations within the file because the value attached to a
variable is known not to change (unless there is a set! within the
file). This allows copy propagation, function inlining, etc at the
file level. So a file containing this code:
(declare (block))
(define n 10)
(define (f x) (* x x))
(define (g) (f (+ n 1)))
will be compiled as though it was:
(define n 10)
(define (f x) (* x x))
(define (g) (let ((x (+ 10 1))) (* x x)))
So you have to be aware that the (block) declaration causes linking
optimizations at the file level. So it is OK to use the (block)
declaration if the granularity of "redefinition" is the file, but it
is not OK if you want to have the ability to redefine individual
procedures. After loading the above (compiled) file, a (define (f x)
(* x 2)) at the REPL or in another file that you load will not affect
the behavior of a call to g. The only way to "update" g is to
redefine it.
Note also that if another file does a (define h g), and then you
reload the above file with new definitions for f and g, you will
access the original definition of g when you call h. In other words,
reloading a file compiled with the (block) declaration changes the
content of the value and primitive cells, it does not "overwrite",
purge or invalidate the previous machine code.
Marc
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (Darwin)
iD8DBQFGcSfB//V9Zc2T/v4RAjVAAJ9NxpvoYePHJFWmjE2groAga0rMxACeIUWX
5HPLZpxAJlCXTpU9leMgqdk=
=u2gJ
-----END PGP SIGNATURE-----
More information about the Gambit-list
mailing list