expander: avoid unneeded namespace reference

This change avoids the stair-step effect that is depicted in the
"current Racket -M" build plot from the January 2019 blog post about
Racket on Chez Scheme.

The stair step in that plot is a result of a combination of effects,
but one key part is that the `.set-transformer!` linklet import (to
support macro definitions) has a reference back to the namespace.
While `.set-transformer!` normally would not be captured in any
closure, `db/private/generic/prepared` creates a thread that causes
the "prefix" part of a closure to be moved to a thread's runstack
before it can be pruned by the GC. The stair-step problem happens only
when running directly from machine-independent form, because that form
is recompiled in a way that doesn't optimize away the unused
`.set-transformer!` import. The change in this commit avoids a
reference to the namespace in some cases where it will not be useful,
which turns out to be sufficient to address the build problem.

A more complete repair would be to change the compiler to pair a
closure prefix on the runstack with a liveness mask. An even more
complete repair is to switch to Racket CS. Racket CS is immune to the
problem, even when running from machine-independent bytecode, because
its closures do not keep extra references (with the tradeoff that
there's less sharing).
This commit is contained in:
Matthew Flatt 2019-03-14 06:22:19 -06:00
parent 077a11c84f
commit e7744efb7d
2 changed files with 34 additions and 3 deletions

View File

@ -190,8 +190,16 @@
(define module-body-instance-instance
(make-module-body-instance-instance
#:set-transformer! (lambda (name val)
(namespace-set-transformer! ns (sub1 phase-level) name val))))
#:set-transformer! (cond
[(zero-phase? phase-level)
(lambda (name val)
(error 'define-syntax "should not happen at phase level 0"))]
[(zero-phase? (phase+ phase-shift phase-level))
;; No use for phase -1 bindings
(lambda (name val) (void))]
[else
(lambda (name val)
(namespace-set-transformer! ns (sub1 phase-level) name val))])))
(define (instantiate-body)
(instantiate-linklet phase-linklet

View File

@ -37864,14 +37864,37 @@ static const char *startup_source =
"(values))))"
"(let-values(((module-body-instance-instance_0)"
"(let-values(((temp52_0)"
"(if(zero-phase?"
" phase-level_0)"
"(let-values()"
"(lambda(name_0"
" val_0)"
"(begin"
" 'temp52"
"(error"
" 'define-syntax"
" \"should not happen at phase level 0\"))))"
"(if(zero-phase?"
"(phase+"
" phase-shift_0"
" phase-level_0))"
"(let-values()"
"(lambda(name_0"
" val_0)"
"(begin"
" 'temp52"
"(void))))"
"(let-values()"
"(lambda(name_0"
" val_0)"
"(begin"
" 'temp52"
"(namespace-set-transformer!"
" ns_2"
"(sub1"
" phase-level_0)"
" name_0"
" val_0))))"
" val_0))))))))"
"(make-module-body-instance-instance18.1"
" temp52_0))))"
"(let-values(((instantiate-body_0)"