Merge branch 'livefix' of github.com:mflatt/ChezScheme

original commit: 7292d4a04806da0f7f07de9404aeedaf00158a4e
This commit is contained in:
Matthew Flatt 2017-12-21 05:35:55 -07:00
commit 8af0a5de94
17 changed files with 582 additions and 364 deletions

12
LOG
View File

@ -781,3 +781,15 @@
cmacros.ss, compile.ss, cpnanopass.ss, inspect.ss,
primdata.ss, prims.ss, misc.ms,
system.stex, release_notes.tex
- added support for Visual Studio 2017.15.5
wininstall/locate-vcredist.bat
- fixed substring-fill! and vector-fill! to return void, reflecting the
documented return value of unspecified value. Also changes substring-fill!
to use define-who instead of repeating 'substring-fill! in all the error
messages.
5_4.ss, 5_6.ss
- keep call-live in tree form, which allows more efficient computation
of live-pointer masks when many live variables span many calls
cpnanopass.ss, inspect.ss, np-languages.ss, primdata.ss,
tree.ss (added), types.ss,
x86_64.ss, cmacros.ss, gc.c, s/Mf-base

58
c/gc.c
View File

@ -45,6 +45,7 @@ static void sweep_port PROTO((ptr p));
static void sweep_thread PROTO((ptr p));
static void sweep_continuation PROTO((ptr p));
static void sweep_stack PROTO((uptr base, uptr size, uptr ret));
static void sweep_live_tree PROTO((uptr range, ptr tree, ptr *pp));
static void sweep_record PROTO((ptr x));
static int scan_record_for_self PROTO((ptr x));
static IGEN sweep_dirty_record PROTO((ptr x));
@ -1831,7 +1832,7 @@ static void sweep_continuation(p) ptr p; {
/* assumes stack has already been copied to newspace */
static void sweep_stack(base, fp, ret) uptr base, fp, ret; {
ptr *pp; iptr oldret;
ptr num;
ptr livemask;
while (fp != base) {
if (fp < base)
@ -1843,33 +1844,74 @@ static void sweep_stack(base, fp, ret) uptr base, fp, ret; {
ret = (iptr)(*pp);
relocate_return_addr(pp)
num = ENTRYLIVEMASK(oldret);
if (Sfixnump(num)) {
uptr mask = UNFIX(num);
livemask = ENTRYLIVEMASK(oldret);
if (Sfixnump(livemask)) {
uptr mask = UNFIX(livemask);
while (mask != 0) {
pp += 1;
if (mask & 0x0001) relocate(pp)
mask >>= 1;
}
} else {
} else if (Spairp(livemask)) {
/* A tree: (range . tree). The tree must be shallow enough that
recursion in `sweep_tree_live` is ok. */
relocate(&ENTRYLIVEMASK(oldret))
livemask = ENTRYLIVEMASK(oldret);
relocate(&INITCDR(livemask))
sweep_live_tree(UNFIX(Scar(livemask)), Scdr(livemask), pp);
} else if (Sbignump(livemask)) {
/* As of the addition of the above tree form, we
don't expect bignums to be used as a mask anymore,
but allow them for now. */
iptr index;
relocate(&ENTRYLIVEMASK(oldret))
num = ENTRYLIVEMASK(oldret);
index = BIGLEN(num);
livemask = ENTRYLIVEMASK(oldret);
index = BIGLEN(livemask);
while (index-- != 0) {
INT bits = bigit_bits;
bigit mask = BIGIT(num,index);
bigit mask = BIGIT(livemask,index);
while (bits-- > 0) {
pp += 1;
if (mask & 1) relocate(pp)
mask >>= 1;
}
}
} else {
S_error_abort("sweep_stack(gc): unreocgnized mask format");
}
}
}
static void sweep_live_tree(range, tree, pp) uptr range; ptr tree, *pp; {
/* A tree is either a fixnum or a pair of two trees, with
half of the range on the left and the rest on the right */
if (Sfixnump(tree)) {
uptr mask = UNFIX(tree);
while (mask != 0) {
pp += 1;
if (mask & 0x0001) relocate(pp)
mask >>= 1;
}
} else if (tree == Strue) {
while (range-- > 0) {
pp += 1;
relocate(pp)
}
} else {
uptr split = range >> 1;
relocate(&INITCAR(tree))
relocate(&INITCDR(tree))
sweep_live_tree(split, Scar(tree), pp);
sweep_live_tree(range - split, Scdr(tree), pp + split);
}
}
#define sweep_or_check_record(x, sweep_or_check) \
ptr *pp; ptr num; ptr rtd; \
\

View File

@ -120,19 +120,19 @@
($string-set-immutable! v2)
v2)])))
(define substring-fill!
(define-who substring-fill!
(lambda (s m n c)
(unless (mutable-string? s)
($oops 'substring-fill! "~s is not a mutable string" s))
($oops who "~s is not a mutable string" s))
(unless (char? c)
($oops 'substring-fill! "~s is not a character" c))
($oops who "~s is not a character" c))
(let ([k (string-length s)])
(unless (and (fixnum? m) (fixnum? n) (fx<= 0 m n k))
($oops 'substring-fill!
($oops who
"~s and ~s are not valid start/end indices for ~s"
m n s))
(do ([i m (fx+ i 1)])
((fx= i n) s)
((fx= i n))
(string-set! s i c)))))
(set! string-for-each

View File

@ -85,7 +85,7 @@
(unless (mutable-vector? v) ($oops who "~s is not a mutable vector" v))
(let ([n (vector-length v)])
(do ([i 0 (fx+ i 1)])
((fx= i n) v)
((fx= i n))
(vector-set! v i obj)))))
(set! fxvector->list

View File

@ -146,7 +146,7 @@ macroobj =\
allsrc =\
${basesrc} ${compilersrc} cmacros.ss ${archincludes} setup.ss debug.ss priminfo.ss primdata.ss layout.ss\
base-lang.ss expand-lang.ss primref.ss types.ss io-types.ss fasl-helpers.ss hashtable-types.ss\
np-languages.ss
np-languages.ss tree.ss
# doit uses a different Scheme process to compile each target
doit: ${PetiteBoot} ${SchemeBoot} ${Cheader} ${Cequates}
@ -476,7 +476,7 @@ ${asm} ${obj} mkheader.so: ${macroobj} nanopass.so base-lang.ss expand-lang.ss p
primvars.so setup.so mkheader.so env.so: cmacros.so priminfo.so primref.ss
setup.so: debug.ss
${patchobj}: ${macroobj} nanopass.so base-lang.ss expand-lang.ss primref.ss types.ss io-types.ss fasl-helpers.ss hashtable-types.ss env.ss
${patchobj}: ${macroobj} nanopass.so base-lang.ss expand-lang.ss primref.ss types.ss tree.ss io-types.ss fasl-helpers.ss hashtable-types.ss env.ss
cpnanopass.$m cpnanopass.patch: nanopass.so np-languages.ss ${archincludes}
5_4.$m: ../unicode/unicode-char-cases.ss ../unicode/unicode-charinfo.ss

View File

@ -2287,7 +2287,7 @@
(if (target-fixnum? lpm)
`(long . ,(fix lpm))
`(abs 0 (object ,lpm)))
(aop-cons* `(asm livemask: ,(format "~b" lpm))
(aop-cons* `(asm livemask: ,(if (number? lpm) (format "~b" lpm) (format "~s" lpm)))
'(code-top-link)
(aop-cons* `(asm code-top-link)
`(long . ,fs)

View File

@ -1469,7 +1469,7 @@
[ptr link]))
(define-primitive-structure-disps rp-header typemod
([ptr livemask]
([ptr livemask] ; a fixnum or (cons size tree)
[uptr toplink]
[iptr frame-size]
[uptr mv-return-address]))

View File

@ -250,236 +250,8 @@
(bytevector-u16-native-ref bv n))
count))))))))
(module (empty-tree full-tree tree-extract tree-for-each tree-fold-left tree-bit-set? tree-bit-set tree-bit-unset tree-bit-count tree-same? tree-merge)
; tree -> fixnum | (tree-node tree tree)
; 0 represents any tree or subtree with no bits set, and a tree or subtree
; with no bits set is always 0
(define empty-tree 0)
; any tree or subtree with all bits set
(define full-tree #t)
(define (full-fixnum size) (fxsrl (most-positive-fixnum) (fx- (fx- (fixnum-width) 1) size)))
(define compute-split
(lambda (size)
(fxsrl size 1)
; 2015/03/15 rkd: tried the following under the theory that we'd allocate
; fewer nodes. for example, say fixmun-width is 30 and size is 80. if we
; split 40/40 we create two nodes under the current node. if instead we
; split 29/51 we create just one node and one fixnum under the current
; node. this worked as planned; however, it reduced the number of nodes
; created by only 3.3% on the x86 and made compile times slightly worse.
#;(if (fx<= size (fx* (fx- (fixnum-width) 1) 3)) (fx- (fixnum-width) 1) (fxsrl size 1))))
(meta-cond
[(fx= (optimize-level) 3)
(module (make-tree-node tree-node? tree-node-left tree-node-right)
(define make-tree-node cons)
(define tree-node? pair?)
(define tree-node-left car)
(define tree-node-right cdr))]
[else
(module (make-tree-node tree-node? tree-node-left tree-node-right)
(define-record-type tree-node
(nongenerative)
(sealed #t)
(fields left right)
(protocol
(lambda (new)
(lambda (left right)
(new left right)))))
(record-writer (record-type-descriptor tree-node)
(lambda (r p wr)
(define tree-node->s-exp
(lambda (tn)
(with-virgin-quasiquote
(let ([left (tree-node-left tn)] [right (tree-node-right tn)])
`(tree-node
,(if (tree-node? left) (tree-node->s-exp left) left)
,(if (tree-node? right) (tree-node->s-exp right) right))))))
(wr (tree-node->s-exp r) p))))])
(define tree-extract ; assumes empty-tree is 0
(lambda (st size v)
(let extract ([st st] [size size] [offset 0] [x* '()])
(cond
[(fixnum? st)
(do ([st st (fxsrl st 1)]
[offset offset (fx+ offset 1)]
[x* x* (if (fxodd? st) (cons (vector-ref v offset) x*) x*)])
((fx= st 0) x*))]
[(eq? st full-tree)
(do ([size size (fx- size 1)]
[offset offset (fx+ offset 1)]
[x* x* (cons (vector-ref v offset) x*)])
((fx= size 0) x*))]
[else
(let ([split (compute-split size)])
(extract (tree-node-right st) (fx- size split) (fx+ offset split)
(extract (tree-node-left st) split offset x*)))]))))
(define tree-for-each ; assumes empty-tree is 0
(lambda (st size start end action)
(let f ([st st] [size size] [start start] [end end] [offset 0])
(cond
[(fixnum? st)
(unless (eq? st empty-tree)
(do ([st (fxbit-field st start end) (fxsrl st 1)] [offset (fx+ offset start) (fx+ offset 1)])
((fx= st 0))
(when (fxodd? st) (action offset))))]
[(eq? st full-tree)
(do ([start start (fx+ start 1)] [offset offset (fx+ offset 1)])
((fx= start end))
(action offset))]
[else
(let ([split (compute-split size)])
(when (fx< start split)
(f (tree-node-left st) split start (fxmin end split) offset))
(when (fx> end split)
(f (tree-node-right st) (fx- size split) (fxmax (fx- start split) 0) (fx- end split) (fx+ offset split))))]))))
(define tree-fold-left ; assumes empty-tree is 0
(lambda (proc size init st)
(let f ([st st] [size size] [offset 0] [init init])
(cond
[(fixnum? st)
(do ([st st (fxsrl st 1)]
[offset offset (fx+ offset 1)]
[init init (if (fxodd? st) (proc init offset) init)])
((fx= st 0) init))]
[(eq? st full-tree)
(do ([size size (fx- size 1)]
[offset offset (fx+ offset 1)]
[init init (proc init offset)])
((fx= size 0) init))]
[else
(let ([split (compute-split size)])
(f (tree-node-left st) split offset
(f (tree-node-right st) (fx- size split) (fx+ offset split) init)))]))))
(define tree-bit-set? ; assumes empty-tree is 0
(lambda (st size bit)
(let loop ([st st] [size size] [bit bit])
(cond
[(fixnum? st)
(and (not (eqv? st empty-tree))
; fxlogbit? is unnecessarily general, so roll our own
(fxlogtest st (fxsll 1 bit)))]
[(eq? st full-tree) #t]
[else
(let ([split (compute-split size)])
(if (fx< bit split)
(loop (tree-node-left st) split bit)
(loop (tree-node-right st) (fx- size split) (fx- bit split))))]))))
(define tree-bit-set ; assumes empty-tree is 0
(lambda (st size bit)
; set bit in tree. result is eq? to tr if result is same as tr.
(cond
[(eq? st full-tree) st]
[(fx< size (fixnum-width))
(let ([st (fxlogbit1 bit st)])
(if (fx= st (full-fixnum size))
full-tree
st))]
[else
(let ([split (compute-split size)])
(if (eqv? st empty-tree)
(if (fx< bit split)
(make-tree-node (tree-bit-set empty-tree split bit) empty-tree)
(make-tree-node empty-tree (tree-bit-set empty-tree (fx- size split) (fx- bit split))))
(let ([lst (tree-node-left st)] [rst (tree-node-right st)])
(if (fx< bit split)
(let ([new-lst (tree-bit-set lst split bit)])
(if (eq? new-lst lst)
st
(if (and (eq? new-lst full-tree) (eq? rst full-tree))
full-tree
(make-tree-node new-lst rst))))
(let ([new-rst (tree-bit-set rst (fx- size split) (fx- bit split))])
(if (eq? new-rst rst)
st
(if (and (eq? lst full-tree) (eq? new-rst full-tree))
full-tree
(make-tree-node lst new-rst))))))))])))
(define tree-bit-unset ; assumes empty-tree is 0
(lambda (st size bit)
; reset bit in tree. result is eq? to tr if result is same as tr.
(cond
[(fixnum? st)
(if (eqv? st empty-tree)
empty-tree
(fxlogbit0 bit st))]
[(eq? st full-tree)
(if (fx< size (fixnum-width))
(fxlogbit0 bit (full-fixnum size))
(let ([split (compute-split size)])
(if (fx< bit split)
(make-tree-node (tree-bit-unset full-tree split bit) full-tree)
(make-tree-node full-tree (tree-bit-unset full-tree (fx- size split) (fx- bit split))))))]
[else
(let ([split (compute-split size)] [lst (tree-node-left st)] [rst (tree-node-right st)])
(if (fx< bit split)
(let ([new-lst (tree-bit-unset lst split bit)])
(if (eq? new-lst lst)
st
(if (and (eq? new-lst empty-tree) (eq? rst empty-tree))
empty-tree
(make-tree-node new-lst rst))))
(let ([new-rst (tree-bit-unset rst (fx- size split) (fx- bit split))])
(if (eq? new-rst rst)
st
(if (and (eq? lst empty-tree) (eq? new-rst empty-tree))
empty-tree
(make-tree-node lst new-rst))))))])))
(define tree-bit-count ; assumes empty-tree is 0
(lambda (st size)
(cond
[(fixnum? st) (fxbit-count st)]
[(eq? st full-tree) size]
[else
(let ([split (compute-split size)])
(fx+
(tree-bit-count (tree-node-left st) split)
(tree-bit-count (tree-node-right st) (fx- size split))))])))
(define tree-same? ; assumes empty-tree is 0
(lambda (st1 st2)
(or (eq? st1 st2) ; assuming fixnums and full trees are eq-comparable
(and (tree-node? st1)
(tree-node? st2)
(tree-same? (tree-node-left st1) (tree-node-left st2))
(tree-same? (tree-node-right st1) (tree-node-right st2))))))
(define tree-merge
; merge tr1 and tr2. result is eq? to tr1 if result is same as tr1.
(lambda (st1 st2 size)
(cond
[(or (eq? st1 st2) (eq? st2 empty-tree)) st1]
[(eq? st1 empty-tree) st2]
[(or (eq? st1 full-tree) (eq? st2 full-tree)) full-tree]
[(fixnum? st1)
(safe-assert (fixnum? st2))
(let ([st (fxlogor st1 st2)])
(if (fx= st (full-fixnum size))
full-tree
st))]
[else
(let ([lst1 (tree-node-left st1)]
[rst1 (tree-node-right st1)]
[lst2 (tree-node-left st2)]
[rst2 (tree-node-right st2)])
(let ([split (compute-split size)])
(let ([l (tree-merge lst1 lst2 split)] [r (tree-merge rst1 rst2 (fx- size split))])
(cond
[(and (eq? l lst1) (eq? r rst1)) st1]
[(and (eq? l lst2) (eq? r rst2)) st2]
[(and (eq? l full-tree) (eq? r full-tree)) full-tree]
[else (make-tree-node l r)]))))]))))
(include "tree.ss")
(define-syntax tc-disp
(lambda (x)
(syntax-case x ()
@ -764,7 +536,7 @@
(define-record-type ctrpi ; compile-time version of rp-info
(nongenerative)
(sealed #t)
(fields label src sexpr mask))
(fields label src sexpr mask)) ; mask is like a livemask: an integer or (cons size tree)
(define-threaded next-lambda-seqno)
@ -809,7 +581,7 @@
nfv*
nfv**
(mutable weight)
(mutable call-live*)
(mutable call-live*) ; a tree
(mutable frame-words)
(mutable local-save*))
(protocol
@ -14421,24 +14193,37 @@
(define-who record-call-live!
(lambda (block* varvec)
(for-each
(lambda (block)
(when (newframe-block? block)
(let ([newframe-info (newframe-block-info block)])
(let ([call-live* (get-live-vars (newframe-block-live-call block) (vector-length varvec) varvec)])
(for-each
(lambda (x)
(define fixnum (lambda (x) (if (fixnum? x) x (most-positive-fixnum))))
(when (uvar? x)
(uvar-spilled! x #t)
(unless (block-pariah? block)
(uvar-save-weight-set! x
(fixnum
(+ (uvar-save-weight x)
(* (info-newframe-weight newframe-info) 2)))))))
call-live*)
(info-newframe-call-live*-set! newframe-info call-live*)))))
block*)))
(let ([spill-and-get-non-poison
(make-memoized-tree-reduce (vector-length varvec)
;; handle one var from tree:
(lambda (v offset)
(let ([x (vector-ref varvec offset)])
(cond
[(uvar? x)
(uvar-spilled! x #t)
(if (uvar-poison? x)
v
(cons x v))]
[else v])))
;; merge results from two trees:
append
'())])
(for-each
(lambda (block)
(when (newframe-block? block)
(let ([newframe-info (newframe-block-info block)])
(let ([non-poison-live* (spill-and-get-non-poison (newframe-block-live-call block))])
(unless (block-pariah? block)
(for-each
(lambda (x)
(define fixnum (lambda (x) (if (fixnum? x) x (most-positive-fixnum))))
(uvar-save-weight-set! x
(fixnum
(+ (uvar-save-weight x)
(* (info-newframe-weight newframe-info) 2)))))
non-poison-live*))
(info-newframe-call-live*-set! newframe-info (newframe-block-live-call block))))))
block*))))
; maintain move sets as (var . weight) lists, sorted by weight (largest first)
; 2014/06/26: allx move set size averages .79 elements with a max of 12, so no
@ -14462,6 +14247,8 @@
(values move (cons move2 move*)))))))))
cons))))))
(define poison-spillable-threshold 1000) ; NB: parameter?
(define-who identify-poison!
(lambda (kspillable varvec live-size block*)
(define kpoison 0)
@ -14493,6 +14280,31 @@
(unless (or (fx= stride 16) (< (* (fx- kspillable kpoison) (fx* stride 2)) 1000000))
(refine (fxsrl skip 1) skip)))))))
(define (make-get-non-poison varvec live-size kspillable keep-nonspillable?)
(cond
[(fx> kspillable poison-spillable-threshold)
;; It's probably worth pruning trees to non-poison when
;; iterating through spillables. This pays off when there
;; are enough iterations through spillables for non-poison
;; spillables and unspillables:
(make-memoized-tree-reduce live-size
(lambda (non-poison-out y-offset)
(cond
[(< y-offset kspillable)
(let ([y (vector-ref varvec y-offset)])
(if (uvar-poison? y)
non-poison-out
(tree-bit-set non-poison-out live-size y-offset)))]
[keep-nonspillable?
(tree-bit-set non-poison-out live-size y-offset)]
[else
non-poison-out]))
(lambda (t1 t2) (tree-merge t1 t2 live-size))
empty-tree)]
[else
;; Probably not worthwhile:
(lambda (out) out)]))
(define-who do-spillable-conflict!
(lambda (kspillable kfv varvec live-size block*)
(define remove-var (make-remove-var live-size))
@ -14501,6 +14313,8 @@
(when (var-index x2)
($add-move! x1 x2 2)
($add-move! x2 x1 2))))
(define get-non-poison
(make-get-non-poison varvec live-size kspillable #f))
(define add-conflict!
(lambda (x out)
; invariants:
@ -14513,10 +14327,11 @@
(lambda (y-offset)
; frame y -> poison spillable x
(conflict-bit-set! (var-spillable-conflict* (vector-ref varvec y-offset)) x-offset)))
(let ([cset (var-spillable-conflict* x)])
(let ([cset (var-spillable-conflict* x)]
[non-poison-out (get-non-poison out)])
(if (fx< x-offset kspillable)
(begin
(tree-for-each out live-size 0 kspillable
(tree-for-each non-poison-out live-size 0 kspillable
(lambda (y-offset)
(let ([y (vector-ref varvec y-offset)])
(unless (uvar-poison? y)
@ -14534,7 +14349,7 @@
(lambda (y-offset)
; frame x -> poison or non-poison spillable y
(conflict-bit-set! cset y-offset)))
(tree-for-each out live-size 0 kspillable
(tree-for-each non-poison-out live-size 0 kspillable
(lambda (y-offset)
(unless (uvar-poison? (vector-ref varvec y-offset))
; register x -> non-poison spillable y
@ -14703,11 +14518,57 @@
(definitions
(define remove-var (make-remove-var live-size))
(define find-max-fv
(lambda (call-live*)
(fold-left
(lambda (call-max-fv x)
(fxmax (fv-offset (if (uvar? x) (uvar-location x) x)) call-max-fv))
-1 call-live*)))
(make-memoized-tree-reduce (vector-length varvec)
(lambda (call-max-fv offset)
(let ([x (vector-ref varvec offset)])
(fxmax (fv-offset (if (uvar? x) (uvar-location x) x)) call-max-fv)))
fxmax -1))
(define add-to-live-pointer-tree
(lambda (lpt live)
(define (add-fv fv lpt)
(let ([offset (fv-offset fv)])
(if (fx= offset 0) ; no bit for fv0
lpt
(tree-bit-set lpt live-size (fx- offset 1)))))
(cond
[(fv? live) (add-fv live lpt)]
[(eq? (uvar-type live) 'ptr) (add-fv (uvar-location live) lpt)]
[else lpt])))
(define build-live-pointer-tree-from-tree
(make-memoized-tree-reduce (vector-length varvec)
(lambda (lpt offset)
(add-to-live-pointer-tree lpt (vector-ref varvec offset)))
(lambda (t1 t2) (tree-merge t1 t2 live-size))
empty-tree))
(define build-live-pointer-tree-from-list
(lambda (live*) (fold-left add-to-live-pointer-tree empty-tree live*)))
(define build-inspector-tree
(cond
[(info-lambda-ctci lambda-info) =>
(lambda (ctci)
(make-memoized-tree-reduce (vector-length varvec)
(lambda (tree offset lpm)
(let ([x (vector-ref varvec offset)])
(cond
[(and (uvar? x) (uvar-iii x)) =>
(lambda (index)
(safe-assert
(let ([name.offset (vector-ref (ctci-live ctci) index)])
($livemask-member? lpm (fx- (cdr name.offset) 1))))
(tree-bit-set tree live-size index))]
[else tree])))
(lambda (t1 t2) (tree-merge t1 t2 live-size))
empty-tree))]
[else #f]))
(define extract-local-save
(make-memoized-tree-reduce (vector-length varvec)
(lambda (var* offset)
(let ([x (vector-ref varvec offset)])
(if (and (uvar? x) (uvar-local-save? x))
(cons x var*)
var*)))
append
'()))
(define cool?
(lambda (base nfv*)
(let loop ([nfv* nfv*] [offset base])
@ -14736,41 +14597,6 @@
(for-each (lambda (nfv*) (set-offsets! nfv* arg-base)) nfv**)
base)
(loop (fx+ base 1))))))))
(define build-mask
(lambda (index*)
(define bucket-width (if (fx> (fixnum-width) 32) 32 16))
(let* ([nbits (fx+ (fold-left (lambda (m index) (fxmax m index)) -1 index*) 1)]
[nbuckets (fxdiv (fx+ nbits (fx- bucket-width 1)) bucket-width)]
[buckets (make-fxvector nbuckets 0)])
(for-each
(lambda (index)
(let-values ([(i j) (fxdiv-and-mod index bucket-width)])
(fxvector-set! buckets i (fxlogbit1 j (fxvector-ref buckets i)))))
index*)
(let f ([base 0] [len nbuckets])
(if (fx< len 2)
(if (fx= len 0)
0
(fxvector-ref buckets base))
(let ([half (fxsrl len 1)])
(logor
(bitwise-arithmetic-shift-left (f (fx+ base half) (fx- len half)) (fx* half bucket-width))
(f base half))))))))
(define build-live-pointer-mask
(lambda (live*)
(build-mask
(fold-left
(lambda (index* live)
(define (cons-fv fv index*)
(let ([offset (fv-offset fv)])
(if (fx= offset 0) ; no bit for fv0
index*
(cons (fx- offset 1) index*))))
(cond
[(fv? live) (cons-fv live index*)]
[(eq? (uvar-type live) 'ptr) (cons-fv (uvar-location live) index*)]
[else index*]))
'() live*))))
(define (process-info-newframe! info)
(unless (info-newframe-frame-words info)
(let ([call-live* (info-newframe-call-live* info)])
@ -14778,26 +14604,14 @@
(let ([cnfv* (info-newframe-cnfv* info)])
(fx+ (assign-new-frame! cnfv* (cons (info-newframe-nfv* info) (info-newframe-nfv** info)) call-live*)
(length cnfv*))))
(info-newframe-local-save*-set! info
(filter (lambda (x) (and (uvar? x) (uvar-local-save? x))) call-live*)))))
(info-newframe-local-save*-set! info (extract-local-save call-live*)))))
(define record-inspector-info!
(lambda (src sexpr rpl call-live* lpm)
(safe-assert (if call-live* rpl (not rpl)))
(cond
[(and call-live* (info-lambda-ctci lambda-info)) =>
(lambda (ctci)
(let ([mask (build-mask
(fold-left
(lambda (i* x)
(cond
[(and (uvar? x) (uvar-iii x)) =>
(lambda (index)
(safe-assert
(let ([name.offset (vector-ref (ctci-live ctci) index)])
(logbit? (fx- (cdr name.offset) 1) lpm)))
(cons index i*))]
[else i*]))
'() call-live*))])
(let ([mask ($make-livemask live-size (build-inspector-tree call-live* lpm))])
(when (or src sexpr (not (eqv? mask 0)))
(ctci-rpi*-set! ctci (cons (make-ctrpi rpl src sexpr mask) (ctci-rpi* ctci))))))]))))
(Pred : Pred (ir) -> Pred ())
@ -14809,10 +14623,14 @@
(foldable-Effect : Effect (ir new-effect*) -> * (new-effect*)
[(return-point ,info ,rpl ,mrvl (,cnfv* ...))
(process-info-newframe! info)
(let ([lpm (build-live-pointer-mask (append cnfv* (info-newframe-call-live* info)))])
(let ([lpm ($make-livemask
live-size
(tree-merge (build-live-pointer-tree-from-list cnfv*)
(build-live-pointer-tree-from-tree (info-newframe-call-live* info))
live-size))])
(record-inspector-info! (info-newframe-src info) (info-newframe-sexpr info) rpl (info-newframe-call-live* info) lpm)
(with-output-language (L15b Effect)
(safe-assert (< -1 lpm (ash 1 (fx- (info-newframe-frame-words info) 1))))
(safe-assert (<= ($livemask-size lpm) (fx- (info-newframe-frame-words info) 1)))
(cons `(rp-header ,mrvl ,(fx* (info-newframe-frame-words info) (constant ptr-bytes)) ,lpm) new-effect*)))]
[(remove-frame ,live-info ,info)
(process-info-newframe! info)
@ -15260,6 +15078,8 @@
(define-who do-unspillable-conflict!
(lambda (kfv kspillable varvec live-size kunspillable unvarvec block*)
(define remove-var (make-remove-var live-size))
(define get-non-poison
(make-get-non-poison varvec live-size kspillable #t))
(define unspillable?
(lambda (x)
(and (uvar? x) (uvar-unspillable? x))))
@ -15345,7 +15165,7 @@
(Effect* (cdr e*)
(nanopass-case (L15d Effect) (car e*)
[(set! ,live-info ,x ,rhs)
(let ([spillable-live (live-info-live live-info)])
(let ([spillable-live (get-non-poison (live-info-live live-info))])
(if (unspillable? x)
(let ([unspillable* (remq x unspillable*)])
(safe-assert (uvar-seen? x))
@ -15762,11 +15582,11 @@
(RApass unparse-L15a do-live-analysis! live-size entry-block*)
; this is worth enabling from time to time...
#;(check-entry-live! (info-lambda-name info) live-size varvec entry-block*)
; rerun intra-block live analysis and record (fv v reg v spillable) x spillable conflicts
(RApass unparse-L15a record-call-live! block* varvec)
;; NB: we could just use (vector-length varvec) to get live-size
(when (fx> kspillable 1000) ; NB: parameter?
(when (fx> kspillable poison-spillable-threshold)
(RApass unparse-L15a identify-poison! kspillable varvec live-size block*))
(RApass unparse-L15a record-call-live! block* varvec)
; rerun intra-block live analysis and record (fv v reg v spillable) x spillable conflicts
(RApass unparse-L15a do-spillable-conflict! kspillable kfv varvec live-size block*)
#;(show-conflicts (info-lambda-name info) varvec '#())
; find frame homes for call-live variables; adds new fv x spillable conflicts

View File

@ -1744,6 +1744,29 @@
)
(let ()
(include "tree.ss")
(set! $livemask?
(lambda (v)
;; intended to be constant-time, so just check plausible:
(or (integer? v) (and (pair? v) (integer? (car v))))))
(set! $make-livemask
(lambda (size t)
(let ([t (or (tree-simplify-for-readonly t size) t)])
(if (integer? t)
t
(cons size t)))))
(set! $livemask-size
(lambda (livemask)
(if (number? livemask)
(integer-length livemask)
(tree-bit-length (cdr livemask) (car livemask)))))
(set! $livemask-member?
(lambda (livemask index)
(if (number? livemask)
(logbit? index livemask)
(tree-bit-set? (cdr livemask) (car livemask) index)))))
(define inspect/object
(lambda (x)
(define compute-size
@ -2165,7 +2188,7 @@
(values (source-file-descriptor-name sfd) fp))]
[(path line char) (values path line char)]))
(values))))
(define-who make-continuation-object
(lambda (x pos)
(include "types.ss")
@ -2192,19 +2215,20 @@
(let ([cookie '(chocolate . chip)])
(let ([vals (make-vector len cookie)] [vars (make-vector len '())] [live (code-info-live info)])
; fill vals based on live-pointer mask
(let f ([i 1] [lpm lpm])
(let f ([i 1])
(unless (>= i len)
(when (odd? lpm)
(when ($livemask-member? lpm (fx- i 1))
(vector-set! vals (fx1- i) ($continuation-stack-ref x i)))
(f (fx1+ i) (ash lpm -1))))
(f (fx1+ i))))
; fill vars based on code-info variable mask
(let f ([i 0] [mask (rp-info-mask rpi)])
(unless (eqv? mask 0)
(when (odd? mask)
(let ([p (vector-ref live i)])
(let ([index (fx1- (cdr p))])
(vector-set! vars index (cons (car p) (vector-ref vars index))))))
(f (+ i 1) (ash mask -1))))
(let ([mask (rp-info-mask rpi)])
(let f ([i 0])
(unless (fx= i ($livemask-size mask))
(when ($livemask-member? mask i)
(let ([p (vector-ref live i)])
(let ([index (fx1- (cdr p))])
(vector-set! vars index (cons (car p) (vector-ref vars index))))))
(f (+ i 1)))))
; create return vector
(with-values
(let f ([i 0] [count 0] [cp #f] [cpvar* '()])
@ -2255,13 +2279,13 @@
(real-make-continuation-object x (rp-info-src rpi) (rp-info-sexpr rpi) cp v frame-count pos))))))]
[else
(let ([v (list->vector
(let f ([i 1] [lpm lpm])
(let f ([i 1])
(cond
[(>= i len) '()]
[(odd? lpm)
[($livemask-member? lpm (fx- i 1))
(cons (make-variable-object ($continuation-stack-ref x i) #f)
(f (fx1+ i) (ash lpm -1)))]
[else (f (fx1+ i) (ash lpm -1))])))])
(f (fx1+ i)))]
[else (f (fx1+ i))])))])
(real-make-continuation-object x #f #f #f v (vector-length v) pos))]))))
(define real-make-continuation-object
@ -2502,9 +2526,9 @@
($split-continuation x 0)
; not following RA slot at base of the frame, but this should always hold dounderflow,
; which will be in the static generation and therefore ignored anyway after compact heap
(let ([len ($continuation-stack-length x)])
(let ([len ($continuation-stack-length x)]
[lpm ($continuation-return-livemask x)])
(let loop ([i 1]
[lpm ($continuation-return-livemask x)]
[size (fx+ (constant size-continuation)
(align (fx* len (constant ptr-bytes)))
(compute-size ($continuation-return-code x))
@ -2513,7 +2537,7 @@
(compute-size ($continuation-winders x)))])
(if (fx>= i len)
size
(loop (fx+ i 1) (ash lpm -1) (if (odd? lpm) (fx+ size (compute-size ($continuation-stack-ref x i))) size)))))))
(loop (fx+ i 1) (if ($livemask-member? lpm (fx- i 1)) (fx+ size (compute-size ($continuation-stack-ref x i))) size)))))))
(let ([n ($closure-length x)])
(do ([i 0 (fx+ i 1)]
[size (fx+ (align (fx+ (constant header-size-closure) (fx* n (constant ptr-bytes)))) (compute-size ($closure-code x)))
@ -2665,12 +2689,13 @@
(compute-composition! ($closure-code x))
(compute-composition! ($continuation-link x))
(compute-composition! ($continuation-winders x))
(let ([len ($continuation-stack-length x)])
(let ([len ($continuation-stack-length x)]
[lpm ($continuation-return-livemask x)])
(incr! stack (align (fx* len (constant ptr-bytes))))
(let loop ([i 1] [lpm ($continuation-return-livemask x)])
(let loop ([i 1])
(unless (fx>= i len)
(when (odd? lpm) (compute-composition! ($continuation-stack-ref x i)))
(loop (fx+ i 1) (ash lpm -1)))))))
(when ($livemask-member? lpm (fx- i 1)) (compute-composition! ($continuation-stack-ref x i)))
(loop (fx+ i 1)))))))
(begin
(compute-composition! ($closure-code x))
(let ([n ($closure-length x)])
@ -2800,13 +2825,14 @@
($split-continuation x 0)
; not following RA slot at base of the frame, but this should always hold dounderflow,
; which will be in the static generation and therefore ignored anyway after compact heap
(let ([len ($continuation-stack-length x)])
(let loop ([i 1] [lpm ($continuation-return-livemask x)])
(let ([len ($continuation-stack-length x)]
[lpm ($continuation-return-livemask x)])
(let loop ([i 1])
(if (fx>= i len)
(construct-proc ($continuation-return-code x) ($closure-code x) ($continuation-link x) ($continuation-winders x) next-proc)
(if (odd? lpm)
(construct-proc ($continuation-stack-ref x i) (loop (fx+ i 1) (ash lpm -1)))
(loop (fx+ i 1) (ash lpm -1))))))))
(if ($livemask-member? lpm (fx- i 1))
(construct-proc ($continuation-stack-ref x i) (loop (fx+ i 1)))
(loop (fx+ i 1))))))))
(construct-proc ($closure-code x)
(let ([n ($closure-length x)])
(let f ([i 0])

View File

@ -783,6 +783,8 @@
(lambda (x)
(and (integer? x) (exact? x))))
(define livemask? $livemask?)
; calling conventions are imposed; clauses no longer have formals (they are
; now locals set by arguments from argument registers and frame); calls no
; longer have arguments; case-lambda is resposible for dispatching to correct
@ -798,7 +800,7 @@
(pred-primitive (pred-prim))
(value-primitive (value-prim))
(immediate (imm fs))
(exact-integer (lpm))
(livemask (lpm))
(info (info))
(maybe-label (mrvl))
(label (l rpl))
@ -927,7 +929,7 @@
(pred-primitive (pred-prim))
(value-primitive (value-prim))
(immediate (imm fs))
(exact-integer (lpm))
(livemask (lpm))
(live-info (live-info))
(info (info))
(label (l rpl))

View File

@ -2084,7 +2084,7 @@
(if (target-fixnum? lpm)
`(long . ,(fix lpm))
`(abs 0 (object ,lpm)))
(aop-cons* `(asm livemask: ,(format "~b" lpm))
(aop-cons* `(asm livemask: ,(if (number? lpm) (format "~b" lpm) (format "~s" lpm)))
'(code-top-link)
(aop-cons* `(asm code-top-link)
`(long . ,fs)

View File

@ -2043,6 +2043,9 @@
($library-requirements-options [flags])
($library-search [flags])
($list-length [flags])
($livemask? [flags])
($livemask-size [flags])
($livemask-member? [flags])
($load-library [flags])
($locate-source [flags])
($logand [flags])
@ -2077,6 +2080,7 @@
($make-fptr [flags pure mifoldable discard true])
($make-graph-env [flags])
($make-library-requirements-options [flags pure discard true])
($make-livemask [flags])
($make-object-finder [flags])
($make-promise [flags alloc])
($make-read [flags])

303
s/tree.ss Normal file
View File

@ -0,0 +1,303 @@
(module (empty-tree full-tree tree-extract tree-for-each tree-fold-left tree-bit-set? tree-bit-set tree-bit-unset
tree-bit-count tree-bit-length tree-simplify-for-readonly tree-same? tree-merge
make-memoized-tree-reduce)
; tree -> fixnum | (tree-node tree tree) | #t
; 0 represents any tree or subtree with no bits set, and a tree or subtree
; with no bits set is always 0.
; #t represents a subtree with all bits set
(define empty-tree 0)
; any tree or subtree with all bits set
(define full-tree #t)
(define (full-fixnum size) (fxsrl (most-positive-fixnum) (fx- (fx- (fixnum-width) 1) size)))
(define compute-split
(lambda (size)
(fxsrl size 1)
; 2015/03/15 rkd: tried the following under the theory that we'd allocate
; fewer nodes. for example, say fixmun-width is 30 and size is 80. if we
; split 40/40 we create two nodes under the current node. if instead we
; split 29/51 we create just one node and one fixnum under the current
; node. this worked as planned; however, it reduced the number of nodes
; created by only 3.3% on the x86 and made compile times slightly worse.
#;(if (fx<= size (fx* (fx- (fixnum-width) 1) 3)) (fx- (fixnum-width) 1) (fxsrl size 1))))
;; A tree is represented with pairs so that it can serve directly as
;; a livemask when paired with its sized, as long as the tree
;; doesn't have any `full-tree` parts
(module (make-tree-node tree-node? tree-node-left tree-node-right)
(define make-tree-node cons)
(define tree-node? pair?)
(define tree-node-left car)
(define tree-node-right cdr))
(define tree-extract ; assumes empty-tree is 0
(lambda (st size v)
(let extract ([st st] [size size] [offset 0] [x* '()])
(cond
[(fixnum? st)
(do ([st st (fxsrl st 1)]
[offset offset (fx+ offset 1)]
[x* x* (if (fxodd? st) (cons (vector-ref v offset) x*) x*)])
((fx= st 0) x*))]
[(eq? st full-tree)
(do ([size size (fx- size 1)]
[offset offset (fx+ offset 1)]
[x* x* (cons (vector-ref v offset) x*)])
((fx= size 0) x*))]
[else
(let ([split (compute-split size)])
(extract (tree-node-right st) (fx- size split) (fx+ offset split)
(extract (tree-node-left st) split offset x*)))]))))
(define tree-for-each ; assumes empty-tree is 0
(lambda (st size start end action)
(let f ([st st] [size size] [start start] [end end] [offset 0])
(cond
[(fixnum? st)
(unless (eq? st empty-tree)
(do ([st (fxbit-field st start end) (fxsrl st 1)] [offset (fx+ offset start) (fx+ offset 1)])
((fx= st 0))
(when (fxodd? st) (action offset))))]
[(eq? st full-tree)
(do ([start start (fx+ start 1)] [offset offset (fx+ offset 1)])
((fx= start end))
(action offset))]
[else
(let ([split (compute-split size)])
(when (fx< start split)
(f (tree-node-left st) split start (fxmin end split) offset))
(when (fx> end split)
(f (tree-node-right st) (fx- size split) (fxmax (fx- start split) 0) (fx- end split) (fx+ offset split))))]))))
(define tree-fold-left ; assumes empty-tree is 0
(lambda (proc size init st)
(let f ([st st] [size size] [offset 0] [init init])
(cond
[(fixnum? st)
(do ([st st (fxsrl st 1)]
[offset offset (fx+ offset 1)]
[init init (if (fxodd? st) (proc init offset) init)])
((fx= st 0) init))]
[(eq? st full-tree)
(do ([size size (fx- size 1)]
[offset offset (fx+ offset 1)]
[init init (proc init offset)])
((fx= size 0) init))]
[else
(let ([split (compute-split size)])
(f (tree-node-left st) split offset
(f (tree-node-right st) (fx- size split) (fx+ offset split) init)))]))))
(define tree-bit-set? ; assumes empty-tree is 0
(lambda (st size bit)
(let loop ([st st] [size size] [bit bit])
(cond
[(fixnum? st)
(and (not (eqv? st empty-tree))
; fxlogbit? is unnecessarily general, so roll our own
(fxlogtest st (fxsll 1 bit)))]
[(eq? st full-tree) #t]
[else
(let ([split (compute-split size)])
(if (fx< bit split)
(loop (tree-node-left st) split bit)
(loop (tree-node-right st) (fx- size split) (fx- bit split))))]))))
(define tree-bit-set ; assumes empty-tree is 0
(lambda (st size bit)
; set bit in tree. result is eq? to tr if result is same as tr.
(cond
[(eq? st full-tree) st]
[(fx< size (fixnum-width))
(let ([st (fxlogbit1 bit st)])
(if (fx= st (full-fixnum size))
full-tree
st))]
[else
(let ([split (compute-split size)])
(if (eqv? st empty-tree)
(if (fx< bit split)
(make-tree-node (tree-bit-set empty-tree split bit) empty-tree)
(make-tree-node empty-tree (tree-bit-set empty-tree (fx- size split) (fx- bit split))))
(let ([lst (tree-node-left st)] [rst (tree-node-right st)])
(if (fx< bit split)
(let ([new-lst (tree-bit-set lst split bit)])
(if (eq? new-lst lst)
st
(if (and (eq? new-lst full-tree) (eq? rst full-tree))
full-tree
(make-tree-node new-lst rst))))
(let ([new-rst (tree-bit-set rst (fx- size split) (fx- bit split))])
(if (eq? new-rst rst)
st
(if (and (eq? lst full-tree) (eq? new-rst full-tree))
full-tree
(make-tree-node lst new-rst))))))))])))
(define tree-bit-unset ; assumes empty-tree is 0
(lambda (st size bit)
; reset bit in tree. result is eq? to tr if result is same as tr.
(cond
[(fixnum? st)
(if (eqv? st empty-tree)
empty-tree
(fxlogbit0 bit st))]
[(eq? st full-tree)
(if (fx< size (fixnum-width))
(fxlogbit0 bit (full-fixnum size))
(let ([split (compute-split size)])
(if (fx< bit split)
(make-tree-node (tree-bit-unset full-tree split bit) full-tree)
(make-tree-node full-tree (tree-bit-unset full-tree (fx- size split) (fx- bit split))))))]
[else
(let ([split (compute-split size)] [lst (tree-node-left st)] [rst (tree-node-right st)])
(if (fx< bit split)
(let ([new-lst (tree-bit-unset lst split bit)])
(if (eq? new-lst lst)
st
(if (and (eq? new-lst empty-tree) (eq? rst empty-tree))
empty-tree
(make-tree-node new-lst rst))))
(let ([new-rst (tree-bit-unset rst (fx- size split) (fx- bit split))])
(if (eq? new-rst rst)
st
(if (and (eq? lst empty-tree) (eq? new-rst empty-tree))
empty-tree
(make-tree-node lst new-rst))))))])))
(define tree-bit-count ; assumes empty-tree is 0
(lambda (st size)
(cond
[(fixnum? st) (fxbit-count st)]
[(eq? st full-tree) size]
[else
(let ([split (compute-split size)])
(fx+
(tree-bit-count (tree-node-left st) split)
(tree-bit-count (tree-node-right st) (fx- size split))))])))
(define tree-bit-length
(lambda (st size)
(cond
[(fixnum? st) (integer-length st)]
[(eq? st full-tree) size]
[else
(let ([split (compute-split size)])
(let ([rlen (tree-bit-length (tree-node-right st) (fx- size split))])
(if (fx= 0 rlen)
(tree-bit-length (tree-node-left st) split)
(fx+ split rlen))))])))
;; If a tree has only a leftmost fixnum, then we can
;; reperesent it for `tree-bit-set?` as just the fixnum.
(define tree-simplify-for-readonly
(lambda (st size)
(cond
[(fixnum? st) st]
[(eq? st full-tree)
(and (fx< size (fixnum-width))
(full-fixnum size))]
[else
(and (eq? (tree-node-right st) empty-tree)
(tree-simplify-for-readonly (tree-node-left st) (compute-split size)))])))
(define tree-same? ; assumes empty-tree is 0
(lambda (st1 st2)
(or (eq? st1 st2) ; assuming fixnums and full trees are eq-comparable
(and (tree-node? st1)
(tree-node? st2)
(tree-same? (tree-node-left st1) (tree-node-left st2))
(tree-same? (tree-node-right st1) (tree-node-right st2))))))
(define tree-merge
; merge tr1 and tr2. result is eq? to tr1 if result is same as tr1.
(lambda (st1 st2 size)
(cond
[(or (eq? st1 st2) (eq? st2 empty-tree)) st1]
[(eq? st1 empty-tree) st2]
[(or (eq? st1 full-tree) (eq? st2 full-tree)) full-tree]
[(fixnum? st1)
(safe-assert (fixnum? st2))
(let ([st (fxlogor st1 st2)])
(if (fx= st (full-fixnum size))
full-tree
st))]
[else
(let ([lst1 (tree-node-left st1)]
[rst1 (tree-node-right st1)]
[lst2 (tree-node-left st2)]
[rst2 (tree-node-right st2)])
(let ([split (compute-split size)])
(let ([l (tree-merge lst1 lst2 split)] [r (tree-merge rst1 rst2 (fx- size split))])
(cond
[(and (eq? l lst1) (eq? r rst1)) st1]
[(and (eq? l lst2) (eq? r rst2)) st2]
[(and (eq? l full-tree) (eq? r full-tree)) full-tree]
[else (make-tree-node l r)]))))])))
(define make-memoized-tree-reduce
;; A function produced by `make-memoized-tree-reduce` is meant to
;; be applied to different trees where the same bit in different
;; trees means the same thing. Memoizing reduces over multiple
;; trees is useful when the tree are likely to share nodes.
;; Memoizing is approximate, applied only when it seems like to be
;; worthwhile. Memoizing also relies on results being non-#f.
(lambda (total-size leaf-proc merge-proc init)
(cond
[(< total-size (* 8 (fixnum-width)))
;; Memoizing probably isn't worthwhile
(case-lambda
[(st)
(tree-fold-left leaf-proc total-size init st)]
[(st . extra-leaf-args)
(tree-fold-left (lambda (init offset)
(apply leaf-proc init offset extra-leaf-args))
total-size init st)])]
[else
;; Memoizing could be worthwhile...
(let ([cache (make-eq-hashtable)] ; maps st to a result
[full-cache (make-eqv-hashtable)] ; maps offset+size to a result for full trees
[apply-leaf-proc (lambda (init offset extra-leaf-args)
(if (null? extra-leaf-args)
(leaf-proc init offset)
(apply leaf-proc init offset extra-leaf-args)))])
(lambda (st . extra-leaf-args)
(let f ([st st] [size total-size] [offset 0])
(cond
[(fixnum? st)
;; No memoizing at fixnum leaves, since it seems unlikely
;; to be useful
(do ([st st (fxsrl st 1)]
[offset offset (fx+ offset 1)]
[init init (if (fxodd? st) (apply-leaf-proc init offset extra-leaf-args) init)])
((fx= st 0) init))]
[(eq? st full-tree)
;; Memoizing at full subtrees uses offset and size
;; (combined into one number) to identity the subtree.
(let ([key (+ offset (* total-size size))])
(cond
[(hashtable-ref full-cache key #f)
=> (lambda (v) v)]
[else
(let ([v (do ([size size (fx- size 1)]
[offset offset (fx+ offset 1)]
[init init (apply-leaf-proc init offset extra-leaf-args)])
((fx= size 0) init))])
(hashtable-set! full-cache key v)
v)]))]
[else
;; We're relying on a fresh `cons`es to repersent different parts
;; of a tree, even if the parts have the same local content. So,
;; `eq?` identifies a subtree.
(let ([cell (eq-hashtable-cell cache st #f)]
[key (+ offset (* total-size size))])
(cond
[(cdr cell) => (lambda (v) v)]
[else
(let ([v (let ([split (compute-split size)])
(merge-proc (f (tree-node-left st) split offset)
(f (tree-node-right st) (fx- size split) (fx+ offset split))))])
(set-cdr! cell v)
v)]))]))))]))))

View File

@ -59,7 +59,11 @@
(sealed #t))
(define-record-type rp-info
(fields (immutable offset) (immutable src) (immutable sexpr) (immutable mask))
(fields
(immutable offset)
(immutable src)
(immutable sexpr)
(immutable mask)) ; an integer or (cons size tree)
(nongenerative #{rp-info gr886ae7iuw4wt9ft4vxym-1})
(sealed #t))

View File

@ -2267,7 +2267,7 @@
(if (target-fixnum? lpm)
`(long . ,(fix lpm))
`(abs 0 (object ,lpm)))
(aop-cons* `(asm livemask: ,(format "~b" lpm))
(aop-cons* `(asm livemask: ,(if (number? lpm) (format "~b" lpm) (format "~s" lpm)))
'(code-top-link)
(aop-cons* `(asm code-top-link)
`(long . ,fs)

View File

@ -2412,7 +2412,7 @@
(if (target-fixnum? lpm)
`(,size . ,(fix lpm))
`(abs 0 (object ,lpm)))
(aop-cons* `(asm livemask: ,(format "~b" lpm))
(aop-cons* `(asm livemask: ,(if (number? lpm) (format "~b" lpm) (format "~s" lpm)))
'(code-top-link)
(aop-cons* `(asm code-top-link)
`(,size . ,fs)

View File

@ -17,6 +17,11 @@
@SET "Path32=%VCINSTALLDIR%Redist\MSVC\14.11.25325\MergeModules\Microsoft_VC141_CRT_x86.msm"
@SET "Path64=%VCINSTALLDIR%Redist\MSVC\14.11.25325\MergeModules\Microsoft_VC141_CRT_x64.msm"
)
@IF EXIST "%VCINSTALLDIR%Redist\MSVC\14.12.25810" (
@SET "Path32=%VCINSTALLDIR%Redist\MSVC\14.12.25810\MergeModules\Microsoft_VC141_CRT_x86.msm"
@SET "Path64=%VCINSTALLDIR%Redist\MSVC\14.12.25810\MergeModules\Microsoft_VC141_CRT_x64.msm"
)
)
@DEL vcredist.wxs >nul 2>&1