-----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