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:
parent
d652ea0d52
commit
490b10483a
|
@ -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
|
||||||
|
|
|
@ -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]))))
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
|
|
|
@ -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)))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user