compiler/zo-marshal: fix handling of cyclic scope data

Insert CPT_SHARED as needed to break cycles within scope data.
This commit is contained in:
Matthew Flatt 2015-08-13 20:03:52 -06:00
parent d652ea0d52
commit 490b10483a
3 changed files with 85 additions and 39 deletions

View File

@ -229,7 +229,7 @@
[marshal-parsed [marshal-parsed
#t #t
(zo-marshal parse-orig)] (zo-marshal parse-orig)]
[parse-marshalled [parse-marshaled
#t #t
(zo-parse/bytes marshal-parsed)] (zo-parse/bytes marshal-parsed)]
#;[compare-parsed-to-parsed-marshalled #;[compare-parsed-to-parsed-marshalled

View File

@ -148,17 +148,18 @@
(define stx-objs (make-hasheq)) (define stx-objs (make-hasheq))
(define wraps (make-hasheq)) (define wraps (make-hasheq))
(define hash-consed (make-hash)) (define hash-consed (make-hash))
(define hash-consed-results (make-hasheq))
; (obj -> (or pos #f)) output-port -> number ; (obj -> (or pos #f)) output-port -> number
; writes top to outp using shared-obj-pos to determine symref ; writes top to outp using shared-obj-pos to determine symref
; returns the file position at the end of the compilation top ; returns the file position at the end of the compilation top
(define (out-compilation-top shared-obj-pos shared-obj-unsee counting? outp) (define (out-compilation-top shared-obj-pos shared-obj-pos-any counting? outp)
(define ct (define ct
(match top (match top
[(compilation-top max-let-depth prefix form) [(compilation-top max-let-depth prefix form)
(list* max-let-depth prefix (protect-quote form))])) (list* max-let-depth prefix (protect-quote form))]))
(out-anything ct (make-out outp shared-obj-pos shared-obj-unsee counting? (out-anything ct (make-out outp shared-obj-pos shared-obj-pos-any counting?
stx-objs wraps hash-consed)) stx-objs wraps hash-consed hash-consed-results))
(file-position outp)) (file-position outp))
; -> vector ; -> vector
@ -172,16 +173,12 @@
(define (encounter! v) (define (encounter! v)
(hash-update! encountered v add1 0) (hash-update! encountered v add1 0)
#f) #f)
(define (unencounter! v)
(define how-many-encounters (hash-ref encountered v))
(when (= how-many-encounters 1)
(hash-set! encountered v 0)))
(define (shared-obj-pos v #:error? [error? #f]) (define (shared-obj-pos v #:error? [error? #f])
(hash-ref shared v (hash-ref shared v
(if error? (if error?
(λ () (error 'symref "~e not in symbol table" v)) (λ () (error 'symref "~e not in symbol table" v))
#f))) #f)))
(define (share! v) ; XXX this doesn't always set something, probably should be refactored (define (share! v)
(or (shared-obj-pos v) (or (shared-obj-pos v)
(let ([pos (add1 (hash-count shared))]) (let ([pos (add1 (hash-count shared))])
(hash-set! shared v pos) (hash-set! shared v pos)
@ -203,8 +200,7 @@
(share! v)] (share! v)]
[else [else
(encounter! v)])) (encounter! v)]))
(λ (v) (lambda (v) #f)
(unencounter! v))
#t #t
(open-output-nowhere)) (open-output-nowhere))
@ -233,14 +229,14 @@
[i (in-naturals)]) [i (in-naturals)])
(begin0 (begin0
(file-position outp) (file-position outp)
(out-anything v (make-out outp (shared-obj-pos/modulo-v v) void #f (out-anything v (make-out outp (shared-obj-pos/modulo-v v) shared-obj-pos #f
stx-objs wraps hash-consed)))) stx-objs wraps hash-consed hash-consed-results))))
(file-position outp))) (file-position outp)))
; Calculate file positions ; Calculate file positions
(define counting-port (open-output-nowhere)) (define counting-port (open-output-nowhere))
(define-values (offsets post-shared) (out-symbol-table symbol-table counting-port)) (define-values (offsets post-shared) (out-symbol-table symbol-table counting-port))
(define all-forms-length (out-compilation-top shared-obj-pos void #f counting-port)) (define all-forms-length (out-compilation-top shared-obj-pos shared-obj-pos #f counting-port))
; Write the compiled form header ; Write the compiled form header
(write-bytes #"#~" outp) (write-bytes #"#~" outp)
@ -268,7 +264,7 @@
(write-bytes (int->bytes all-forms-length) outp) (write-bytes (int->bytes all-forms-length) outp)
; Actually write the zo ; Actually write the zo
(out-symbol-table symbol-table outp) (out-symbol-table symbol-table outp)
(out-compilation-top shared-obj-pos void #f outp) (out-compilation-top shared-obj-pos shared-obj-pos #f outp)
(void)) (void))
;; ---------------------------------------- ;; ----------------------------------------
@ -341,7 +337,7 @@
CPT_MODULE_VAR CPT_MODULE_VAR
CPT_PATH CPT_PATH
CPT_CLOSURE CPT_CLOSURE
CPT_DELAY_REF ; XXX unused, but appears to be same as CPT_SYMREF CPT_DELAY_REF ; XXX should be used to delay loading of syntax objects and lambda bodies
CPT_PREFAB CPT_PREFAB
CPT_LET_ONE_UNUSED CPT_LET_ONE_UNUSED
CPT_SCOPE CPT_SCOPE
@ -393,22 +389,21 @@
(define-struct protected-symref (val)) (define-struct protected-symref (val))
(define (encode-stx-obj w wraps-ht) (define (encode-stx-obj w out)
(match w (match w
[(struct stx-obj (datum wraps tamper-status)) [(struct stx-obj (datum wraps tamper-status))
(let* ([enc-datum (let* ([enc-datum
(match datum (match datum
[(cons a b) [(cons a b)
(let ([p (cons (encode-stx-obj a wraps-ht) (let ([p (cons (encode-stx-obj a out)
(let bloop ([b b]) (let bloop ([b b])
(match b (match b
['() null] ['() null]
[(cons b1 b2) [(cons b1 b2)
(cons (encode-stx-obj b1 wraps-ht) (cons (encode-stx-obj b1 out)
(bloop b2))] (bloop b2))]
[else [else
(encode-stx-obj b wraps-ht)])))] (encode-stx-obj b out)])))]
; XXX Cylic list error possible
[len (let loop ([datum datum][len 0]) [len (let loop ([datum datum][len 0])
(cond (cond
[(null? datum) #f] [(null? datum) #f]
@ -420,32 +415,69 @@
(cons len p) (cons len p)
p))] p))]
[(box x) [(box x)
(box (encode-stx-obj x wraps-ht))] (box (encode-stx-obj x out))]
[(? vector? v) [(? vector? v)
(vector-map (lambda (e) (encode-stx-obj e wraps-ht)) v)] (vector-map (lambda (e) (encode-stx-obj e out)) v)]
[(? prefab-struct-key) [(? prefab-struct-key)
(define l (vector->list (struct->vector datum))) (define l (vector->list (struct->vector datum)))
(apply (apply
make-prefab-struct make-prefab-struct
(car l) (car l)
(map (lambda (e) (encode-stx-obj e wraps-ht)) (cdr l)))] (map (lambda (e) (encode-stx-obj e out)) (cdr l)))]
[_ datum])] [_ datum])]
[p (cons enc-datum [p (cons enc-datum
(encode-wrap wraps wraps-ht))]) (share-everywhere (encode-wrap wraps (out-wraps out)) out))])
(case tamper-status (case tamper-status
[(clean) p] [(clean) p]
[(tainted) (vector p)] [(tainted) (vector p)]
[(armed) (vector p #f)]))])) [(armed) (vector p #f)]))]))
(define-struct out (s shared-index shared-unsee counting? stx-objs wraps hash-consed)) (define-struct out (s
;; The output port for writing bytecode.
shared-index
;; Takes a value and reports/record sharing.
;; On the first pass, the number of times this function is
;; called for a value determines whether sharing is needed
;; for the value. That sharing is reported on later passes
;; by returning a number (a slot in "symbol" table) instead
;; of #f. On the symbol-table filling pass, the first call
;; produces #f so that a value is written into the table.
shared-index-any
;; Like `shared-index`, but doesn't record any sharing or
;; produce #f for the immediate value of a symbol table.
counting?
;; Set to #t for the first (sharing-finding pass), #f
;; otherwise.
stx-objs
;; Hash table from syntax objects to encoded forms; set on
;; first pass and encoding are retrieved on following passes.
wraps
;; Hash table from syntax-object wraps to encodings; also
;; set on first pass and used on later passes.
hash-consed
;; Table of hash-consed parts of wrap encodings. This table
;; is `equal?`-based, but with a wrapper to compare self
;; modidxs with `eq?`.
hash-consed-results
;; An `eq?`-based table of hash-cons results. Any of these
;; values that are shared need to be written with CPT_SHARED
;; so graph structure can be managed.
))
(define (out-shared v out k) (define (out-shared v out k)
(if (shareable? v) (if (shareable? v)
(let ([v ((out-shared-index out) v)]) (let ([n ((out-shared-index out) v)])
(if v (if n
(begin (begin
(out-byte CPT_SYMREF out) (out-byte CPT_SYMREF out)
(out-number v out)) (out-number n out))
(k))) (let ([sharepoint? (hash-ref (out-hash-consed-results out) v #f)])
(when sharepoint?
(let ([n2 ((out-shared-index-any out) v)])
(when n2
(out-byte CPT_SHARED out)
(out-number n2 out))))
(k))))
(k))) (k)))
(define (out-byte v out) (define (out-byte v out)
@ -534,7 +566,7 @@
[(? char?) [(? char?)
(out-byte CPT_CHAR out) (out-byte CPT_CHAR out)
(out-number (char->integer v) out)] (out-number (char->integer v) out)]
[(? maybe-same-as-fixnum?) ;XXX not sure if it's okay to use fixnum? instead of exact range check [(? maybe-same-as-fixnum?)
(if (and (v . >= . 0) (if (and (v . >= . 0)
(v . < . (- CPT_SMALL_NUMBER_END CPT_SMALL_NUMBER_START))) (v . < . (- CPT_SMALL_NUMBER_END CPT_SMALL_NUMBER_START)))
(out-byte (+ CPT_SMALL_NUMBER_START v) out) (out-byte (+ CPT_SMALL_NUMBER_START v) out)
@ -880,6 +912,7 @@
(for ([n (in-range (sub1 len) -1 -1)]) (for ([n (in-range (sub1 len) -1 -1)])
(out-number (vector-ref vec n) out)))] (out-number (vector-ref vec n) out)))]
[(? module-path-index?) [(? module-path-index?)
;; XXX should add interning of module path indices
(out-byte CPT_MODULE_INDEX out) (out-byte CPT_MODULE_INDEX out)
(let-values ([(name base) (module-path-index-split v)]) (let-values ([(name base) (module-path-index-split v)])
(out-anything name out) (out-anything name out)
@ -898,7 +931,7 @@
(out-number relative-id out) (out-number relative-id out)
(out-anything (share-everywhere content out) out)] (out-anything (share-everywhere content out) out)]
[(? stx-obj?) [(? stx-obj?)
(out-anything (share-everywhere (lookup-encoded-stx-obj v out) out) out)] (out-anything (lookup-encoded-stx-obj v out) out)]
[(? prefab-struct-key) [(? prefab-struct-key)
(define pre-v (struct->vector v)) (define pre-v (struct->vector v))
(vector-set! pre-v 0 (prefab-struct-key v)) (vector-set! pre-v 0 (prefab-struct-key v))
@ -1052,7 +1085,7 @@
(define (lookup-encoded-stx-obj w out) (define (lookup-encoded-stx-obj w out)
(hash-ref! (out-stx-objs out) w (hash-ref! (out-stx-objs out) w
(λ () (λ ()
(encode-stx-obj w (out-wraps out))))) (encode-stx-obj w out))))
(define (pack-binding-names binding-names) (define (pack-binding-names binding-names)
(define (ht-to-vector ht) (define (ht-to-vector ht)
@ -1187,21 +1220,35 @@
[(box? a) [(box? a)
(and (box? b) (and (box? b)
(simple-equal? (unbox a) (unbox b)))] (simple-equal? (unbox a) (unbox b)))]
[(module-path-index? a)
(and (module-path-index? b)
(let-values ([(a-name a-base) (module-path-index-split a)]
[(b-name b-base) (module-path-index-split b)])
(and a-name
a-base
(simple-equal? a-name b-name)
(simple-equal? a-base b-base))))]
[else #f])) [else #f]))
(define (share-everywhere v out) (define (share-everywhere v out)
(define (register r)
(hash-set! (out-hash-consed-results out) r #t)
r)
(hash-ref! (out-hash-consed out) (hash-ref! (out-hash-consed out)
(modidx-must-be-eq v) (modidx-must-be-eq v)
(lambda () (lambda ()
(cond (cond
[(pair? v) [(pair? v)
(register
(cons (share-everywhere (car v) out) (cons (share-everywhere (car v) out)
(share-everywhere (cdr v) out))] (share-everywhere (cdr v) out)))]
[(vector? v) [(vector? v)
(register
(for/vector #:length (vector-length v) ([e (in-vector v)]) (for/vector #:length (vector-length v) ([e (in-vector v)])
(share-everywhere e out))] (share-everywhere e out)))]
[(box? v) [(box? v)
(box (share-everywhere (unbox v) out))] (register
(box (share-everywhere (unbox v) out)))]
[else v])))) [else v]))))
;; ---------------------------------------- ;; ----------------------------------------

View File

@ -973,7 +973,6 @@
(vector-ref (cport-symtab cp) i)) (vector-ref (cport-symtab cp) i))
(define (read-cyclic cp i who [wrap values]) (define (read-cyclic cp i who [wrap values])
(define v (symtab-lookup cp i))
(define ph (make-placeholder (not-ready))) (define ph (make-placeholder (not-ready)))
(symtab-write! cp i ph) (symtab-write! cp i ph)
(define r (wrap (read-compact cp))) (define r (wrap (read-compact cp)))