1049 lines
38 KiB
Racket
1049 lines
38 KiB
Racket
#lang scheme/base
|
|
(require compiler/zo-structs
|
|
unstable/byte-counting-port
|
|
scheme/match
|
|
scheme/contract
|
|
scheme/local
|
|
scheme/list
|
|
scheme/dict)
|
|
|
|
(provide/contract
|
|
[zo-marshal (compilation-top? . -> . bytes?)]
|
|
[zo-marshal-to (compilation-top? output-port? . -> . void?)])
|
|
|
|
#| Unresolved Issues
|
|
|
|
Less sharing occurs than in the C implementation, creating much larger files
|
|
|
|
protect-quote caused some things to be sent to write. But there are some things (like paths) that can be read and passed to protect-quote that cannot be 'read' in after 'write', so we turned it off
|
|
|#
|
|
|
|
(define current-wrapped-ht (make-parameter #f))
|
|
(define (zo-marshal top)
|
|
(define bs (open-output-bytes))
|
|
(zo-marshal-to top bs)
|
|
(get-output-bytes bs))
|
|
|
|
(define (zo-marshal-to top outp)
|
|
(match top
|
|
[(struct compilation-top (max-let-depth prefix form))
|
|
(define encountered (make-hasheq))
|
|
(define shared (make-hasheq))
|
|
(define wrapped (make-hasheq))
|
|
(define (visit v)
|
|
(if (hash-ref shared v #f)
|
|
#f
|
|
(if (hash-ref encountered v #f)
|
|
(begin
|
|
(hash-set! shared v (add1 (hash-count shared)))
|
|
#f)
|
|
(begin
|
|
(hash-set! encountered v #t)
|
|
(when (closure? v)
|
|
(hash-set! shared v (add1 (hash-count shared))))
|
|
#t))))
|
|
(define (v-skipping v)
|
|
(define skip? #t)
|
|
(lambda (v2)
|
|
(if (and skip? (eq? v v2))
|
|
(begin
|
|
(set! skip? #f)
|
|
#f)
|
|
(hash-ref shared v2 #f))))
|
|
(parameterize ([current-wrapped-ht wrapped])
|
|
(traverse-prefix prefix visit)
|
|
(traverse-form form visit))
|
|
(local [(define in-order-shareds
|
|
(sort (hash-map shared (lambda (k v) (cons v k)))
|
|
<
|
|
#:key car))
|
|
(define (write-all outp)
|
|
(define offsets
|
|
(for/list ([k*v (in-list in-order-shareds)])
|
|
(define v (cdr k*v))
|
|
(begin0
|
|
(file-position outp)
|
|
(out-anything v (make-out outp (v-skipping v) wrapped)))))
|
|
(define post-shared (file-position outp))
|
|
(out-data (list* max-let-depth prefix (protect-quote form))
|
|
(make-out outp (lambda (v) (hash-ref shared v #f)) wrapped))
|
|
(values offsets post-shared (file-position outp)))
|
|
(define counting-p (make-byte-counting-port))
|
|
(define-values (offsets post-shared all-forms-length)
|
|
(write-all counting-p))
|
|
(define all-short? (post-shared . < . #xFFFF))
|
|
(define version-bs (string->bytes/latin-1 (version)))]
|
|
(write-bytes #"#~" outp)
|
|
(write-bytes (bytes (bytes-length version-bs)) outp)
|
|
(write-bytes version-bs outp)
|
|
(write-bytes (int->bytes (add1 (hash-count shared))) outp)
|
|
(write-bytes (bytes (if all-short? 1 0)) outp)
|
|
(for ([o (in-list offsets)])
|
|
(write-bytes (integer->integer-bytes o (if all-short? 2 4) #f #f) outp))
|
|
(write-bytes (int->bytes post-shared) outp)
|
|
(write-bytes (int->bytes all-forms-length) outp)
|
|
(write-all outp)
|
|
(void))]))
|
|
|
|
;; ----------------------------------------
|
|
|
|
(define (traverse-prefix a-prefix visit)
|
|
(match a-prefix
|
|
[(struct prefix (num-lifts toplevels stxs))
|
|
(for-each (lambda (stx) (traverse-toplevel stx visit)) toplevels)
|
|
(for-each (lambda (stx) (traverse-stx stx visit)) stxs)]))
|
|
|
|
(define (traverse-module mod-form visit)
|
|
(match mod-form
|
|
[(struct mod (name srcname self-modidx prefix provides requires body syntax-body unexported
|
|
max-let-depth dummy lang-info internal-context))
|
|
(traverse-data name visit)
|
|
(traverse-data srcname visit)
|
|
(traverse-data self-modidx visit)
|
|
(traverse-prefix prefix visit)
|
|
(for-each (lambda (f) (map (lambda (v) (traverse-data v visit)) (cdr f))) requires)
|
|
(for-each (lambda (f) (traverse-form f visit)) body)
|
|
(for-each (lambda (f) (traverse-form f visit)) syntax-body)
|
|
(traverse-data lang-info visit)
|
|
(traverse-data internal-context visit)]))
|
|
|
|
(define (traverse-toplevel tl visit)
|
|
(match tl
|
|
[#f (void)]
|
|
[(? symbol?) (traverse-data tl visit)]
|
|
[(struct global-bucket (name))
|
|
(void)]
|
|
[(struct module-variable (modidx sym pos phase))
|
|
(visit tl)
|
|
(let-values ([(p b) (module-path-index-split modidx)])
|
|
(if (symbol? p)
|
|
(traverse-data p visit)
|
|
(traverse-data modidx visit)))
|
|
(traverse-data sym visit)]))
|
|
|
|
(define (traverse-wrapped w visit)
|
|
(define ew (hash-ref! (current-wrapped-ht) w (lambda () (encode-wrapped w))))
|
|
(traverse-data ew visit))
|
|
|
|
(define (traverse-stx s visit)
|
|
(when s
|
|
(traverse-wrapped (stx-encoded s) visit)))
|
|
|
|
|
|
(define (traverse-form form visit)
|
|
(match form
|
|
[(? mod?)
|
|
(traverse-module form visit)]
|
|
[(struct def-values (ids rhs))
|
|
(traverse-expr rhs visit)]
|
|
[(struct def-syntaxes (ids rhs prefix max-let-depth))
|
|
(traverse-prefix prefix visit)
|
|
(traverse-expr rhs visit)]
|
|
[(struct def-for-syntax (ids rhs prefix max-let-depth))
|
|
(traverse-prefix prefix visit)
|
|
(traverse-expr rhs visit)]
|
|
[(struct seq (forms))
|
|
(for-each (lambda (f) (traverse-form f visit)) forms)]
|
|
[(struct splice (forms))
|
|
(for-each (lambda (f) (traverse-form f visit)) forms)]
|
|
[else
|
|
(traverse-expr form visit)]))
|
|
|
|
(define (traverse-expr expr visit)
|
|
(match expr
|
|
[(struct toplevel (depth pos const? ready?))
|
|
(void)]
|
|
[(struct topsyntax (depth pos midpt))
|
|
(void)]
|
|
[(struct primval (id))
|
|
(void)]
|
|
[(struct assign (id rhs undef-ok?))
|
|
(traverse-expr rhs visit)]
|
|
[(struct localref (unbox? offset clear? other-clears? flonum?))
|
|
(void)]
|
|
[(? lam?)
|
|
(traverse-lam expr visit)]
|
|
[(struct case-lam (name lams))
|
|
(traverse-data name visit)
|
|
(for-each (lambda (lam) (traverse-lam lam visit)) lams)]
|
|
[(struct let-one (rhs body flonum? unused?))
|
|
(traverse-expr rhs visit)
|
|
(traverse-expr body visit)]
|
|
[(struct let-void (count boxes? body))
|
|
(traverse-expr body visit)]
|
|
[(struct let-rec (procs body))
|
|
(for-each (lambda (lam) (traverse-lam lam visit)) procs)
|
|
(traverse-expr body visit)]
|
|
[(struct install-value (count pos boxes? rhs body))
|
|
(traverse-expr rhs visit)
|
|
(traverse-expr body visit)]
|
|
[(struct boxenv (pos body))
|
|
(traverse-expr body visit)]
|
|
[(struct branch (test then else))
|
|
(traverse-expr test visit)
|
|
(traverse-expr then visit)
|
|
(traverse-expr else visit)]
|
|
[(struct application (rator rands))
|
|
(traverse-expr rator visit)
|
|
(for-each (lambda (rand) (traverse-expr rand visit)) rands)]
|
|
[(struct apply-values (proc args-expr))
|
|
(traverse-expr proc visit)
|
|
(traverse-expr args-expr visit)]
|
|
[(struct seq (exprs))
|
|
(for-each (lambda (expr) (traverse-form expr visit)) exprs)]
|
|
[(struct beg0 (exprs))
|
|
(for-each (lambda (expr) (traverse-expr expr visit)) exprs)]
|
|
[(struct with-cont-mark (key val body))
|
|
(traverse-expr key visit)
|
|
(traverse-expr val visit)
|
|
(traverse-expr body visit)]
|
|
[(struct closure (lam gen-id))
|
|
(traverse-lam expr visit)]
|
|
[(struct indirect (val))
|
|
(traverse-expr val visit)]
|
|
[else (traverse-data expr visit)]))
|
|
|
|
(define (traverse-data expr visit)
|
|
(cond
|
|
[(or (symbol? expr)
|
|
(keyword? expr)
|
|
(string? expr)
|
|
(bytes? expr)
|
|
(path? expr))
|
|
(visit expr)]
|
|
[(module-path-index? expr)
|
|
(visit expr)
|
|
(let-values ([(name base) (module-path-index-split expr)])
|
|
(traverse-data name visit)
|
|
(traverse-data base visit))]
|
|
[(pair? expr)
|
|
(traverse-data (car expr) visit)
|
|
(traverse-data (cdr expr) visit)]
|
|
[(vector? expr)
|
|
(for ([e (in-vector expr)])
|
|
(traverse-data e visit))]
|
|
[(box? expr)
|
|
(traverse-data (unbox expr) visit)]
|
|
[(stx? expr)
|
|
(traverse-stx expr visit)]
|
|
[(wrapped? expr)
|
|
(traverse-wrapped expr visit)]
|
|
[else
|
|
(void)]))
|
|
|
|
(define (traverse-lam expr visit)
|
|
(match expr
|
|
[(struct indirect (val)) (traverse-lam val visit)]
|
|
[(struct closure (lam gen-id))
|
|
(when (visit expr)
|
|
(traverse-lam lam visit))]
|
|
[(struct lam (name flags num-params param-types rest? closure-map closure-types max-let-depth body))
|
|
(traverse-data name visit)
|
|
(traverse-expr body visit)]))
|
|
|
|
;; ----------------------------------------
|
|
|
|
(define toplevel-type-num 0)
|
|
(define syntax-type-num 3)
|
|
(define sequence-type-num 7)
|
|
(define unclosed-procedure-type-num 9)
|
|
(define let-value-type-num 10)
|
|
(define let-void-type-num 11)
|
|
(define letrec-type-num 12)
|
|
(define wcm-type-num 14)
|
|
(define quote-syntax-type-num 15)
|
|
(define variable-type-num 24)
|
|
(define top-type-num 89)
|
|
(define case-lambda-sequence-type-num 99)
|
|
(define begin0-sequence-type-num 100)
|
|
(define module-type-num 103)
|
|
(define prefix-type-num 105)
|
|
|
|
(define-syntax define-enum
|
|
(syntax-rules ()
|
|
[(_ n) (begin)]
|
|
[(_ n id . rest)
|
|
(begin
|
|
(define id n)
|
|
(define-enum (add1 n) . rest))]))
|
|
|
|
(define-enum
|
|
0
|
|
CPT_ESCAPE
|
|
CPT_SYMBOL
|
|
CPT_SYMREF
|
|
CPT_WEIRD_SYMBOL
|
|
CPT_KEYWORD
|
|
CPT_BYTE_STRING
|
|
CPT_CHAR_STRING
|
|
CPT_CHAR
|
|
CPT_INT
|
|
CPT_NULL
|
|
CPT_TRUE
|
|
CPT_FALSE
|
|
CPT_VOID
|
|
CPT_BOX
|
|
CPT_PAIR
|
|
CPT_LIST
|
|
CPT_VECTOR
|
|
CPT_HASH_TABLE
|
|
CPT_STX
|
|
CPT_LET_ONE_FLONUM
|
|
CPT_MARSHALLED
|
|
CPT_QUOTE
|
|
CPT_REFERENCE
|
|
CPT_LOCAL
|
|
CPT_LOCAL_UNBOX
|
|
CPT_SVECTOR
|
|
CPT_APPLICATION
|
|
CPT_LET_ONE
|
|
CPT_BRANCH
|
|
CPT_MODULE_INDEX
|
|
CPT_MODULE_VAR
|
|
CPT_PATH
|
|
CPT_CLOSURE
|
|
CPT_DELAY_REF
|
|
CPT_PREFAB
|
|
CPT_LET_ONE_UNUSED)
|
|
|
|
(define-enum
|
|
0
|
|
DEFINE_VALUES_EXPD
|
|
DEFINE_SYNTAX_EXPD
|
|
SET_EXPD
|
|
CASE_LAMBDA_EXPD
|
|
BEGIN0_EXPD
|
|
BOXENV_EXPD
|
|
MODULE_EXPD
|
|
REQUIRE_EXPD
|
|
DEFINE_FOR_SYNTAX_EXPD
|
|
REF_EXPD
|
|
APPVALS_EXPD
|
|
SPLICE_EXPD)
|
|
|
|
(define CPT_SMALL_NUMBER_START 36)
|
|
(define CPT_SMALL_NUMBER_END 60)
|
|
|
|
(define CPT_SMALL_SYMBOL_START 60)
|
|
(define CPT_SMALL_SYMBOL_END 80)
|
|
|
|
(define CPT_SMALL_MARSHALLED_START 80)
|
|
(define CPT_SMALL_MARSHALLED_END 92)
|
|
|
|
(define CPT_SMALL_LIST_MAX 65)
|
|
(define CPT_SMALL_PROPER_LIST_START 92)
|
|
(define CPT_SMALL_PROPER_LIST_END (+ CPT_SMALL_PROPER_LIST_START CPT_SMALL_LIST_MAX))
|
|
|
|
(define CPT_SMALL_LIST_START CPT_SMALL_PROPER_LIST_END)
|
|
(define CPT_SMALL_LIST_END 192)
|
|
|
|
(define CPT_SMALL_LOCAL_START 192)
|
|
(define CPT_SMALL_LOCAL_END 207)
|
|
(define CPT_SMALL_LOCAL_UNBOX_START 207)
|
|
(define CPT_SMALL_LOCAL_UNBOX_END 222)
|
|
|
|
(define CPT_SMALL_SVECTOR_START 222)
|
|
(define CPT_SMALL_SVECTOR_END 247)
|
|
|
|
(define CPT_SMALL_APPLICATION_START 247)
|
|
(define CPT_SMALL_APPLICATION_END 255)
|
|
|
|
(define CLOS_HAS_REST 1)
|
|
(define CLOS_HAS_REF_ARGS 2)
|
|
(define CLOS_PRESERVES_MARKS 4)
|
|
(define CLOS_IS_METHOD 16)
|
|
(define CLOS_SINGLE_RESULT 32)
|
|
|
|
(define BITS_PER_MZSHORT 32)
|
|
|
|
(define *dummy* #f)
|
|
|
|
(define (int->bytes x)
|
|
(integer->integer-bytes x
|
|
4
|
|
#f
|
|
#f))
|
|
|
|
(define-struct case-seq (name lams))
|
|
(define-struct (seq0 seq) ())
|
|
|
|
(define-struct out (s shared-index encoded-wraps))
|
|
(define (out-shared v out k)
|
|
(let ([v ((out-shared-index out) v)])
|
|
(if v
|
|
(begin
|
|
(out-byte CPT_SYMREF out)
|
|
(out-number v out))
|
|
(k))))
|
|
(define (display-byte b)
|
|
(if (b . <= . #xf)
|
|
(printf "0~x" b)
|
|
(printf "~x" b)))
|
|
|
|
(define (out-byte v out)
|
|
(write-byte v (out-s out)))
|
|
|
|
(define (out-bytes b out)
|
|
(write-bytes b (out-s out)))
|
|
|
|
(define (out-number n out)
|
|
(cond
|
|
[(n . < . 0)
|
|
(if (n . > . -32)
|
|
(out-byte (bitwise-ior #xC0 (- n)) out)
|
|
(begin
|
|
(out-byte #xE0 out)
|
|
(out-bytes (int->bytes (- n)) out)))]
|
|
[(n . < . 128)
|
|
(out-byte n out)]
|
|
[(n . < . #x4000)
|
|
(out-byte (bitwise-ior #x80 (bitwise-and n #x3F)) out)
|
|
(out-byte (bitwise-and #xFF (arithmetic-shift n -6)) out)]
|
|
[else
|
|
(out-byte #xF0 out)
|
|
(out-bytes (int->bytes n) out)]))
|
|
|
|
(define (out-syntax key val out)
|
|
(out-marshaled syntax-type-num (list* key val) out))
|
|
|
|
(define (out-marshaled type-num val out)
|
|
(if (type-num . < . (- CPT_SMALL_MARSHALLED_END CPT_SMALL_MARSHALLED_START))
|
|
(out-byte (+ CPT_SMALL_MARSHALLED_START type-num) out)
|
|
(begin
|
|
(out-byte CPT_MARSHALLED out)
|
|
(out-number type-num out)))
|
|
(out-data val out))
|
|
|
|
(define (out-anything v out)
|
|
(cond
|
|
[(module-variable? v)
|
|
(out-toplevel v out)]
|
|
[(closure? v)
|
|
(out-expr v out)]
|
|
[else
|
|
(out-data v out)]))
|
|
|
|
(define (out-prefix a-prefix out)
|
|
(match a-prefix
|
|
[(struct prefix (num-lifts toplevels stxs))
|
|
(out-marshaled
|
|
prefix-type-num
|
|
(cons num-lifts
|
|
(cons (list->vector toplevels)
|
|
(list->vector stxs)))
|
|
out)]))
|
|
|
|
(define-struct module-decl (content))
|
|
|
|
(define (out-module mod-form out)
|
|
(match mod-form
|
|
[(struct mod (name srcname self-modidx prefix provides requires body syntax-body unexported
|
|
max-let-depth dummy lang-info internal-context))
|
|
(out-syntax MODULE_EXPD
|
|
(let* ([lookup-req (lambda (phase)
|
|
(let ([a (assq phase requires)])
|
|
(if a
|
|
(cdr a)
|
|
null)))]
|
|
[other-requires (filter (lambda (l)
|
|
(not (memq (car l) '(#f -1 0 1))))
|
|
requires)]
|
|
[extract-protects
|
|
(lambda (phase)
|
|
(let ([a (assq phase provides)])
|
|
(and a
|
|
(let ([p (map provided-protected? (append (cadr a)
|
|
(caddr a)))])
|
|
(if (ormap values p)
|
|
(list->vector p)
|
|
#f)))))]
|
|
[list->vector/#f (lambda (default l)
|
|
(if (andmap (lambda (x) (equal? x default)) l)
|
|
#f
|
|
(list->vector l)))]
|
|
[l
|
|
(let loop ([l other-requires])
|
|
(match l
|
|
[(list)
|
|
empty]
|
|
[(list-rest (cons phase reqs) rst)
|
|
(list* phase reqs (loop rst))]))]
|
|
[l (cons (length other-requires) l)]
|
|
[l (cons (lookup-req #f) l)] ; dt-requires
|
|
[l (cons (lookup-req -1) l)] ; tt-requires
|
|
[l (cons (lookup-req 1) l)] ; et-requires
|
|
[l (cons (lookup-req 0) l)] ; requires
|
|
[l (cons (list->vector body) l)]
|
|
[l (cons (list->vector syntax-body) l)]
|
|
[l (append (apply
|
|
append
|
|
(map (lambda (l)
|
|
(let ([phase (car l)]
|
|
[all (append (cadr l) (caddr l))])
|
|
(list phase
|
|
(list->vector/#f #f (map provided-insp all))
|
|
(list->vector/#f 0 (map (lambda (p) (= 1 (provided-src-phase p)))
|
|
all))
|
|
(list->vector/#f #f (map (lambda (p)
|
|
(if (eq? (provided-nom-src p)
|
|
(provided-src p))
|
|
#f ; #f means "same as src"
|
|
(provided-nom-src p)))
|
|
all))
|
|
(list->vector (map provided-src-name all))
|
|
(list->vector (map provided-src all))
|
|
(list->vector (map provided-name all))
|
|
(length (cadr l))
|
|
(length all))))
|
|
provides))
|
|
l)]
|
|
[l (cons (length provides) l)] ; number of provide sets
|
|
[l (cons (extract-protects 0) l)] ; protects
|
|
[l (cons (extract-protects 1) l)] ; et protects
|
|
[l (list* (list->vector (car unexported)) (length (car unexported)) l)] ; indirect-provides
|
|
[l (list* (list->vector (cadr unexported)) (length (cadr unexported)) l)] ; indirect-syntax-provides
|
|
[l (list* (list->vector (caddr unexported)) (length (caddr unexported)) l)] ; indirect-et-provides
|
|
[l (cons prefix l)]
|
|
[l (cons dummy l)]
|
|
[l (cons max-let-depth l)]
|
|
[l (cons internal-context l)] ; module->namespace syntax
|
|
[l (list* #f #f l)] ; obsolete `functional?' info
|
|
[l (cons lang-info l)] ; lang-info
|
|
[l (cons self-modidx l)]
|
|
[l (cons srcname l)]
|
|
[l (cons name l)])
|
|
(make-module-decl l))
|
|
out)]))
|
|
|
|
(define (out-toplevel tl out)
|
|
(match tl
|
|
[#f (out-data tl out)]
|
|
[(? symbol?) (out-data tl out)]
|
|
[(struct global-bucket (name))
|
|
(out-marshaled variable-type-num name out)]
|
|
[(struct module-variable (modidx sym pos phase))
|
|
(out-shared
|
|
tl
|
|
out
|
|
(lambda ()
|
|
(out-byte CPT_MODULE_VAR out)
|
|
(out-data modidx out)
|
|
(out-data sym out)
|
|
(unless (zero? phase)
|
|
(out-number -2 out))
|
|
(out-number pos out)))]))
|
|
|
|
(define (encode-module-bindings module-bindings)
|
|
(define encode-nominal-path
|
|
(match-lambda
|
|
[(struct simple-nominal-path (value))
|
|
value]
|
|
[(struct imported-nominal-path (value import-phase))
|
|
(cons value import-phase)]
|
|
[(struct phased-nominal-path (value import-phase phase))
|
|
(cons value (cons import-phase phase))]))
|
|
(define encoded-bindings (make-vector (* (length module-bindings) 2)))
|
|
(for ([i (in-naturals)]
|
|
[(k v) (in-dict module-bindings)])
|
|
(vector-set! encoded-bindings (* i 2) k)
|
|
(vector-set! encoded-bindings (add1 (* i 2))
|
|
(match v
|
|
[(struct simple-module-binding (path))
|
|
path]
|
|
[(struct exported-module-binding (path export-name))
|
|
(cons path export-name)]
|
|
[(struct nominal-module-binding (path nominal-path))
|
|
(cons path (encode-nominal-path nominal-path))]
|
|
[(struct exported-nominal-module-binding (path export-name nominal-path nominal-export-name))
|
|
(list* path export-name (encode-nominal-path nominal-path) nominal-export-name)]
|
|
[(struct phased-module-binding (path phase export-name nominal-path nominal-export-name))
|
|
(list* path phase export-name (encode-nominal-path nominal-path) nominal-export-name)])))
|
|
encoded-bindings)
|
|
|
|
(define (encode-all-from-module all)
|
|
(match all
|
|
[(struct all-from-module (path phase src-phase exceptions prefix))
|
|
(if (and (empty? exceptions) (not prefix))
|
|
(list* path phase src-phase)
|
|
(list* path phase src-phase (append exceptions prefix)))]))
|
|
|
|
(define (encode-wraps wraps)
|
|
(for/list ([wrap (in-list wraps)])
|
|
(match wrap
|
|
[(struct phase-shift (amt src dest))
|
|
(box (vector amt src dest #f))]
|
|
[(struct module-rename (phase kind set-id unmarshals renames mark-renames plus-kern?))
|
|
(define encoded-kind (eq? kind 'marked))
|
|
(define encoded-unmarshals (map encode-all-from-module unmarshals))
|
|
(define encoded-renames (encode-module-bindings renames))
|
|
(define-values (maybe-unmarshals maybe-renames) (if (null? encoded-unmarshals)
|
|
(values encoded-renames mark-renames)
|
|
(values encoded-unmarshals (cons encoded-renames mark-renames))))
|
|
(define mod-rename (list* phase encoded-kind set-id maybe-unmarshals maybe-renames))
|
|
(if plus-kern?
|
|
(cons #t mod-rename)
|
|
mod-rename)]
|
|
[(struct lexical-rename (bool1 bool2 alist))
|
|
(define len (length alist))
|
|
(define vec (make-vector (+ (* 2 len) 2))) ; + 2 for booleans at the beginning
|
|
(vector-set! vec 0 bool1)
|
|
(vector-set! vec 1 bool2)
|
|
(for ([(k v) (in-dict alist)]
|
|
[i (in-naturals)])
|
|
(vector-set! vec (+ 2 i) k)
|
|
(vector-set! vec (+ 2 i len) v))
|
|
vec]
|
|
[(struct prune (syms))
|
|
(box syms)]
|
|
[(struct wrap-mark (val))
|
|
(list val)])))
|
|
|
|
(define (encode-wrapped w)
|
|
(match w
|
|
[(struct wrapped (datum wraps certs))
|
|
(vector
|
|
(cons
|
|
datum
|
|
(encode-wraps wraps))
|
|
certs)]))
|
|
|
|
(define (lookup-encoded-wrapped w out)
|
|
(hash-ref (out-encoded-wraps out) w))
|
|
|
|
(define (out-wrapped w out)
|
|
(out-data (lookup-encoded-wrapped w out) out))
|
|
|
|
(define (out-stx s out)
|
|
(out-shared s out
|
|
(lambda ()
|
|
(match s
|
|
[(struct stx (encoded))
|
|
(out-byte CPT_STX out)
|
|
(out-wrapped encoded out)]))))
|
|
|
|
(define (out-form form out)
|
|
(match form
|
|
[(? mod?)
|
|
(out-module form out)]
|
|
[(struct def-values (ids rhs))
|
|
(out-syntax DEFINE_VALUES_EXPD
|
|
(list->vector (cons rhs ids))
|
|
out)]
|
|
[(struct def-syntaxes (ids rhs prefix max-let-depth))
|
|
(out-syntax DEFINE_SYNTAX_EXPD
|
|
(list->vector (list* rhs
|
|
prefix
|
|
max-let-depth
|
|
*dummy*
|
|
ids))
|
|
out)]
|
|
[(struct def-for-syntax (ids rhs prefix max-let-depth))
|
|
(out-syntax DEFINE_FOR_SYNTAX_EXPD
|
|
(list->vector (list* rhs
|
|
prefix
|
|
max-let-depth
|
|
*dummy*
|
|
ids))
|
|
out)]
|
|
[(struct seq0 (forms))
|
|
(out-marshaled begin0-sequence-type-num (map protect-quote forms) out)]
|
|
[(struct seq (forms))
|
|
(out-marshaled sequence-type-num (map protect-quote forms) out)]
|
|
[(struct splice (forms))
|
|
(out-syntax SPLICE_EXPD (make-seq forms) out)]
|
|
[(struct req (reqs dummy))
|
|
(error "cannot handle top-level `require', yet")
|
|
(out-syntax REQUIRE_EXPD (cons dummy reqs) out)]
|
|
[else
|
|
(out-expr form out)]))
|
|
|
|
(define (out-expr expr out)
|
|
(match expr
|
|
[(struct toplevel (depth pos const? ready?))
|
|
(out-marshaled toplevel-type-num
|
|
(cons
|
|
depth
|
|
(if (or const? ready?)
|
|
(cons pos
|
|
(bitwise-ior
|
|
(if const? #x1 0)
|
|
(if ready? #x2 0)))
|
|
pos))
|
|
out)]
|
|
[(struct topsyntax (depth pos midpt))
|
|
(out-marshaled quote-syntax-type-num
|
|
(cons depth
|
|
(cons pos midpt))
|
|
out)]
|
|
[(struct primval (id))
|
|
(out-byte CPT_REFERENCE out)
|
|
(out-number id out)]
|
|
[(struct assign (id rhs undef-ok?))
|
|
(out-syntax SET_EXPD
|
|
(cons undef-ok? (cons id rhs))
|
|
out)]
|
|
[(struct localref (unbox? offset clear? other-clears? flonum?))
|
|
(if (and (not clear?) (not other-clears?) (not flonum?)
|
|
(offset . < . (- CPT_SMALL_LOCAL_END CPT_SMALL_LOCAL_START)))
|
|
(out-byte (+ (if unbox?
|
|
CPT_SMALL_LOCAL_UNBOX_START
|
|
CPT_SMALL_LOCAL_START)
|
|
offset)
|
|
out)
|
|
(begin
|
|
(out-byte (if unbox? CPT_LOCAL_UNBOX CPT_LOCAL) out)
|
|
(if (not (or clear? other-clears? flonum?))
|
|
(out-number offset out)
|
|
(begin
|
|
(out-number (- (add1 offset)) out)
|
|
(out-number (if clear?
|
|
#x1
|
|
(if other-clears?
|
|
#x2
|
|
(if flonum?
|
|
#x3
|
|
0)))
|
|
out)))))]
|
|
[(? lam?)
|
|
(out-lam expr out)]
|
|
[(struct case-lam (name lams))
|
|
(let ([seq (make-case-seq name lams)])
|
|
;; If all closures are empy, generate a case sequence directly
|
|
(if (andmap (lambda (lam)
|
|
(or (closure? lam)
|
|
(and (lam? lam)
|
|
(equal? (lam-closure-map lam) #()))))
|
|
lams)
|
|
(out-data seq out)
|
|
(out-syntax CASE_LAMBDA_EXPD
|
|
seq
|
|
out)))]
|
|
[(struct case-seq (name lams))
|
|
(out-marshaled case-lambda-sequence-type-num
|
|
(cons (or name null)
|
|
lams)
|
|
out)]
|
|
[(struct let-one (rhs body flonum? unused?))
|
|
(out-byte (cond
|
|
[flonum? CPT_LET_ONE_FLONUM]
|
|
[unused? CPT_LET_ONE_UNUSED]
|
|
[else CPT_LET_ONE])
|
|
out)
|
|
(out-expr (protect-quote rhs) out)
|
|
(out-expr (protect-quote body) out)]
|
|
[(struct let-void (count boxes? body))
|
|
(out-marshaled let-void-type-num
|
|
(list*
|
|
count
|
|
boxes?
|
|
(protect-quote body))
|
|
out)]
|
|
[(struct let-rec (procs body))
|
|
(out-marshaled letrec-type-num
|
|
(list*
|
|
(length procs)
|
|
(protect-quote body)
|
|
procs)
|
|
out)]
|
|
[(struct install-value (count pos boxes? rhs body))
|
|
(out-marshaled let-value-type-num
|
|
(list*
|
|
count
|
|
pos
|
|
boxes?
|
|
(protect-quote rhs)
|
|
(protect-quote body))
|
|
out)]
|
|
[(struct boxenv (pos body))
|
|
(out-syntax BOXENV_EXPD
|
|
(cons
|
|
pos
|
|
(protect-quote body))
|
|
out)]
|
|
[(struct branch (test then else))
|
|
(out-byte CPT_BRANCH out)
|
|
(out-expr (protect-quote test) out)
|
|
(out-expr (protect-quote then) out)
|
|
(out-expr (protect-quote else) out)]
|
|
[(struct application (rator rands))
|
|
(let ([len (length rands)])
|
|
(if (len . < . (- CPT_SMALL_APPLICATION_END CPT_SMALL_APPLICATION_START))
|
|
(out-byte (+ CPT_SMALL_APPLICATION_START (length rands)) out)
|
|
(begin
|
|
(out-byte CPT_APPLICATION out)
|
|
(out-number len out)))
|
|
(for-each (lambda (e) (out-expr (protect-quote e) out))
|
|
(cons rator rands)))]
|
|
[(struct apply-values (proc args-expr))
|
|
(out-syntax APPVALS_EXPD
|
|
(cons (protect-quote proc)
|
|
(protect-quote args-expr))
|
|
out)]
|
|
[(struct seq (exprs))
|
|
(out-form expr out)]
|
|
[(struct beg0 (exprs))
|
|
(out-syntax BEGIN0_EXPD
|
|
(make-seq0 exprs)
|
|
out)]
|
|
[(struct with-cont-mark (key val body))
|
|
(out-marshaled wcm-type-num
|
|
(list*
|
|
(protect-quote key)
|
|
(protect-quote val)
|
|
(protect-quote body))
|
|
out)]
|
|
[(struct closure (lam gen-id))
|
|
(out-lam expr out)]
|
|
[(struct indirect (val))
|
|
(out-expr val out)]
|
|
[(struct varref (expr))
|
|
(out-syntax REF_EXPD
|
|
expr
|
|
out)]
|
|
[else (out-value expr out)]))
|
|
|
|
(define (out-lam expr out)
|
|
(match expr
|
|
[(struct indirect (val)) (out-lam val out)]
|
|
[(struct closure (lam gen-id))
|
|
(out-shared
|
|
expr
|
|
out
|
|
(lambda ()
|
|
(out-byte CPT_CLOSURE out)
|
|
(out-number ((out-shared-index out) expr) out)
|
|
(out-lam lam out)))]
|
|
[(struct lam (name flags num-params param-types rest? closure-map closure-types max-let-depth body))
|
|
(let* ([l (protect-quote body)]
|
|
[any-refs? (or (ormap (lambda (t) (memq t '(ref flonum))) param-types)
|
|
(ormap (lambda (t) (memq t '(flonum))) closure-types))]
|
|
[num-all-params ((if rest? add1 values) num-params)]
|
|
[l (cons (make-svector (if any-refs?
|
|
(list->vector
|
|
(append
|
|
(vector->list closure-map)
|
|
(let* ([v (make-vector (ceiling
|
|
(/ (* 2 (+ num-params (vector-length closure-map)))
|
|
BITS_PER_MZSHORT)))]
|
|
[set-bit! (lambda (i bit)
|
|
(let ([pos (quotient (* 2 i) BITS_PER_MZSHORT)])
|
|
(vector-set! v pos
|
|
(bitwise-ior (vector-ref v pos)
|
|
(arithmetic-shift
|
|
bit
|
|
(modulo (* 2 i) BITS_PER_MZSHORT))))))])
|
|
(for ([t (in-list param-types)]
|
|
[i (in-naturals)])
|
|
(when (eq? t 'ref) (set-bit! i 1))
|
|
(when (eq? t 'flonum) (set-bit! i 2)))
|
|
(for ([t (in-list closure-types)]
|
|
[i (in-naturals num-all-params)])
|
|
(when (eq? t 'flonum) (set-bit! i 2)))
|
|
(vector->list v))))
|
|
closure-map))
|
|
l)]
|
|
[l (if any-refs?
|
|
(cons (vector-length closure-map) l)
|
|
l)])
|
|
(out-marshaled unclosed-procedure-type-num
|
|
(list*
|
|
(+ (if rest? CLOS_HAS_REST 0)
|
|
(if any-refs? CLOS_HAS_REF_ARGS 0)
|
|
(if (memq 'preserves-marks flags) CLOS_PRESERVES_MARKS 0)
|
|
(if (memq 'is-method flags) CLOS_IS_METHOD 0)
|
|
(if (memq 'single-result flags) CLOS_SINGLE_RESULT 0))
|
|
num-all-params
|
|
max-let-depth
|
|
name
|
|
l)
|
|
out))]))
|
|
|
|
(define (out-as-bytes expr ->bytes CPT len2 out #:before-length [before-length #f])
|
|
(out-shared expr out (lambda ()
|
|
(let ([s (->bytes expr)])
|
|
(out-byte CPT out)
|
|
(when before-length
|
|
(out-number before-length out))
|
|
(out-number (bytes-length s) out)
|
|
(when len2 (out-number len2 out))
|
|
(out-bytes s out)))))
|
|
|
|
(define (out-data expr out)
|
|
(cond
|
|
[(prefix? expr) (out-prefix expr out)]
|
|
[(global-bucket? expr) (out-toplevel expr out)]
|
|
[(module-variable? expr) (out-toplevel expr out)]
|
|
[else (out-form expr out)]))
|
|
|
|
(define (out-value expr out)
|
|
(cond
|
|
[(and (symbol? expr) (not (symbol-interned? expr)))
|
|
(out-as-bytes expr
|
|
#:before-length (if (symbol-unreadable? expr) 0 1)
|
|
(compose string->bytes/utf-8 symbol->string)
|
|
CPT_WEIRD_SYMBOL
|
|
#f
|
|
out)]
|
|
[(symbol? expr)
|
|
(out-shared expr out
|
|
(lambda ()
|
|
(define bs (string->bytes/utf-8 (symbol->string expr)))
|
|
(define len (bytes-length bs))
|
|
(if (len . < . (- CPT_SMALL_SYMBOL_END CPT_SMALL_SYMBOL_START))
|
|
(out-byte (+ CPT_SMALL_SYMBOL_START len) out)
|
|
(begin (out-byte CPT_SYMBOL out)
|
|
(out-number len out)))
|
|
(out-bytes bs out)))]
|
|
[(keyword? expr)
|
|
(out-as-bytes expr
|
|
(compose string->bytes/utf-8 keyword->string)
|
|
CPT_KEYWORD
|
|
#f
|
|
out)]
|
|
[(string? expr)
|
|
(out-as-bytes expr
|
|
string->bytes/utf-8
|
|
CPT_CHAR_STRING
|
|
(string-length expr)
|
|
out)]
|
|
[(bytes? expr)
|
|
(out-as-bytes expr
|
|
values
|
|
CPT_BYTE_STRING
|
|
#f
|
|
out)]
|
|
[(path? expr)
|
|
(out-as-bytes expr
|
|
path->bytes
|
|
CPT_PATH
|
|
#f
|
|
out)]
|
|
[(char? expr)
|
|
(out-byte CPT_CHAR out)
|
|
(out-number (char->integer expr) out)]
|
|
[(and (exact-integer? expr)
|
|
(and (expr . >= . -1073741824) (expr . <= . 1073741823)))
|
|
(if (and (expr . >= . 0)
|
|
(expr . < . (- CPT_SMALL_NUMBER_END CPT_SMALL_NUMBER_START)))
|
|
(out-byte (+ CPT_SMALL_NUMBER_START expr) out)
|
|
(begin
|
|
(out-byte CPT_INT out)
|
|
(out-number expr out)))]
|
|
[(null? expr)
|
|
(out-byte CPT_NULL out)]
|
|
[(eq? expr #t)
|
|
(out-byte CPT_TRUE out)]
|
|
[(eq? expr #f)
|
|
(out-byte CPT_FALSE out)]
|
|
[(void? expr)
|
|
(out-byte CPT_VOID out)]
|
|
[(box? expr)
|
|
(out-byte CPT_BOX out)
|
|
(out-data (unbox expr) out)]
|
|
[(pair? expr)
|
|
(local [(define seen? (make-hasheq)) ; XXX Maybe this should be global?
|
|
(define (list-length-before-cycle/improper-end l)
|
|
(if (hash-has-key? seen? l)
|
|
(begin (values 0 #f))
|
|
(begin (hash-set! seen? l #t)
|
|
(cond
|
|
[(null? l)
|
|
(values 0 #t)]
|
|
[(pair? l)
|
|
(let-values ([(len proper?)
|
|
(list-length-before-cycle/improper-end (cdr l))])
|
|
(values (add1 len) proper?))]
|
|
[else
|
|
(values 0 #f)]))))
|
|
(define-values (len proper?) (list-length-before-cycle/improper-end expr))
|
|
(define (print-contents-as-proper)
|
|
(for ([e (in-list expr)])
|
|
(out-data e out)))
|
|
(define (print-contents-as-improper)
|
|
(let loop ([l expr] [i len])
|
|
(cond
|
|
[(zero? i)
|
|
(out-data l out)]
|
|
[else
|
|
(out-data (car l) out)
|
|
(loop (cdr l) (sub1 i))])))]
|
|
(if proper?
|
|
(if (len . < . (- CPT_SMALL_PROPER_LIST_END CPT_SMALL_PROPER_LIST_START))
|
|
(begin (out-byte (+ CPT_SMALL_PROPER_LIST_START len) out)
|
|
(print-contents-as-proper))
|
|
(begin (out-byte CPT_LIST out)
|
|
(out-number len out)
|
|
(print-contents-as-proper)
|
|
(out-data null out)))
|
|
(if (len . < . (- CPT_SMALL_LIST_END CPT_SMALL_LIST_START))
|
|
(begin (out-byte (+ CPT_SMALL_LIST_START len) out)
|
|
(print-contents-as-improper))
|
|
(begin (out-byte CPT_LIST out)
|
|
(out-number len out)
|
|
(print-contents-as-improper)))))]
|
|
[(vector? expr)
|
|
(out-byte CPT_VECTOR out)
|
|
(out-number (vector-length expr) out)
|
|
(for ([v (in-vector expr)])
|
|
(out-data v out))]
|
|
[(hash? expr)
|
|
(out-byte CPT_HASH_TABLE out)
|
|
(out-number (cond
|
|
[(hash-eqv? expr) 2]
|
|
[(hash-eq? expr) 0]
|
|
[else 1])
|
|
out)
|
|
(out-number (hash-count expr) out)
|
|
(for ([(k v) (in-hash expr)])
|
|
(out-data k out)
|
|
(out-data v out))]
|
|
[(svector? expr)
|
|
(let* ([vec (svector-vec expr)]
|
|
[len (vector-length vec)])
|
|
(if (len . < . (- CPT_SMALL_SVECTOR_END CPT_SMALL_SVECTOR_START))
|
|
(out-byte (+ CPT_SMALL_SVECTOR_START len) out)
|
|
(begin (out-byte CPT_SVECTOR out)
|
|
(out-number len out)))
|
|
(for ([n (in-range (sub1 len) -1 -1)])
|
|
(out-number (vector-ref vec n) out)))]
|
|
[(module-path-index? expr)
|
|
(out-shared expr out
|
|
(lambda ()
|
|
(out-byte CPT_MODULE_INDEX out)
|
|
(let-values ([(name base) (module-path-index-split expr)])
|
|
(out-data name out)
|
|
(out-data base out))))]
|
|
[(module-decl? expr)
|
|
(out-marshaled module-type-num
|
|
(module-decl-content expr)
|
|
out)]
|
|
[(stx? expr)
|
|
(out-stx expr out)]
|
|
[(wrapped? expr)
|
|
(out-wrapped expr out)]
|
|
[else
|
|
(out-byte CPT_QUOTE out)
|
|
(let ([s (open-output-bytes)])
|
|
(write (if (quoted? expr)
|
|
(quoted-v expr)
|
|
expr) s)
|
|
(out-byte CPT_ESCAPE out)
|
|
(let ([bstr (get-output-bytes s)])
|
|
(out-number (bytes-length bstr) out)
|
|
(out-bytes bstr out)))]))
|
|
|
|
|
|
(define-struct quoted (v) #:prefab)
|
|
|
|
(define (protect-quote v)
|
|
v
|
|
#;(if (or (list? v) (vector? v) (box? v) (hash? v))
|
|
(make-quoted v)
|
|
v))
|
|
|
|
|
|
(define-struct svector (vec))
|
|
|
|
;; ----------------------------------------
|
|
|