From eed18fac93cf68b541939546488008f848fcfd61 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Tue, 21 Aug 2018 06:36:18 -0600 Subject: [PATCH] schemify: improve use-before-definition analysis This improvement removes only a few places where a variable use is considered possibly too early in the RacketCS implementation, but the improvement is significant for uses of `input-port?` in "io". --- racket/src/schemify/mutated-state.rkt | 10 ++++++++- racket/src/schemify/mutated.rkt | 32 ++++++++++++++++++++++++++- racket/src/schemify/schemify.rkt | 7 +++--- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/racket/src/schemify/mutated-state.rkt b/racket/src/schemify/mutated-state.rkt index b5ab47c0dd..580ddb2043 100644 --- a/racket/src/schemify/mutated-state.rkt +++ b/racket/src/schemify/mutated-state.rkt @@ -8,6 +8,9 @@ ;; * 'too-early - the identifier may be referenced before it is ;; defined ;; +;; * 'too-early/ready - a variant of 'too-early where the variable +;; is now definitely ready +;; ;; * 'not-ready - the identifier's value is not yet ready, so a ;; reference transitions to 'too-early ;; @@ -28,6 +31,7 @@ (provide delayed-mutated-state? simple-mutated-state? not-ready-mutated-state? + too-early-mutated-state? via-variable-mutated-state? set!ed-mutated-state?) @@ -35,11 +39,15 @@ (define (simple-mutated-state? v) (or (not v) - (delayed-mutated-state? v))) + (delayed-mutated-state? v) + (eq? v 'too-early/ready))) (define (not-ready-mutated-state? v) (eq? v 'not-ready)) +(define (too-early-mutated-state? v) + (eq? v 'too-early)) + ;; When referecing an exported identifier, we need to consistently go ;; through a `variable` record when it can be `set!`ed. We don't need ;; to go through a `variable` record if the identifier might simply be diff --git a/racket/src/schemify/mutated.rkt b/racket/src/schemify/mutated.rkt index 6895161a4a..769e26909a 100644 --- a/racket/src/schemify/mutated.rkt +++ b/racket/src/schemify/mutated.rkt @@ -8,9 +8,11 @@ "struct-type-info.rkt" "mutated-state.rkt" "find-known.rkt" + "infer-known.rkt" "letrec.rkt") -(provide mutated-in-body) +(provide mutated-in-body + update-mutated-state!) ;; See "mutated-state.rkt" for information on the content of the ;; `mutated` table. @@ -190,3 +192,31 @@ [else (hash-remove! mutated v) (state)])])))]))) + +(define (update-mutated-state! l mut-l mutated) + (cond + [(wrap-null? mut-l) '()] + [(eq? l mut-l) + ;; Check for function definitions at the start of `l`, because we + ;; can mark all 'too-early variable uses as being ready from now + ;; on + (define new-mut-l + (let loop ([mut-l mut-l]) + (cond + [(wrap-null? mut-l) '()] + [else + (match (wrap-car mut-l) + [`(define-values (,ids ...) ,rhs) + (cond + [(lambda? rhs #:simple? #t) + (for ([id (in-list ids)]) + (define u-id (unwrap id)) + (when (too-early-mutated-state? (hash-ref mutated u-id #f)) + (hash-set! mutated u-id 'too-early/ready))) + (loop (wrap-cdr mut-l))] + [else mut-l])] + [`,_ mut-l])]))) + (if (eq? mut-l l) + (wrap-cdr mut-l) + l)] + [else mut-l])) diff --git a/racket/src/schemify/schemify.rkt b/racket/src/schemify/schemify.rkt index d8c03bd594..557af4d1b8 100644 --- a/racket/src/schemify/schemify.rkt +++ b/racket/src/schemify/schemify.rkt @@ -186,7 +186,8 @@ ;; corresponding exported `variable` records, but delay those ;; installs to the end, if possible (define schemified - (let loop ([l l] [accum-exprs null] [accum-ids null]) + (let loop ([l l] [in-mut-l l] [accum-exprs null] [accum-ids null]) + (define mut-l (update-mutated-state! l in-mut-l mutated)) (cond [(null? l) (define set-vars @@ -218,7 +219,7 @@ schemified (let id-loop ([ids ids] [accum-exprs null] [accum-ids accum-ids]) (cond - [(wrap-null? ids) (loop (wrap-cdr l) accum-exprs accum-ids)] + [(wrap-null? ids) (loop (wrap-cdr l) mut-l accum-exprs accum-ids)] [(or (or for-jitify? for-cify?) (via-variable-mutated-state? (hash-ref mutated (unwrap (wrap-car ids)) #f))) (define id (unwrap (wrap-car ids))) @@ -233,7 +234,7 @@ [else (id-loop (wrap-cdr ids) accum-exprs (cons (unwrap (wrap-car ids)) accum-ids))]))))] [`,_ - (loop (wrap-cdr l) (cons schemified accum-exprs) accum-ids)])]))) + (loop (wrap-cdr l) mut-l (cons schemified accum-exprs) accum-ids)])]))) ;; Return both schemified and known-binding information, where ;; the later is used for cross-linklet optimization (values schemified knowns mutated))