@@ -2905,19 +2905,6 @@ f(x) = yt(x)
29052905 (or (assq s (car (lam: vinfo lam)))
29062906 (assq s (cadr (lam: vinfo lam)))))
29072907
2908- (define (table.merge! l r)
2909- (table.foreach (lambda (k v) (put! l k v))
2910- r))
2911-
2912- (define (table.delete-if! p t)
2913- (let ((to-del '()))
2914- (table.foreach (lambda (v _)
2915- (if (p v)
2916- (set! to-del (cons v to-del))))
2917- t)
2918- (for-each (lambda (v) (del! t v))
2919- to-del)))
2920-
29212908;; Try to identify never-undef variables, and then clear the `captured` flag for single-assigned,
29222909;; never-undef variables to avoid allocating unnecessary `Box`es.
29232910(define (lambda-optimize-vars! lam)
@@ -2931,81 +2918,90 @@ f(x) = yt(x)
29312918 (let ((am (all-methods-for ex stmts)))
29322919 (put! allmethods-table mn am)
29332920 am))))
2934- (define (expr-uses-var ex v body)
2935- (cond ((atom? ex) (expr-contains-eq v ex))
2936- ((assignment? ex) (expr-contains-eq v (caddr ex)))
2937- ((eq? (car ex) 'method)
2938- (and (length> ex 2)
2939- ;; a method expression captures a variable if any methods for the
2940- ;; same function do.
2941- (let* ((mn (method-expr-name ex))
2942- (all-methods (if (local-in? mn lam)
2943- (get-methods ex body)
2944- (list ex))))
2945- (any (lambda (ex)
2946- (assq v (cadr (lam: vinfo (cadddr ex)))))
2947- all-methods))))
2948- (else (expr-contains-eq v ex))))
29492921 ;; This does a basic-block-local dominance analysis to find variables that
29502922 ;; are never used undef.
29512923 (let ((vi (car (lam: vinfo lam)))
29522924 (unused (table)) ;; variables not (yet) used (read from) in the current block
29532925 (live (table)) ;; variables that have been set in the current block
2954- (seen (table)) ;; all variables we've seen assignments to
2955- (b1vars '()) ;; vars set in first basic block
2956- (first #t)) ;; are we in the first basic block?
2926+ (seen (table))) ;; all variables we've seen assignments to
29572927 ;; Collect candidate variables: those that are captured (and hence we want to optimize)
29582928 ;; and only assigned once. This populates the initial `unused` table.
29592929 (for-each (lambda (v)
29602930 (if (and (vinfo: capt v) (vinfo: sa v))
29612931 (put! unused (car v) #t)))
29622932 vi)
2933+ (define (restore old)
2934+ (table.foreach (lambda (k v)
2935+ (if (not (has? old k))
2936+ (put! unused k v)))
2937+ live)
2938+ (set! live old))
29632939 (define (kill)
29642940 ;; when we see control flow, empty live set back into unused set
2965- (if first
2966- (begin (set! first #f)
2967- (set! b1vars (table.keys live))))
2968- (table.merge! unused live)
2969- (set! live (table)))
2970- (define (mark-used e)
2971- ;; remove variables used by `e` from the unused table
2972- (table.delete-if! (lambda (v) (expr-uses-var e v (lam: body lam)))
2973- unused))
2941+ (restore (table)))
2942+ (define (mark-used var)
2943+ ;; remove variable from the unused table
2944+ (if (has? unused var)
2945+ (del! unused var)))
2946+ (define (assign! var)
2947+ (if (has? unused var)
2948+ ;; When a variable is assigned, move it to the live set to protect
2949+ ;; it from being removed from `unused`.
2950+ (begin (put! live var #t)
2951+ (put! seen var #t)
2952+ (del! unused var))))
29742953 (define (visit e)
2975- (cond ((atom? e) (if (symbol? e) (mark-used e)))
2954+ ;; returns whether e contained a symboliclabel
2955+ (cond ((atom? e) (if (symbol? e) (mark-used e))
2956+ #f)
29762957 ((lambda-opt-ignored-exprs (car e))
2977- #t )
2958+ #f )
29782959 ((eq? (car e) 'scope-block)
29792960 (visit (cadr e)))
2980- ((eq? (car e) 'block)
2981- (for-each visit (cdr e)))
2961+ ((memq (car e) '( block call new _do_while) )
2962+ (eager-any visit (cdr e)))
29822963 ((eq? (car e) 'break-block)
29832964 (visit (caddr e)))
29842965 ((eq? (car e) 'return)
2985- (visit (cadr e))
2986- (kill))
2987- ((memq (car e) '(break label symboliclabel symbolicgoto))
2988- (kill))
2989- ((memq (car e) '(if elseif _while _do_while trycatch tryfinally))
2990- (for-each (lambda (e)
2991- (visit e)
2992- (kill))
2993- (cdr e)))
2966+ (begin0 (visit (cadr e))
2967+ (kill)))
2968+ ((memq (car e) '(break label symbolicgoto))
2969+ (kill)
2970+ #f)
2971+ ((eq? (car e) 'symboliclabel)
2972+ (kill)
2973+ #t)
2974+ ((memq (car e) '(if elseif _while trycatch tryfinally))
2975+ (let ((prev (table.clone live)))
2976+ (if (eager-any (lambda (e) (begin0 (visit e)
2977+ (kill)))
2978+ (cdr e))
2979+ ;; if there is a label inside, we could have skipped a prior
2980+ ;; variable initialization
2981+ (begin (kill) #t)
2982+ (begin (restore prev) #f))))
2983+ ((eq? (car e) '=)
2984+ (begin0 (visit (caddr e))
2985+ (assign! (cadr e))))
2986+ ((eq? (car e) 'method)
2987+ (if (length> e 2)
2988+ (let* ((mn (method-expr-name e))
2989+ ;; a method expression captures a variable if any methods for
2990+ ;; the same function do.
2991+ (all-methods (if (local-in? mn lam)
2992+ (get-methods e (lam: body lam))
2993+ (list e))))
2994+ (for-each (lambda (ex)
2995+ (for-each mark-used
2996+ (map car (cadr (lam: vinfo (cadddr ex))))))
2997+ all-methods)
2998+ (assign! (cadr e))))
2999+ #f)
29943000 (else
2995- (if (eq? (car e) '=)
2996- (visit (caddr e))
2997- (mark-used e))
2998- (if (and (or (eq? (car e) '=)
2999- (and (eq? (car e) 'method) (length> e 2)))
3000- (has? unused (cadr e)))
3001- ;; When a variable is assigned, move it to the live set to protect
3002- ;; it from being removed from `unused`.
3003- (begin (put! live (cadr e) #t)
3004- (put! seen (cadr e) #t)
3005- (del! unused (cadr e)))
3006- ;; in all other cases there's nothing to do except assert that
3007- ;; all expression heads have been handled.
3008- #;(assert (memq (car e) '(= method new call foreigncall cfunction |::|)))))))
3001+ (eager-any visit (cdr e))
3002+ ;; in all other cases there's nothing to do except assert that
3003+ ;; all expression heads have been handled.
3004+ #;(assert (memq (car e) '(foreigncall cfunction |::|))))))
30093005 (visit (lam: body lam))
30103006 ;; Finally, variables can be marked never-undef if they were set in the first block,
30113007 ;; or are currently live, or are back in the unused set (because we've left the only
@@ -3014,7 +3010,7 @@ f(x) = yt(x)
30143010 (if (has? seen v)
30153011 (let ((vv (assq v vi)))
30163012 (vinfo: set-never-undef! vv #t))))
3017- (append b1vars (table.keys live) (table.keys unused)))
3013+ (append (table.keys live) (table.keys unused)))
30183014 (for-each (lambda (v)
30193015 (if (and (vinfo: sa v) (vinfo: never-undef v))
30203016 (set-car! (cddr v) (logand (caddr v) (lognot 5)))))
0 commit comments