fix space-safety annotation for nested ifs

Closes PR 15176
This commit is contained in:
Matthew Flatt 2015-11-07 18:39:38 -07:00
parent db464d5ed2
commit 2ed6c01e56
2 changed files with 50 additions and 3 deletions

View File

@ -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)

View File

@ -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;