fix bytecode compiler bug

Certain `lambda'-lifting operations can cause information
about the flonumness of a variable to get lost, leading
to a mismatch between the closure's flags and flags on
a variable reference. (The bytecode validator could detect the
bug when loading the broken bytecode. The broken information,
meanwhile, was only used by the JIT.)
This commit is contained in:
Matthew Flatt 2012-01-30 10:05:42 -07:00
parent 3bed8aee43
commit 706d5026ac
2 changed files with 36 additions and 7 deletions

View File

@ -1892,6 +1892,25 @@
(case-lambda ((v) (set! f3 v))))])
(f3))))))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Make sure that certain lifting operations
;; do not lose track of flonum-ness of a variable:
(let ([e '(let ([f (random)])
(define (s t)
(cons
(lambda () (s (fl+ t 1.0)))
(lambda () f)))
(s 0.0))]
[ns (make-base-namespace)]
[o (open-output-bytes)])
(parameterize ([current-namespace ns])
(namespace-require 'racket/flonum)
(write (compile e) o))
;; bytecode validation can catch the relevant mistake:
(parameterize ([read-accept-compiled #t])
(read (open-input-bytes (get-output-bytes o)))))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(report-errs)

View File

@ -1665,9 +1665,9 @@ XFORM_NONGCING static void boxmap_set(mzshort *boxmap, int j, int bit, int delta
boxmap[delta + ((2 * j) / BITS_PER_MZSHORT)] |= ((mzshort)bit << ((2 * j) & (BITS_PER_MZSHORT - 1)));
}
XFORM_NONGCING static int boxmap_get(mzshort *boxmap, int j, int bit)
XFORM_NONGCING static int boxmap_get(mzshort *boxmap, int j, int bit, int delta)
{
if (boxmap[(2 * j) / BITS_PER_MZSHORT] & ((mzshort)bit << ((2 * j) & (BITS_PER_MZSHORT - 1))))
if (boxmap[delta + ((2 * j) / BITS_PER_MZSHORT)] & ((mzshort)bit << ((2 * j) & (BITS_PER_MZSHORT - 1))))
return 1;
else
return 0;
@ -1826,9 +1826,14 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info,
int cp;
cp = i;
if (convert_boxes) {
if (boxmap_get(convert_boxes, i, 1))
if (boxmap_get(convert_boxes, i, 1, 0))
cp = -((2 * cp) + 1);
else if (boxmap_get(convert_boxes, i, 2))
else if (boxmap_get(convert_boxes, i, 2, 0))
cp = -((2 * cp) + 2);
} else if (expanded_already) {
if (boxmap_get(closure_map, data->num_params + i, 1, data->closure_size))
cp = -((2 * cp) + 1);
else if (boxmap_get(closure_map, data->num_params + i, 2, data->closure_size))
cp = -((2 * cp) + 2);
}
scheme_hash_set(captured, scheme_make_integer(closure_map[i]), scheme_make_integer(cp));
@ -1872,12 +1877,15 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info,
if (captured && (captured->count > offset)) {
/* We need to extend the closure map. All the info
is in captured, so just build it from scratch. */
int old_pos, j, new_size;
int old_pos, j, new_size, need_flags;
new_size = (captured->count + (has_tl ? 1 : 0));
if (cl->flonum_map)
if (cl->flonum_map || expanded_already || convert_boxes) {
need_flags = new_size;
new_size += boxmap_size(data->num_params + new_size);
} else
need_flags = 0;
closure_map = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * new_size);
if (cl->flonum_map)
if (need_flags)
memset(closure_map, 0, sizeof(mzshort) * new_size);
offset = captured->count;
convert_boxes = NULL;
@ -1900,6 +1908,8 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info,
if (!convert_boxes)
convert_boxes = allocate_boxmap(offset);
boxmap_set(convert_boxes, cp, bit, 0);
if (need_flags)
boxmap_set(closure_map, cp, bit, need_flags);
}
closure_map[cp] = old_pos;
}