cs: change continuation-frame marks table
Use an association list instead of an eq hashtable. This choice is compatible with assumptions in traditional Racket (i.e., that the number of mark keys per continuation frame will be small) and cuts about 1/4 of the time in a benchmark like (define f ((contract (-> (-> integer? integer?)) (λ () values) 'pos 'neg))) (time (for ([x (in-range 1000000)]) (f x)))
This commit is contained in:
parent
99fff46726
commit
c2c04711a3
|
@ -783,6 +783,68 @@
|
|||
mark-splice)))]
|
||||
[else mf]))
|
||||
|
||||
;; ----------------------------------------
|
||||
;; Continuation-mark table
|
||||
|
||||
;; A continuation-mark table within a frame is just an association
|
||||
;; list. This works well as long as the number of marks per frame is
|
||||
;; small.
|
||||
|
||||
(define empty-mark-table '())
|
||||
|
||||
(define (mark-table-add mt k v)
|
||||
(cons (cons k v) mt))
|
||||
|
||||
(define (mark-table-remove mt k)
|
||||
(cond
|
||||
[(null? mt) mt]
|
||||
[(eq? k (caar mt)) (cdr mt)]
|
||||
[else (let ([mt-rest (mark-table-remove (cdr mt) k)])
|
||||
(if (eq? mt-rest (cdr mt))
|
||||
mt
|
||||
(cons (car mt) mt-rest)))]))
|
||||
|
||||
(define (mark-table-add/replace mt k v)
|
||||
(mark-table-add (mark-table-remove mt k) k v))
|
||||
|
||||
(define (mark-table-ref mt k default)
|
||||
(let ([a (#%assq k mt)])
|
||||
(if a
|
||||
(cdr a)
|
||||
default)))
|
||||
|
||||
(define (mark-table-merge a b)
|
||||
(cond
|
||||
[(null? a) b]
|
||||
[(null? b) a]
|
||||
[else
|
||||
(let loop ([b b] [a a])
|
||||
(cond
|
||||
[(null? a) b]
|
||||
[else (let ([p (car a)])
|
||||
(loop (mark-table-add/replace b (car p) (cdr p))
|
||||
(cdr a)))]))]))
|
||||
|
||||
(define (mark-table-prune a b)
|
||||
(cond
|
||||
[(null? a) b]
|
||||
[(null? b) a]
|
||||
[else
|
||||
(let loop ([b b] [a a])
|
||||
(cond
|
||||
[(null? a) b]
|
||||
[else (let ([p (car a)])
|
||||
(loop (mark-table-remove b (car p))
|
||||
(cdr a)))]))]))
|
||||
|
||||
(define (mark-table->hash mt)
|
||||
(let loop ([ht empty-hasheq] [mt mt])
|
||||
(cond
|
||||
[(null? mt) ht]
|
||||
[else (let ([p (car mt)])
|
||||
(loop (intmap-set ht (car p) (cdr p))
|
||||
(cdr mt)))])))
|
||||
|
||||
;; ----------------------------------------
|
||||
;; Continuation marks
|
||||
|
||||
|
@ -828,9 +890,9 @@
|
|||
(unless (eq? key none)
|
||||
(current-mark-stack (make-mark-stack-frame (mark-stack-frame-prev mark-stack)
|
||||
k
|
||||
(intmap-set/cm-key (mark-stack-frame-table mark-stack)
|
||||
key
|
||||
val)
|
||||
(mark-table-add/replace* (mark-stack-frame-table mark-stack)
|
||||
key
|
||||
val)
|
||||
#f)))
|
||||
(proc)]
|
||||
[else
|
||||
|
@ -841,8 +903,8 @@
|
|||
(make-mark-stack-frame mark-stack
|
||||
new-k
|
||||
(if (eq? key none)
|
||||
empty-hasheq
|
||||
(intmap-set/cm-key empty-hasheq key val))
|
||||
empty-mark-table
|
||||
(mark-table-add empty-mark-table key val))
|
||||
#f))
|
||||
(proc)))
|
||||
(current-mark-stack (mark-stack-frame-prev (current-mark-stack)))
|
||||
|
@ -856,7 +918,7 @@
|
|||
(current-mark-stack
|
||||
(make-mark-stack-frame (current-mark-stack)
|
||||
#f
|
||||
(intmap-set empty-hasheq key val)
|
||||
(mark-table-add empty-mark-table key val)
|
||||
#f))
|
||||
(proc)
|
||||
;; If we're in an escape process, then `(current-mark-stack)` might not
|
||||
|
@ -874,7 +936,7 @@
|
|||
[(not mark-stack) null]
|
||||
[(mark-stack-frame-flat mark-stack) => (lambda (l) l)]
|
||||
[else
|
||||
(let ([l (cons (mark-stack-frame-table mark-stack)
|
||||
(let ([l (cons (mark-table->hash (mark-stack-frame-table mark-stack))
|
||||
(loop (mark-stack-frame-prev mark-stack)))])
|
||||
(set-mark-stack-frame-flat! mark-stack l)
|
||||
l)])))
|
||||
|
@ -948,22 +1010,10 @@
|
|||
[else
|
||||
(make-mark-stack-frame #f
|
||||
(mark-stack-frame-k mark-stack)
|
||||
(merge-mark-table (mark-stack-frame-table mark-stack)
|
||||
(mark-table-merge (mark-stack-frame-table mark-stack)
|
||||
(mark-stack-frame-table mark-splice))
|
||||
#f)]))
|
||||
|
||||
(define (merge-mark-table a b)
|
||||
(cond
|
||||
[(eq? empty-hasheq a) b]
|
||||
[(eq? empty-hasheq b) a]
|
||||
[else
|
||||
(let loop ([b b] [i (hash-iterate-first a)])
|
||||
(cond
|
||||
[(not i) b]
|
||||
[else (let-values ([(key val) (hash-iterate-key+value a i)])
|
||||
(loop (hash-set b key val)
|
||||
(hash-iterate-next a i)))]))]))
|
||||
|
||||
;; If `mark-stack` ends with a frame that is conceptually
|
||||
;; merged with one in `mark-splice`, then discard any keys
|
||||
;; in `mark-splice` that are in the `mark-stack` frame.
|
||||
|
@ -984,22 +1034,11 @@
|
|||
[(and (not prev) (eq? (mark-stack-frame-k mark-stack) empty-k))
|
||||
(make-mark-stack-frame #f
|
||||
empty-k
|
||||
(prune-mark-table (mark-stack-frame-table mark-stack)
|
||||
(mark-table-prune (mark-stack-frame-table mark-stack)
|
||||
(mark-stack-frame-table mark-splice))
|
||||
#f)]
|
||||
[else (loop prev)]))]))]))
|
||||
|
||||
(define (prune-mark-table a b)
|
||||
(cond
|
||||
[(eq? empty-hasheq a) b]
|
||||
[(eq? empty-hasheq b) a]
|
||||
[else
|
||||
(let loop ([b b] [i (hash-iterate-first a)])
|
||||
(cond
|
||||
[(not i) b]
|
||||
[else (loop (hash-remove b (hash-iterate-key a i))
|
||||
(hash-iterate-next a i))]))]))
|
||||
|
||||
(define (mark-stack-starts-with? mark-stack k)
|
||||
(and mark-stack
|
||||
(eq? k (mark-stack-frame-k mark-stack))))
|
||||
|
@ -1011,7 +1050,7 @@
|
|||
[(mark-stack-starts-with? mark-stack k)
|
||||
(make-mark-stack-frame (mark-stack-frame-prev mark-stack)
|
||||
(mark-stack-frame-k mark-stack)
|
||||
empty-hasheq
|
||||
empty-mark-table
|
||||
#f)]
|
||||
[else mark-stack]))
|
||||
|
||||
|
@ -1057,9 +1096,9 @@
|
|||
(call/cc (lambda (k)
|
||||
(when (eq? k (current-empty-k)) (merge-mark-splice!))
|
||||
(if (eq? k (mark-stack-frame-k (current-mark-stack)))
|
||||
(|#%app| proc (let ([v (intmap-ref (mark-stack-frame-table (current-mark-stack))
|
||||
key
|
||||
none)])
|
||||
(|#%app| proc (let ([v (mark-table-ref (mark-stack-frame-table (current-mark-stack))
|
||||
key
|
||||
none)])
|
||||
(if (eq? v none)
|
||||
default-v
|
||||
(wrapper v))))
|
||||
|
@ -1362,8 +1401,8 @@
|
|||
(and (impersonator? v)
|
||||
(authentic-continuation-mark-key? (impersonator-val v)))))
|
||||
|
||||
;; Like `intmap-set`, but handles continuation-mark-key impersonators
|
||||
(define (intmap-set/cm-key ht k v)
|
||||
;; Like `mark-table-add/replace`, but handles continuation-mark-key impersonators
|
||||
(define (mark-table-add/replace* ht k v)
|
||||
(cond
|
||||
[(and (impersonator? k)
|
||||
(authentic-continuation-mark-key? (impersonator-val k)))
|
||||
|
@ -1383,8 +1422,8 @@
|
|||
[(impersonator? k)
|
||||
(loop (impersonator-next k) v)]
|
||||
[else
|
||||
(intmap-set ht k v)]))]
|
||||
[else (intmap-set ht k v)]))
|
||||
(mark-table-add/replace ht k v)]))]
|
||||
[else (mark-table-add/replace ht k v)]))
|
||||
|
||||
;; Extracts the key and converts the wrapper functions into
|
||||
;; a single function:
|
||||
|
|
Loading…
Reference in New Issue
Block a user