diff --git a/pkgs/racket-test-core/tests/racket/will.rktl b/pkgs/racket-test-core/tests/racket/will.rktl index a10573e4cc..d43dd1c4fb 100644 --- a/pkgs/racket-test-core/tests/racket/will.rktl +++ b/pkgs/racket-test-core/tests/racket/will.rktl @@ -293,6 +293,25 @@ (if (car p) (add1 n) n)))) (test #t < fraction-retained 1/2))) +;; ---------------------------------------- +;; Check space safety conversion for nested `if`s + +(let ([ht (make-weak-hasheq)]) + (letrec ([f (lambda (false long-vector values n) + (begin + (if false + (if (random) 7 (length long-vector)) + 'long-vector-not-cleared-here) + (if (zero? n) + (begin + (collect-garbage) + (hash-count ht)) + (let ([vec (make-vector 1000)]) + (hash-set! ht vec #t) + (values (f false vec values (sub1 n)))))))]) + (set! f f) + (test #t < (f #f #f values 100) 33))) + ;; ---------------------------------------- (report-errs) diff --git a/racket/src/racket/src/sfs.c b/racket/src/racket/src/sfs.c index 8196415d0b..e2f93aeb71 100644 --- a/racket/src/racket/src/sfs.c +++ b/racket/src/racket/src/sfs.c @@ -424,13 +424,14 @@ static Scheme_Object *sfs_one_branch(SFS_Info *info, int ip, SFS_LOG(printf(" |%d %d %d\n", i + t_min_t, n, info->max_nontail)); info->max_used[i + t_min_t] = n; info->max_calls[i + t_min_t] = info->max_nontail; - } + } else + SCHEME_VEC_ELS(t_vec)[i] = scheme_false; } } } /* If the other branch has last use for something not used in this branch, and if there's a non-tail call in this branch - of later, then we'll have to start with explicit clears. + or later, then we'll have to start with explicit clears. Note that it doesn't matter whether the other branch actually clears them (i.e., the relevant non-tail call might be only in this branch). */ @@ -456,7 +457,7 @@ static Scheme_Object *sfs_one_branch(SFS_Info *info, int ip, n = SCHEME_INT_VAL(o); pos = i + t_min_t; at_ip = info->max_used[pos]; - SFS_LOG(printf(" ?%d %d %d\n", pos, n, at_ip)); + SFS_LOG(printf(" ?%d[%d] %d %d\n", pos, i, n, at_ip)); /* is last use in other branch? */ if (((!delta && (at_ip == ip)) || (delta && (at_ip == n)))) { @@ -526,6 +527,25 @@ static Scheme_Object *sfs_one_branch(SFS_Info *info, int ip, return tbranch; } +static void sfs_restore_one_branch(SFS_Info *info, int ip, + Scheme_Object *vec, int delta) +{ + int t_min_t, t_cnt, i; + Scheme_Object *t_vec; + + t_vec = SCHEME_VEC_ELS(vec)[(delta * SFS_BRANCH_W) + 1]; + + if (SCHEME_FALSEP(t_vec)) return; + + t_min_t = SCHEME_INT_VAL(SCHEME_VEC_ELS(vec)[delta * SFS_BRANCH_W]); + t_cnt = SCHEME_VEC_SIZE(t_vec); + + for (i = 0; i < t_cnt; i++) { + if (SCHEME_TRUEP(SCHEME_VEC_ELS(t_vec)[i])) + info->max_used[i + t_min_t] = ip; + } +} + static Scheme_Object *sfs_branch(Scheme_Object *o, SFS_Info *info) { Scheme_Branch_Rec *b; @@ -579,6 +599,14 @@ static Scheme_Object *sfs_branch(Scheme_Object *o, SFS_Info *info) info->max_nontail = ip + 1; } + if (info->pass) { + /* Restore "outside" view for both branches, so that + the numbers after `if` for the second pass match + the numbers after the first pass: */ + sfs_restore_one_branch(info, ip, vec, 0); + sfs_restore_one_branch(info, ip, vec, 1); + } + SFS_LOG(printf(" done if: %d %d\n", min_t, max_t)); info->min_touch = min_t;