To describe it, here is the small piece of code which causes the problem.
(import (rnrs)) (define label-counter (lambda () 0)) (define (new-lbl!) (label-counter)) (define (change-label-counter) (set! label-counter (lambda () 1))) (define (print . args) (for-each display args) (newline)) (let ((lbl (new-lbl!))) (print lbl)) (change-label-counter) (let ((lbl (new-lbl!))) (print lbl))This should print 0 then 1. Well, it doesn't seem there is a problem except the
change-label-counter
. The defined label-counter
is obviously constant so it'd be inlined in the new-lbl!
. Now, the change-label-counter
sets the new value to label-counter
, here comes the problem. The new-lbl!
has already compiled with inlined value and just returns 0 so change-label-counter
doesn't have any effect to it. Then the result value would be always 0.If these procedures are defined in a library, then Sagittarius compiler could check if the global defined variable would be changed or not however because this is defined in a script it can't and just tries to inline so that the target procedure looks constant.
What I can do is;
- Don't inline them if it's in script.
- Forbit
set!
for globally defined variable. - Make impossible to run some of R5RS code (e.g. Gambit benchmark's compiler)
- Read all expression and wrap with a library before compiling a script
- I can already see the horrible future...
3 comments:
Well it's an inevitable consequence of "open binding" model, where the bindings can be altered after you examine the current expression. Some Scheme have define-inline or define-constant exactly because of this; you need programmer's help to determine which bindings will be altered. Take it, or give up Scheme as it is; there are languages that are more strict about side effects...
btw, one option is that you compile aggressively, keeping which bindings you assume to be constant, and whenever that assumption is voided by side effects, you recompile the expression (or fall back to the less-aggressive optimized version). It may be a win if most global bindings in a script is constant and mutation is rare.
Yes, for some reason I totally forgot about this. IMO, compiler should be able to determine whether or not it can inline procedures.
I'm thinking that R6/7RS don't allow user to re-define/re-assign imported variable so if a binding is bound in other library then it can be folded. Sort of less conservative way though.
Post a Comment