cs: simplify and improve handling of literals

Use data instead of code to shrink ".zo" sizes by 10-30%.

When Racket code contains a literal that cannot be serialized directly
by Chez Scheme (such as a keyword or an immutable string that should
be datum-interned), the old approach was to generate Scheme code to
construct the literal through a lifted `let` binding. To handle paths
associated with procedures, however, Chez Scheme's `fasl-write` had
been extended to allow arbitrary values to be intercepted during fasl
and passed back in to `fasl-read`. Using that strategy for all Racket
literals simplifies the implementation and reduces compiled code. It
also makes closures smaller, while increases the number of
relocations. DrRacket's foorprint shrinks by about 1%, but the main
affect is on disk space for a Racket installation.
This commit is contained in:
Matthew Flatt 2020-11-21 14:15:50 -07:00
parent b2a27ef05c
commit f07c2fea71
42 changed files with 3002 additions and 6388 deletions

View File

@ -14,7 +14,7 @@
;; In the Racket source repo, this version should change only when
;; "racket_version.h" changes:
(define version "7.9.0.6")
(define version "7.9.0.7")
(define deps `("racket-lib"
["racket" #:version ,version]))

View File

@ -248,31 +248,23 @@
[(? linklet?)
(case (system-type 'vm)
[(chez-scheme)
(define-values (fmt code sfd-paths args) ((vm-primitive 'linklet-fasled-code+arguments) l))
(define-values (fmt code literals) ((vm-primitive 'linklet-fasled-code+arguments) l))
(cond
[code
(case fmt
[(compile)
(cond
[(not (current-partial-fasl))
;; Note that applying the result of `vm-eval` no longer shows the setup of
;; Racket level constants (like keywords):
(define make-proc (vm-eval `(load-compiled-from-port (open-bytevector-input-port ,code) ',sfd-paths)))
(define proc (make-proc))
(let ([proc (decompile-chez-procedure (if (null? args) proc (apply proc args)) make-proc)])
(if (null? args)
proc
(cons proc (map (vm-primitive 'force-unfasl) args))))]
(define proc (vm-eval `(load-compiled-from-port (open-bytevector-input-port ,code) ',literals)))
(decompile-chez-procedure proc)]
[else
(define desc (disassemble-in-description
`(#(FASL
#:length ,(bytes-length code)
,(vm-eval `(($primitive $describe-fasl-from-port) (open-bytevector-input-port ,code) ',sfd-paths))))))
(if (null? args)
desc
(cons desc (map (vm-primitive 'force-unfasl) args)))])]
(disassemble-in-description
`(#(FASL
#:length ,(bytes-length code)
#:literals ,literals
,(vm-eval `(($primitive $describe-fasl-from-port) (open-bytevector-input-port ,code) ',literals)))))])]
[(interpret)
(define bytecode (vm-eval `(fasl-read (open-bytevector-input-port ,code) 'load ',sfd-paths)))
(define bytecode (vm-eval `(fasl-read (open-bytevector-input-port ,code) 'load ',literals)))
(list `(#%interpret ,(unwrap-chez-interpret-jitified bytecode)))]
[else
'(....)])]

View File

@ -12,19 +12,15 @@
(define current-can-disassemble (make-parameter #t))
(define current-partial-fasl (make-parameter #f))
(define (decompile-chez-procedure p make-p)
(define (decompile-chez-procedure p)
(unless (procedure? p)
(error 'decompile-chez-procedure "not a procedure"))
(define seen (make-hasheq))
((vm-primitive 'call-with-system-wind)
(lambda ()
(define make-proc ((vm-primitive 'inspect/object) make-p))
(define make-code (make-proc 'code))
(define proc ((vm-primitive 'inspect/object) p))
(define code (proc 'code))
(append
(decompile-code make-code #f seen #:name "body-maker-that-creates-lifted-constants")
(decompile-code code proc seen #:unwrap-body? #t)))))
(decompile-code code seen #:unwrap-body? #t))))
(define (decompile obj closure seen)
(define type (obj 'type))
@ -36,7 +32,7 @@
[else
(hash-set! seen (obj 'value) #t)
(case type
[(code) (decompile-code obj closure seen)]
[(code) (decompile-code obj seen)]
[(variable)
(decompile (obj 'ref) #f seen)]
[(procedure)
@ -46,20 +42,11 @@
(define (decompile-value v seen)
(decompile ((vm-primitive 'inspect/object) v) #f seen))
(define (decompile-code code closure seen
#:unwrap-body? [unwrap-body? #f]
#:name [name #f])
(define (decompile-code code seen
#:unwrap-body? [unwrap-body? #f])
(define $generation (vm-eval '($primitive $generation)))
(define $code? (vm-eval '($primitive $code?)))
(define max-gen (vm-eval '(collect-maximum-generation)))
(define captures (if (and closure (positive? (code 'free-count)))
`('(captures: ,@(for/list ([i (in-range (code 'free-count))])
(define v (closure 'ref i))
(let loop ([v v])
(case (v 'type)
[(variable) (loop (v 'ref))]
[else (v 'value)])))))
'()))
(append
(apply
append
@ -68,11 +55,9 @@
(($generation v) . > . max-gen)))
(decompile-value v seen)))
(if unwrap-body?
(append
captures
(decompile-code-body code))
(decompile-code-body code)
(list
`(define ,(let ([name (or name (code 'name))])
`(define ,(let* ([name (code 'name)])
(if name
(string->symbol
(if (and ((string-length name) . > . 0)
@ -81,7 +66,6 @@
name))
'....))
(lambda ,(arity-mask->args (code 'arity-mask))
,@captures
,@(decompile-code-body code)))))))
(define (decompile-code-body code-obj)
@ -110,16 +94,20 @@
(if s
(let-values ([(path line col pos)
(vm-eval `(let ([s ',s])
(values (let ([sfd (source-object-sfd s)])
(values (let* ([sfd (source-object-sfd s)])
(and sfd (source-file-descriptor-path sfd)))
(source-object-line s)
(source-object-column s)
(source-object-bfp s))))])
(cond
[(not path) null]
[(and line col) (list (format "~a:~a:~a" path line col))]
[pos (list (format "~a:~a" path pos))]
[else (list path)]))
(let ([path (if (srcloc? path)
;; the linklet layer wraps paths as srclocs
(srcloc-source path)
path)])
(cond
[(not path) null]
[(and line col) (list (format "~a:~a:~a" path line col))]
[pos (list (format "~a:~a" path pos))]
[else (list path)])))
null))
;; Show machine/assembly code:
(cond

View File

@ -13,11 +13,13 @@
[out (or/c output-port? #f) #f]
[#:keep-mutable? keep-mutable? any/c #f]
[#:handle-fail handle-fail (or/c #f (any/c . -> . any/c)) #f]
[#:external-lift? external-lift? (or/c #f (any/c . -> . any/c)) #f])
[#:external-lift? external-lift? (or/c #f (any/c . -> . any/c)) #f]
[#:skip-prefix? skip-prefix? any/c #f])
(or/c (void) bytes?)]
@defproc[(fasl->s-exp [in (or/c input-port? bytes?)]
[#:datum-intern? datum-intern? any/c #t]
[#:external-lifts external-lifts vector? '#()])
[#:external-lifts external-lifts vector? '#()]
[#:skip-prefix? skip-prefix? any/c #f])
any/c]
)]{
@ -74,11 +76,19 @@ is filtered by @racket[datum-intern-literal]. The defaults make the
composition of @racket[s-exp->fasl] and @racket[fasl->s-exp] behave
like the composition of @racket[write] and @racket[read].
If @racket[skip-prefix?] is not @racket[#f], then a prefix that
identifies the stream as a serialization is not written by
@racket[s-exp->fasl] or read by @racket[fasl->s-exp]. Omitting a
prefix can save a small amount of space, which can useful when
serializing small values, but it gives up a sanity check on the
@racket[fasl->s-exp] that is often useful.
The byte-string encoding produced by @racket[s-exp->fasl] is
independent of the Racket version, except as future Racket versions
introduce extensions that are not currently recognized. In particular,
the result of @racket[s-exp->fasl] will be valid as input to any
future version of @racket[fasl->s-exp].
future version of @racket[fasl->s-exp] (as long as the
@racket[skip-prefix?] arguments are consistent).
@mz-examples[
#:eval fasl-eval

View File

@ -2,6 +2,7 @@
(require '#%extfl
racket/linklet
racket/unsafe/undefined
racket/fixnum
(for-syntax racket/base)
"private/truncate-path.rkt"
"private/relative-path.rkt"
@ -121,7 +122,8 @@
[orig-o #f]
#:keep-mutable? [keep-mutable? #f]
#:handle-fail [handle-fail #f]
#:external-lift? [external-lift? #f])
#:external-lift? [external-lift? #f]
#:skip-prefix? [skip-prefix? #f])
(when orig-o
(unless (output-port? orig-o)
(raise-argument-error 's-exp->fasl "(or/c output-port? #f)" orig-o)))
@ -184,7 +186,8 @@
(define (treat-immutable? v) (or (not keep-mutable?) (immutable? v)))
(define path->relative-path-elements (make-path->relative-path-elements))
;; The fasl formal prefix:
(write-bytes fasl-prefix o)
(unless skip-prefix?
(write-bytes fasl-prefix o))
;; Write content to a string, so we can measure it
(define bstr
(let ([o (open-output-bytes)])
@ -394,14 +397,16 @@
(define (fasl->s-exp orig-i
#:datum-intern? [intern? #t]
#:external-lifts [external-lifts '#()])
#:external-lifts [external-lifts '#()]
#:skip-prefix? [skip-prefix? #f])
(define init-i (cond
[(bytes? orig-i) (mcons orig-i 0)]
[(input-port? orig-i) orig-i]
[else (raise-argument-error 'fasl->s-exp "(or/c bytes? input-port?)" orig-i)]))
(unless (bytes=? (read-bytes/exactly fasl-prefix-length init-i) fasl-prefix)
(read-error "unrecognized prefix"))
(define shared-count (read-fasl-integer init-i))
(unless skip-prefix?
(unless (bytes=? (read-bytes/exactly* fasl-prefix-length init-i) fasl-prefix)
(read-error "unrecognized prefix")))
(define shared-count (read-fasl-integer* init-i))
(define shared (make-vector shared-count))
(unless (and (vector? external-lifts)
@ -411,11 +416,11 @@
[pos (in-naturals)])
(vector-set! shared pos (vector-ref external-lifts pos)))
(define len (read-fasl-integer init-i))
(define len (read-fasl-integer* init-i))
(define i (if (mpair? init-i)
init-i
;; Faster to work with a byte string:
(let ([bstr (read-bytes/exactly len init-i)])
(let ([bstr (read-bytes/exactly* len init-i)])
(mcons bstr 0))))
(define (intern v) (if intern? (datum-intern-literal v) v))
@ -588,13 +593,16 @@
args))
(define (read-byte/no-eof i)
(define pos (mcdr i))
(unless (pos . < . (bytes-length (mcar i)))
(read-error "truncated stream"))
(set-mcdr! i (fx+ pos 1))
(bytes-ref (mcar i) pos))
(define (read-byte/no-eof* i)
(cond
[(mpair? i)
(define pos (mcdr i))
(unless (pos . < . (bytes-length (mcar i)))
(read-error "truncated stream"))
(set-mcdr! i (add1 pos))
(bytes-ref (mcar i) pos)]
(read-byte/no-eof i)]
[else
(define b (read-byte i))
(when (eof-object? b)
@ -602,42 +610,93 @@
b]))
(define (read-bytes/exactly n i)
(define pos (mcdr i))
(unless ((+ pos n) . <= . (bytes-length (mcar i)))
(read-error "truncated stream"))
(set-mcdr! i (fx+ pos n))
(subbytes (mcar i) pos (fx+ pos n)))
(define (read-bytes/exactly* n i)
(cond
[(mpair? i)
(define pos (mcdr i))
(unless ((+ pos n) . <= . (bytes-length (mcar i)))
(read-error "truncated stream"))
(set-mcdr! i (+ pos n))
(subbytes (mcar i) pos (+ pos n))]
(read-bytes/exactly n i)]
[else
(define bstr (read-bytes n i))
(unless (and (bytes? bstr) (= n (bytes-length bstr)))
(read-error "truncated stream"))
bstr]))
(define (read-fasl-integer i)
(define b (read-byte/no-eof i))
(cond
[(<= b 127) b]
[(>= b 132) (- b 256)]
[(eqv? b 128)
(integer-bytes->integer (read-bytes/exactly 2 i) #t #f)]
[(eqv? b 129)
(integer-bytes->integer (read-bytes/exactly 4 i) #t #f)]
[(eqv? b 130)
(integer-bytes->integer (read-bytes/exactly 8 i) #t #f)]
[(eqv? b 131)
(define len (read-fasl-integer i))
(define str (read-fasl-string i len))
(unless (and (string? str) (= len (string-length str)))
(read-error "truncated stream at number"))
(string->number str 16)]
[else
(read-error "internal error on integer mode")]))
(define-values (read-fasl-integer read-fasl-integer*)
(let-syntax ([gen
(syntax-rules ()
[(_ read-byte/no-eof read-bytes/exactly)
(lambda (i)
(define b (read-byte/no-eof i))
(cond
[(fx<= b 127) b]
[(fx>= b 132) (fx- b 256)]
[(eqv? b 128)
(define lo (read-byte/no-eof i))
(define hi (read-byte/no-eof i))
(if (hi . fx> . 127)
(fxior (fxlshift (fx+ -256 hi) 8) lo)
(fxior (fxlshift hi 8) lo))]
[(eqv? b 129)
(define a (read-byte/no-eof i))
(define b (read-byte/no-eof i))
(define c (read-byte/no-eof i))
(define d (read-byte/no-eof i))
(bitwise-ior a
(arithmetic-shift
;; 24 bits always fit in a fixnum:
(if (d . fx> . 127)
(fxior (fxlshift (fx+ -256 d) 16)
(fxlshift c 8)
b)
(fxior (fxlshift d 16)
(fxlshift c 8)
b))
8))]
[(eqv? b 130)
(integer-bytes->integer (read-bytes/exactly 8 i) #t #f)]
[(eqv? b 131)
(define len (read-fasl-integer i))
(define str (read-fasl-string i len))
(unless (and (string? str) (= len (string-length str)))
(read-error "truncated stream at number"))
(string->number str 16)]
[else
(read-error "internal error on integer mode")]))])])
(values (gen read-byte/no-eof read-bytes/exactly)
(gen read-byte/no-eof* read-bytes/exactly*))))
(define (read-fasl-string i [len (read-fasl-integer i)])
(define bstr (read-bytes/exactly len i))
(bytes->string/utf-8 bstr))
(define pos (mcdr i))
(define bstr (mcar i))
(cond
[((+ pos len) . <= . (bytes-length bstr))
(set-mcdr! i (fx+ pos len))
;; optimistically assume ASCII:
(define s (make-string len))
(let loop ([i 0])
(cond
[(fx= i len)
;; success: all ASCII
s]
[else
(define c (bytes-ref bstr (fx+ i pos)))
(cond
[(c . fx<= . 128)
(string-set! s i (integer->char c))
(loop (fx+ i 1))]
[else
;; not ASCII, so abandon fast-path string
(bytes->string/utf-8 bstr #f pos (fx+ pos len))])]))]
[else
;; let read-bytes/exactly complain
(define bstr (read-bytes/exactly len i))
;; don't expect to get here!
(bytes->string/utf-8 bstr)]))
(define (read-fasl-bytes i)
(define len (read-fasl-integer i))

View File

@ -3737,6 +3737,8 @@
[(base index offset e build-assign build-barrier-seq)
(if (nanopass-case (L7 Expr) e
[(quote ,d) (ptr->imm d)]
[(call ,info ,mdcl ,pr ,e* ...)
(eq? 'fixnum ($sgetprop (primref-name pr) '*result-type* #f))]
[else #f])
(build-assign base index offset e)
(let ([a (if (eq? index %zero)

View File

@ -207,9 +207,7 @@
[(symbol-hashtable? x) (bld-graph x t a? d #t bld-ht)]
[($record? x) (bld-graph x t a? d #t bld-record)]
[(box? x) (bld-graph x t a? d #t bld-box)]
[(or (large-integer? x) (ratnum? x) ($inexactnum? x) ($exactnum? x)
(fxvector? x) (flvector? x) (bytevector? x))
(bld-graph x t a? d #t bld-simple)])))
[else (bld-graph x t a? d #t bld-simple)])))
(module (small-integer? large-integer?)
(define least-small-integer (- (expt 2 31)))
@ -626,6 +624,11 @@
(put-u8 p (constant fasl-type-graph-ref))
(put-uptr p (car a))]))))
(define (wrf-invalid x p t a?)
(wrf-graph x p t a?
(lambda (x p t a?)
($oops 'fasl-write "invalid fasl object ~s" x))))
(define wrf
(lambda (x p t a?)
(cond
@ -649,7 +652,7 @@
; this check must go before $record? check
[(symbol-hashtable? x) (wrf-graph x p t a? wrf-symht)]
; this check must go before $record? check
[(hashtable? x) ($oops 'fasl-write "invalid fasl object ~s" x)]
[(hashtable? x) (wrf-invalid x p t a?)]
[($record? x) (wrf-graph x p t a? wrf-record)]
[(vector? x) (wrf-graph x p t a? wrf-vector)]
[(stencil-vector? x) (wrf-graph x p t a? wrf-stencil-vector)]
@ -667,7 +670,7 @@
[(eq? x '#0=#0#) (wrf-immediate (constant black-hole) p)]
[($rtd-counts? x) (wrf-immediate (constant sfalse) p)]
[(phantom-bytevector? x) (wrf-phantom x p)]
[else ($oops 'fasl-write "invalid fasl object ~s" x)])))
[else (wrf-invalid x p t a?)])))
(module (start)
(define start

View File

@ -4,7 +4,7 @@
primitive-in-category?)
racket/cmdline
"../../schemify/schemify.rkt"
"../../schemify/serialize.rkt"
"../../cify/literal.rkt"
"../../schemify/known.rkt"
"../../schemify/lift.rkt"
"../../schemify/reinfer-name.rkt"
@ -66,13 +66,13 @@
a-known-constant]))))
(printf "Serializable...\n")
(define-values (bodys/constants-lifted lifted-constants)
(time (convert-for-serialize l #t #t)))
(define-values (bodys/literals-extracted literals)
(time (extract-literals l)))
;; Startup code reuses names to keep it compact; make
;; te names unique again
(define bodys/re-uniqued
(cdr (re-unique `(begin . ,bodys/constants-lifted))))
(cdr (re-unique `(begin . ,bodys/literals-extracted))))
(printf "Schemify...\n")
(define body
@ -93,7 +93,7 @@
(lift-in-schemified-body body)))
(define converted-body
(append (for/list ([p (in-list lifted-constants)])
(append (for/list ([p (in-list literals)])
(cons 'define p))
lifted-body))

View File

@ -18756,14 +18756,15 @@ static const char *startup_source =
"(define-values(fasl-hash-eqv-variant) 2)"
"(define-values"
"(s-exp->fasl.1)"
"(lambda(external-lift?7_0 handle-fail6_0 keep-mutable?5_0 v12_0 orig-o11_0)"
"(lambda(external-lift?7_0 handle-fail6_0 keep-mutable?5_0 skip-prefix?8_0 v14_0 orig-o13_0)"
"(begin"
" 's-exp->fasl"
"(let-values(((v_0) v12_0))"
"(let-values(((orig-o_0) orig-o11_0))"
"(let-values(((v_0) v14_0))"
"(let-values(((orig-o_0) orig-o13_0))"
"(let-values(((keep-mutable?_0) keep-mutable?5_0))"
"(let-values(((handle-fail_0) handle-fail6_0))"
"(let-values(((external-lift?_0) external-lift?7_0))"
"(let-values(((skip-prefix?_0) skip-prefix?8_0))"
"(let-values()"
"(let-values((()"
"(begin"
@ -18772,7 +18773,7 @@ static const char *startup_source =
"(if(output-port? orig-o_0)"
"(void)"
"(let-values()"
" (raise-argument-error 's-exp->fasl \"(or/c output-port? #f)\" orig-o_0))))"
" (raise-argument-error 's-exp->fasl \"(or/c output-port? #f)\" orig-o_0))))"
"(void))"
"(values))))"
"(let-values((()"
@ -18786,7 +18787,7 @@ static const char *startup_source =
"(let-values()"
"(raise-argument-error"
" 's-exp->fasl"
" \"(or/c (procedure-arity-includes/c 1) #f)\""
" \"(or/c (procedure-arity-includes/c 1) #f)\""
" handle-fail_0))))"
"(void))"
"(values))))"
@ -18801,7 +18802,7 @@ static const char *startup_source =
"(let-values()"
"(raise-argument-error"
" 's-exp->fasl"
" \"(or/c (procedure-arity-includes/c 1) #f)\""
" \"(or/c (procedure-arity-includes/c 1) #f)\""
" external-lift?_0))))"
"(void))"
"(values))))"
@ -18833,7 +18834,8 @@ static const char *startup_source =
" shared_0"
" v_1"
"(- shared-counter_0))))"
"(if(let-values(((or-part_0)(symbol? v_1)))"
"(if(let-values(((or-part_0)"
"(symbol? v_1)))"
"(if or-part_0"
" or-part_0"
"(let-values(((or-part_1)"
@ -18913,7 +18915,8 @@ static const char *startup_source =
"(loop_0 v_2)))"
" #t))"
"(if(box? v_1)"
"(let-values()(loop_0(unbox v_1)))"
"(let-values()"
"(loop_0(unbox v_1)))"
"(let-values(((c1_0)"
"(prefab-struct-key"
" v_1)))"
@ -18936,7 +18939,7 @@ static const char *startup_source =
" 1)"
"(normalise-inputs"
" 'in-vector"
" \"vector\""
" \"vector\""
"(lambda(x_0)"
"(vector?"
" x_0))"
@ -19055,7 +19058,12 @@ static const char *startup_source =
"(let-values(((path->relative-path-elements_0)"
"(let-values()"
"(make-path->relative-path-elements.1 #f unsafe-undefined))))"
"(let-values((()(begin(1/write-bytes fasl-prefix o_0)(values))))"
"(let-values((()"
"(begin"
"(if skip-prefix?_0"
"(void)"
"(let-values()(1/write-bytes fasl-prefix o_0)))"
"(values))))"
"(let-values(((bstr_0)"
"(let-values(((o_1)(open-output-bytes)))"
"(begin"
@ -19064,7 +19072,9 @@ static const char *startup_source =
"(begin"
" 'loop"
"(if(not"
"(eq?(hash-ref shared_0 v_1 1) 1))"
"(eq?"
"(hash-ref shared_0 v_1 1)"
" 1))"
"(let-values()"
"(let-values(((c_0)"
"(hash-ref"
@ -19084,7 +19094,8 @@ static const char *startup_source =
" shared-counter_0))"
"(begin"
"(set! shared-counter_0"
"(add1 shared-counter_0))"
"(add1"
" shared-counter_0))"
"(1/write-byte"
" fasl-graph-def-type"
" o_1)"
@ -19156,13 +19167,14 @@ static const char *startup_source =
"(if(eqv?"
" v_1"
" +nan.0)"
" #\"\\0\\0\\0\\0\\0\\0\\370\\177\""
" #\"\\0\\0\\0\\0\\0\\0\\370\\177\""
"(real->floating-point-bytes"
" v_1"
" 8"
" #f))"
" o_1)))"
"(if(single-flonum? v_1)"
"(if(single-flonum?"
" v_1)"
"(let-values()"
"(begin"
"(1/write-byte"
@ -19173,7 +19185,7 @@ static const char *startup_source =
" v_1"
"(real->single-flonum"
" +nan.0))"
" #\"\\0\\0\\300\\177\""
" #\"\\0\\0\\300\\177\""
"(real->floating-point-bytes"
" v_1"
" 4"
@ -19190,7 +19202,7 @@ static const char *startup_source =
"(let-values(((bstr_0)"
"(string->bytes/utf-8"
"(format"
" \"~a\""
" \"~a\""
" v_1))))"
"(begin"
"(write-fasl-integer"
@ -19200,7 +19212,8 @@ static const char *startup_source =
"(1/write-bytes"
" bstr_0"
" o_1)))))"
"(if(rational? v_1)"
"(if(rational?"
" v_1)"
"(let-values()"
"(begin"
"(1/write-byte"
@ -19212,7 +19225,8 @@ static const char *startup_source =
"(loop_0"
"(denominator"
" v_1))))"
"(if(complex? v_1)"
"(if(complex?"
" v_1)"
"(let-values()"
"(begin"
"(1/write-byte"
@ -19224,7 +19238,8 @@ static const char *startup_source =
"(loop_0"
"(imag-part"
" v_1))))"
"(if(char? v_1)"
"(if(char?"
" v_1)"
"(let-values()"
"(begin"
"(1/write-byte"
@ -19591,7 +19606,7 @@ static const char *startup_source =
" 1)"
"(normalise-inputs"
" 'in-vector"
" \"vector\""
" \"vector\""
"(lambda(x_0)"
"(vector?"
" x_0))"
@ -19787,8 +19802,8 @@ static const char *startup_source =
" v_1))"
"(raise-arguments-error"
" 's-exp->fasl"
" \"cannot write value\""
" \"value\""
" \"cannot write value\""
" \"value\""
" v_1))))))))))))))))))))))))))))))))))))"
" loop_0)"
" v_0)"
@ -19797,15 +19812,16 @@ static const char *startup_source =
"(write-fasl-integer shared-counter_0 o_0)"
"(write-fasl-integer(bytes-length bstr_0) o_0)"
"(1/write-bytes bstr_0 o_0)"
"(if orig-o_0(void)(get-output-bytes o_0))))))))))))))))))))))))"
"(if orig-o_0(void)(get-output-bytes o_0)))))))))))))))))))))))))"
"(define-values"
"(fasl->s-exp.1)"
"(lambda(datum-intern?14_0 external-lifts15_0 orig-i18_0)"
"(lambda(datum-intern?16_0 external-lifts17_0 skip-prefix?18_0 orig-i22_0)"
"(begin"
" 'fasl->s-exp"
"(let-values(((orig-i_0) orig-i18_0))"
"(let-values(((intern?_0) datum-intern?14_0))"
"(let-values(((external-lifts_0)(if(eq? external-lifts15_0 unsafe-undefined) '#() external-lifts15_0)))"
"(let-values(((orig-i_0) orig-i22_0))"
"(let-values(((intern?_0) datum-intern?16_0))"
"(let-values(((external-lifts_0)(if(eq? external-lifts17_0 unsafe-undefined) '#() external-lifts17_0)))"
"(let-values(((skip-prefix?_0) skip-prefix?18_0))"
"(let-values()"
"(let-values(((init-i_0)"
"(if(bytes? orig-i_0)"
@ -19813,14 +19829,17 @@ static const char *startup_source =
"(if(input-port? orig-i_0)"
"(let-values() orig-i_0)"
"(let-values()"
" (raise-argument-error 'fasl->s-exp \"(or/c bytes? input-port?)\" orig-i_0))))))"
" (raise-argument-error 'fasl->s-exp \"(or/c bytes? input-port?)\" orig-i_0))))))"
"(let-values((()"
"(begin"
"(if(bytes=?(read-bytes/exactly fasl-prefix-length init-i_0) fasl-prefix)"
"(if skip-prefix?_0"
"(void)"
" (let-values () (read-error \"unrecognized prefix\")))"
"(let-values()"
"(if(bytes=?(read-bytes/exactly* fasl-prefix-length init-i_0) fasl-prefix)"
"(void)"
" (let-values () (read-error \"unrecognized prefix\")))))"
"(values))))"
"(let-values(((shared-count_0)(read-fasl-integer init-i_0)))"
"(let-values(((shared-count_0)(read-fasl-integer* init-i_0)))"
"(let-values(((shared_0)(make-vector shared-count_0)))"
"(let-values((()"
"(begin"
@ -19829,7 +19848,7 @@ static const char *startup_source =
" #f)"
"(void)"
"(let-values()"
" (error 'fasl->s-exp \"external-lift vector does not match expected size\")))"
" (error 'fasl->s-exp \"external-lift vector does not match expected size\")))"
"(values))))"
"(let-values((()"
"(begin"
@ -19849,7 +19868,8 @@ static const char *startup_source =
"(begin"
" 'for-loop"
"(if(if(unsafe-fx< pos_0 len_0) #t #f)"
"(let-values(((v_0)(unsafe-vector-ref vec_0 pos_0))"
"(let-values(((v_0)"
"(unsafe-vector-ref vec_0 pos_0))"
"((pos_2) pos_1))"
"(let-values((()"
"(let-values()"
@ -19866,7 +19886,9 @@ static const char *startup_source =
"(values)))))"
"(values)))))"
"(if(not #f)"
"(for-loop_0(unsafe-fx+ 1 pos_0)(+ pos_1 1))"
"(for-loop_0"
"(unsafe-fx+ 1 pos_0)"
"(+ pos_1 1))"
"(values))))"
"(values))))))"
" for-loop_0)"
@ -19874,11 +19896,11 @@ static const char *startup_source =
" start_0)))"
"(values))))"
"(let-values()"
"(let-values(((len_0)(read-fasl-integer init-i_0)))"
"(let-values(((len_0)(read-fasl-integer* init-i_0)))"
"(let-values(((i_0)"
"(if(mpair? init-i_0)"
" init-i_0"
"(let-values(((bstr_0)(read-bytes/exactly len_0 init-i_0)))"
"(let-values(((bstr_0)(read-bytes/exactly* len_0 init-i_0)))"
"(mcons bstr_0 0)))))"
"(let-values(((intern_0)"
"(lambda(v_0)"
@ -19953,8 +19975,8 @@ static const char *startup_source =
" fasl-lowest-small-integer))"
"(let-values()"
"(read-error"
" \"unrecognized fasl tag\""
" \"tag\""
" \"unrecognized fasl tag\""
" \"tag\""
" type_0))))"
"(if(unsafe-fx< index_0 2)"
"(let-values()"
@ -19965,7 +19987,7 @@ static const char *startup_source =
"(if(< pos_0 shared-count_0)"
"(void)"
"(let-values()"
" (read-error \"bad graph index\")))"
" (read-error \"bad graph index\")))"
"(vector-set! shared_0 pos_0 v_0)"
" v_0))))"
"(if(unsafe-fx< index_0 3)"
@ -19976,7 +19998,7 @@ static const char *startup_source =
"(if(< pos_0 shared-count_0)"
"(void)"
"(let-values()"
" (read-error \"bad graph index\")))"
" (read-error \"bad graph index\")))"
"(vector-ref shared_0 pos_0))))"
"(let-values() #f))))"
"(if(unsafe-fx< index_0 6)"
@ -20034,8 +20056,10 @@ static const char *startup_source =
"(read-fasl-string i_0)))"
"(if(unsafe-fx< index_0 19)"
"(let-values()"
"(string->keyword(read-fasl-string i_0)))"
"(let-values()(read-fasl-string i_0))))))))"
"(string->keyword"
"(read-fasl-string i_0)))"
"(let-values()"
"(read-fasl-string i_0))))))))"
"(if(unsafe-fx< index_0 30)"
"(if(unsafe-fx< index_0 24)"
"(if(unsafe-fx< index_0 21)"
@ -20068,7 +20092,8 @@ static const char *startup_source =
"(#%variable-reference))"
"(void)"
"(let-values()"
"(check-list lst_0)))"
"(check-list"
" lst_0)))"
"((letrec-values(((for-loop_0)"
"(lambda(fold-var_0"
" lst_1)"
@ -20116,9 +20141,12 @@ static const char *startup_source =
"(if(null? rel-elems_0)"
"(let-values()(build-path 'same))"
"(let-values()"
"(apply build-path rel-elems_0)))))))"
"(apply"
" build-path"
" rel-elems_0)))))))"
"(let-values()"
"(intern_0(pregexp(read-fasl-string i_0)))))"
"(intern_0"
"(pregexp(read-fasl-string i_0)))))"
"(if(unsafe-fx< index_0 27)"
"(let-values()"
"(intern_0(regexp(read-fasl-string i_0))))"
@ -20203,7 +20231,8 @@ static const char *startup_source =
"(let-values(((len_1)"
"(read-fasl-integer i_0)))"
"(let-values(((vec_0)"
"(let-values(((len_2) len_1))"
"(let-values(((len_2)"
" len_1))"
"(begin"
"(if(exact-nonnegative-integer?"
" len_2)"
@ -20211,7 +20240,7 @@ static const char *startup_source =
"(let-values()"
"(raise-argument-error"
" 'for/vector"
" \"exact-nonnegative-integer?\""
" \"exact-nonnegative-integer?\""
" len_2)))"
"(let-values(((v_0)"
"(make-vector"
@ -20432,7 +20461,8 @@ static const char *startup_source =
" end_0"
" inc_0)))"
"((letrec-values(((for-loop_0)"
"(lambda(ht_1 pos_0)"
"(lambda(ht_1"
" pos_0)"
"(begin"
" 'for-loop"
"(if(<"
@ -20481,8 +20511,10 @@ static const char *startup_source =
"(srcloc-source s_0)"
"(srcloc-line s_0)"
"(srcloc-column s_0)"
"(srcloc-position s_0)"
"(srcloc-span s_0)))))"
"(srcloc-position"
" s_0)"
"(srcloc-span"
" s_0)))))"
"(let-values(((lst_0)(loop_0)))"
"(begin"
"(if(variable-reference-from-unsafe?"
@ -20528,7 +20560,7 @@ static const char *startup_source =
" lst_0)))))))"
"(let-values()"
" unsafe-undefined)))))))))))))))"
" loop_0)))))))))))))))))))"
" loop_0))))))))))))))))))))"
"(define-values"
"(write-fasl-integer)"
"(lambda(i_0 o_0)"
@ -20562,13 +20594,17 @@ static const char *startup_source =
"(read-byte/no-eof)"
"(lambda(i_0)"
"(begin"
"(if(mpair? i_0)"
"(let-values()"
"(let-values(((pos_0)(mcdr i_0)))"
"(begin"
" (if (< pos_0 (bytes-length (mcar i_0))) (void) (let-values () (read-error \"truncated stream\")))"
"(set-mcdr! i_0(add1 pos_0))"
"(bytes-ref(mcar i_0) pos_0))))"
" (if (< pos_0 (bytes-length (mcar i_0))) (void) (let-values () (read-error \"truncated stream\")))"
"(set-mcdr! i_0(fx+ pos_0 1))"
"(bytes-ref(mcar i_0) pos_0))))))"
"(define-values"
"(read-byte/no-eof*)"
"(lambda(i_0)"
"(begin"
"(if(mpair? i_0)"
"(let-values()(read-byte/no-eof i_0))"
"(let-values()"
"(let-values(((b_0)(read-byte i_0)))"
" (begin (if (eof-object? b_0) (let-values () (read-error \"truncated stream\")) (void)) b_0)))))))"
@ -20576,13 +20612,17 @@ static const char *startup_source =
"(read-bytes/exactly)"
"(lambda(n_0 i_0)"
"(begin"
"(if(mpair? i_0)"
"(let-values()"
"(let-values(((pos_0)(mcdr i_0)))"
"(begin"
" (if (<= (+ pos_0 n_0) (bytes-length (mcar i_0))) (void) (let-values () (read-error \"truncated stream\")))"
"(set-mcdr! i_0(+ pos_0 n_0))"
"(subbytes(mcar i_0) pos_0(+ pos_0 n_0)))))"
" (if (<= (+ pos_0 n_0) (bytes-length (mcar i_0))) (void) (let-values () (read-error \"truncated stream\")))"
"(set-mcdr! i_0(fx+ pos_0 n_0))"
"(subbytes(mcar i_0) pos_0(fx+ pos_0 n_0)))))))"
"(define-values"
"(read-bytes/exactly*)"
"(lambda(n_0 i_0)"
"(begin"
"(if(mpair? i_0)"
"(let-values()(read-bytes/exactly n_0 i_0))"
"(let-values()"
"(let-values(((bstr_0)(read-bytes n_0 i_0)))"
"(begin"
@ -20591,18 +20631,34 @@ static const char *startup_source =
" (let-values () (read-error \"truncated stream\")))"
" bstr_0)))))))"
"(define-values"
"(read-fasl-integer)"
"(read-fasl-integer read-fasl-integer*)"
"(let-values()"
"(let-values()"
"(values"
"(lambda(i_0)"
"(begin"
"(let-values(((b_0)(read-byte/no-eof i_0)))"
"(if(<= b_0 127)"
"(if(fx<= b_0 127)"
"(let-values() b_0)"
"(if(>= b_0 132)"
"(let-values()(- b_0 256))"
"(if(fx>= b_0 132)"
"(let-values()(fx- b_0 256))"
"(if(eqv? b_0 128)"
"(let-values()(integer-bytes->integer(read-bytes/exactly 2 i_0) #t #f))"
"(let-values()"
"(let-values(((lo_0)(read-byte/no-eof i_0)))"
"(let-values(((hi_0)(read-byte/no-eof i_0)))"
"(if(fx> hi_0 127)(fxior(fxlshift(fx+ -256 hi_0) 8) lo_0)(fxior(fxlshift hi_0 8) lo_0)))))"
"(if(eqv? b_0 129)"
"(let-values()(integer-bytes->integer(read-bytes/exactly 4 i_0) #t #f))"
"(let-values()"
"(let-values(((a_0)(read-byte/no-eof i_0)))"
"(let-values(((b_1)(read-byte/no-eof i_0)))"
"(let-values(((c_0)(read-byte/no-eof i_0)))"
"(let-values(((d_0)(read-byte/no-eof i_0)))"
"(bitwise-ior"
" a_0"
"(arithmetic-shift"
"(if(fx> d_0 127)"
"(fxior(fxlshift(fx+ -256 d_0) 16)(fxlshift c_0 8) b_1)"
"(fxior(fxlshift d_0 16)(fxlshift c_0 8) b_1))"
" 8)))))))"
"(if(eqv? b_0 130)"
"(let-values()(integer-bytes->integer(read-bytes/exactly 8 i_0) #t #f))"
"(if(eqv? b_0 131)"
@ -20612,22 +20668,87 @@ static const char *startup_source =
"(begin"
"(if(if(string? str_0)(= len_0(string-length str_0)) #f)"
"(void)"
" (let-values () (read-error \"truncated stream at number\")))"
" (let-values () (read-error \"truncated stream at number\")))"
"(1/string->number str_0 16)))))"
" (let-values () (read-error \"internal error on integer mode\"))))))))))))"
" (let-values () (read-error \"internal error on integer mode\"))))))))))"
"(lambda(i_0)"
"(let-values(((b_0)(read-byte/no-eof* i_0)))"
"(if(fx<= b_0 127)"
"(let-values() b_0)"
"(if(fx>= b_0 132)"
"(let-values()(fx- b_0 256))"
"(if(eqv? b_0 128)"
"(let-values()"
"(let-values(((lo_0)(read-byte/no-eof* i_0)))"
"(let-values(((hi_0)(read-byte/no-eof* i_0)))"
"(if(fx> hi_0 127)(fxior(fxlshift(fx+ -256 hi_0) 8) lo_0)(fxior(fxlshift hi_0 8) lo_0)))))"
"(if(eqv? b_0 129)"
"(let-values()"
"(let-values(((a_0)(read-byte/no-eof* i_0)))"
"(let-values(((b_1)(read-byte/no-eof* i_0)))"
"(let-values(((c_0)(read-byte/no-eof* i_0)))"
"(let-values(((d_0)(read-byte/no-eof* i_0)))"
"(bitwise-ior"
" a_0"
"(arithmetic-shift"
"(if(fx> d_0 127)"
"(fxior(fxlshift(fx+ -256 d_0) 16)(fxlshift c_0 8) b_1)"
"(fxior(fxlshift d_0 16)(fxlshift c_0 8) b_1))"
" 8)))))))"
"(if(eqv? b_0 130)"
"(let-values()(integer-bytes->integer(read-bytes/exactly* 8 i_0) #t #f))"
"(if(eqv? b_0 131)"
"(let-values()"
"(let-values(((len_0)(read-fasl-integer i_0)))"
"(let-values(((str_0)(read-fasl-string i_0 len_0)))"
"(begin"
"(if(if(string? str_0)(= len_0(string-length str_0)) #f)"
"(void)"
" (let-values () (read-error \"truncated stream at number\")))"
"(1/string->number str_0 16)))))"
" (let-values () (read-error \"internal error on integer mode\"))))))))))))))"
"(define-values"
"(read-fasl-string)"
"(let-values(((read-fasl-string_0)"
"(lambda(i21_0 len20_0)"
"(lambda(i25_0 len24_0)"
"(begin"
" 'read-fasl-string"
"(let-values(((i_0) i21_0))"
"(let-values(((len_0)(if(eq? len20_0 unsafe-undefined)(read-fasl-integer i_0) len20_0)))"
"(let-values(((i_0) i25_0))"
"(let-values(((len_0)(if(eq? len24_0 unsafe-undefined)(read-fasl-integer i_0) len24_0)))"
"(let-values()"
"(let-values(((bstr_0)(read-bytes/exactly len_0 i_0)))(bytes->string/utf-8 bstr_0)))))))))"
"(let-values(((pos_0)(mcdr i_0)))"
"(let-values(((bstr_0)(mcar i_0)))"
"(if(<=(+ pos_0 len_0)(bytes-length bstr_0))"
"(let-values()"
"(let-values((()(begin(set-mcdr! i_0(fx+ pos_0 len_0))(values))))"
"(let-values(((s_0)(make-string len_0)))"
"((letrec-values(((loop_0)"
"(lambda(i_1)"
"(begin"
" 'loop"
"(if(fx= i_1 len_0)"
"(let-values() s_0)"
"(let-values()"
"(let-values(((c_0)(bytes-ref bstr_0(fx+ i_1 pos_0))))"
"(if(fx<= c_0 128)"
"(let-values()"
"(begin"
"(string-set! s_0 i_1(integer->char c_0))"
"(loop_0(fx+ i_1 1))))"
"(let-values()"
"(bytes->string/utf-8"
" bstr_0"
" #f"
" pos_0"
"(fx+ pos_0 len_0)))))))))))"
" loop_0)"
" 0))))"
"(let-values()"
"(let-values(((bstr_1)(read-bytes/exactly len_0 i_0)))"
"(bytes->string/utf-8 bstr_1)))))))))))))"
"(case-lambda"
"((i_0)(begin(read-fasl-string_0 i_0 unsafe-undefined)))"
"((i_0 len20_0)(read-fasl-string_0 i_0 len20_0)))))"
"((i_0 len24_0)(read-fasl-string_0 i_0 len24_0)))))"
"(define-values"
"(read-fasl-bytes)"
"(lambda(i_0)(begin(let-values(((len_0)(read-fasl-integer i_0)))(read-bytes/exactly len_0 i_0)))))"
@ -20754,7 +20875,6 @@ static const char *startup_source =
" call-with-module-prompt"
" make-pthread-parameter"
" engine-block"
" force-unfasl"
" make-record-type-descriptor"
" make-record-type-descriptor*"
" make-record-constructor-descriptor"
@ -29807,7 +29927,7 @@ static const char *startup_source =
"(define-values"
"(write-correlated-linklet-bundle-hash)"
"(lambda(ht_0 o_0)"
"(begin(let-values(((temp7_0)(->faslable ht_0))((o8_0) o_0))(s-exp->fasl.1 #f #f #f temp7_0 o8_0)))))"
"(begin(let-values(((temp7_0)(->faslable ht_0))((o8_0) o_0))(s-exp->fasl.1 #f #f #f #f temp7_0 o8_0)))))"
"(define-values"
"(->faslable)"
"(lambda(v_0)"
@ -29961,7 +30081,8 @@ static const char *startup_source =
"(define-values"
"(read-correlated-linklet-bundle-hash)"
"(lambda(in_0)"
"(begin(faslable->(let-values(((in9_0) in_0)((temp10_0) #t))(fasl->s-exp.1 temp10_0 unsafe-undefined in9_0))))))"
"(begin"
"(faslable->(let-values(((in9_0) in_0)((temp10_0) #t))(fasl->s-exp.1 temp10_0 unsafe-undefined #f in9_0))))))"
"(define-values"
"(faslable->)"
"(lambda(v_0)"

238
racket/src/cify/literal.rkt Normal file
View File

@ -0,0 +1,238 @@
#lang racket/base
(require racket/extflonum
racket/prefab
racket/unsafe/undefined
"match.rkt"
"../schemify/wrap.rkt")
(provide extract-literals)
;; For most literal values values, lift a construction of the quoted value
;; out and replace the use of a quoted value with a variable
;; reference. This lifting can interefere with optimizations, so only
;; lift as a last resort.
(define (extract-literals bodys)
(define lifted-eq-constants (make-hasheq))
(define lifted-equal-constants (make-hash))
(define lift-bindings null)
(define lifts-count 0)
(define (add-lifted rhs)
;; FIXME: make sure these `id`s don't collide with anything
(define id (string->symbol (format "q:~a" lifts-count)))
(set! lifts-count (add1 lifts-count))
(set! lift-bindings (cons (list id rhs) lift-bindings))
id)
(define new-bodys
(for/list ([v (in-list bodys)])
(cond
[(convert-any? v)
(define (convert v)
(reannotate
v
(match v
[`(quote ,q)
(cond
[(lift-quoted? q)
(make-construct q add-lifted lifted-eq-constants lifted-equal-constants)]
[else v])]
[`(lambda ,formals ,body ...)
`(lambda ,formals ,@(convert-function-body body))]
[`(case-lambda [,formalss ,bodys ...] ...)
`(case-lambda ,@(for/list ([formals (in-list formalss)]
[body (in-list bodys)])
`[,formals ,@(convert-function-body body)]))]
[`(define-values ,ids ,rhs)
`(define-values ,ids ,(convert rhs))]
[`(let-values ([,idss ,rhss] ...) ,bodys ...)
`(let-values ,(for/list ([ids (in-list idss)]
[rhs (in-list rhss)])
`[,ids ,(convert rhs)])
,@(convert-body bodys))]
[`(letrec-values ([,idss ,rhss] ...) ,bodys ...)
`(letrec-values ,(for/list ([ids (in-list idss)]
[rhs (in-list rhss)])
`[,ids ,(convert rhs)])
,@(convert-body bodys))]
[`(if ,tst ,thn ,els)
`(if ,(convert tst) ,(convert thn) ,(convert els))]
[`(with-continuation-mark* ,mode ,key ,val ,body)
`(with-continuation-mark* ,mode ,(convert key) ,(convert val) ,(convert body))]
[`(begin ,exps ...)
`(begin . ,(convert-body exps))]
[`(begin-unsafe ,exps ...)
`(begin-unsafe . ,(convert-body exps))]
[`(begin0 ,exps ...)
`(begin0 . ,(convert-body exps))]
[`(set! ,id ,rhs)
`(set! ,id ,(convert rhs))]
[`(#%variable-reference) v]
[`(#%variable-reference ,_) v]
[`(,rator ,exps ...)
`(,(convert rator) ,@(convert-body exps))]
[`,_
(cond
[(and (not (symbol? v))
(lift-quoted? v))
(convert `(quote ,v))]
[else v])])))
(define (convert-body body)
(for/list ([e (in-list body)])
(convert e)))
(define (convert-function-body body)
;; Detect the function-name pattern and avoid
;; mangling it:
(match body
[`((begin (quote ,name) ,body . ,bodys))
`((begin (quote ,name) ,@(convert-body (cons body bodys))))]
[`,_ (convert-body body)]))
(convert v)]
[else v])))
(values new-bodys
(reverse lift-bindings)))
;; v is a form or a list of forms
(define (convert-any? v)
(let convert-any? ([v v])
(match v
[`(quote ,q) (lift-quoted? q)]
[`(lambda ,formals ,body ...)
(convert-any? body)]
[`(case-lambda [,formalss ,bodys ...] ...)
(convert-any? bodys)]
[`(define-values ,ids ,rhs)
(convert-any? rhs)]
[`(let-values ([,idss ,rhss] ...) ,bodys ...)
(or (convert-any? rhss)
(convert-any? bodys))]
[`(letrec-values ([,idss ,rhss] ...) ,bodys ...)
(or (convert-any? rhss)
(convert-any? bodys))]
[`(if ,tst ,thn ,els)
(or (convert-any? tst)
(convert-any? thn)
(convert-any? els))]
[`(with-continuation-mark* ,_ ,key ,val ,body)
(or (convert-any? key)
(convert-any? val)
(convert-any? body))]
[`(begin ,exps ...)
(convert-any? exps)]
[`(begin-unsafe ,exps ...)
(convert-any? exps)]
[`(begin0 ,exps ...)
(convert-any? exps)]
[`(set! ,id ,rhs)
(convert-any? rhs)]
[`(#%variable-reference) #f]
[`(#%variable-reference ,_) #f]
[`(,exps ...)
(for/or ([exp (in-list exps)])
(convert-any? exp))]
[`,_ (and (not (symbol? v))
(lift-quoted? v))])))
;; Construct an expression to be lifted
(define (make-construct q add-lifted lifted-eq-constants lifted-equal-constants)
(define (quote? e) (and (pair? e) (eq? 'quote (car e))))
(define seen #hasheq())
(define (check-cycle v)
(when (hash-ref seen v #f)
(raise-arguments-error 'compile "cannot compile cyclic value"
"value" q))
(set! seen (hash-set seen v #t)))
(define (done-cycle v)
(set! seen (hash-remove seen v)))
(let make-construct ([q q])
(define lifted-constants (if (or (string? q) (bytes? q))
lifted-equal-constants
lifted-eq-constants))
(cond
[(hash-ref lifted-constants q #f)
=> (lambda (id) id)]
[else
(define rhs
(cond
[(path? q)
`(bytes->path ,(path->bytes q)
',(path-convention-type q))]
[(regexp? q)
`(,(if (pregexp? q) 'pregexp 'regexp) ,(object-name q))]
[(srcloc? q)
`(unsafe-make-srcloc
,(make-construct (srcloc-source q))
,(make-construct (srcloc-line q))
,(make-construct (srcloc-column q))
,(make-construct (srcloc-position q))
,(make-construct (srcloc-span q)))]
[(byte-regexp? q)
`(,(if (byte-pregexp? q) 'byte-pregexp 'byte-regexp) ,(object-name q))]
[(keyword? q)
`(string->keyword ,(keyword->string q))]
[(hash? q)
(define mut? (not (immutable? q)))
(when mut? (check-cycle q))
(define new-q
`(,(cond
[(hash-eq? q) 'hasheq]
[(hash-eqv? q) 'hasheqv]
[else 'hash])
,@(apply append
(for/list ([(k v) (in-hash q)])
(list (make-construct k)
(make-construct v))))))
(when mut? (done-cycle q))
new-q]
[(string? q) `(datum-intern-literal ,q)]
[(bytes? q) `(datum-intern-literal ,q)]
[(pair? q)
(if (list? q)
(let ([args (map make-construct q)])
(if (andmap quote? args)
`(quote ,q)
`(list ,@(map make-construct q))))
(let ([a (make-construct (car q))]
[d (make-construct (cdr q))])
(if (and (quote? a) (quote? d))
`(quote ,q)
`(cons ,a ,d))))]
[(vector? q)
(let ([args (map make-construct (vector->list q))])
`(vector->immutable-vector
,(if (and (andmap quote? args)
(not (impersonator? q)))
`(quote ,q)
`(vector ,@args))))]
[(box? q)
(let ([arg (make-construct (unbox q))])
`(box-immutable ,arg))]
[(prefab-struct-key q)
=> (lambda (key)
(define mut? (not (prefab-key-all-fields-immutable? key)))
(when mut? (check-cycle q))
(define new-q
`(make-prefab-struct ',key ,@(map make-construct
(cdr (vector->list (struct->vector q))))))
(when mut? (done-cycle q))
new-q)]
[(extflonum? q)
`(string->number ,(format "~a" q) 10 'read)]
[else
;; Assume serializable in-place:
`(quote ,q)]))
(cond
[(and (quote? rhs)
(not (lift-quoted? (cadr rhs))))
rhs]
[else
(define id (add-lifted rhs))
(hash-set! lifted-constants q id)
id])])))
(define (lift-quoted? q)
(not (or (and (exact-integer? q)
;; always a fixnum:
(<= (- (expt 2 29)) q (sub1 (expt 2 29))))
(boolean? q)
(null? q)
(void? q))))

View File

@ -32,7 +32,7 @@
(unless (eof-object? cmd)
(get-u8 in) ; newline
(let-values ([(o get) (open-bytevector-output-port)])
(let ([sfd-paths
(let ([literals
(case (integer->char cmd)
[(#\c #\u)
(call-with-fasled
@ -41,7 +41,7 @@
(parameterize ([optimize-level (if (fx= cmd (char->integer #\u))
3
(optimize-level))])
(compile-to-port (list `(lambda () ,v)) o #f #f #f (string->symbol target) #f pred))))]
(compile-to-port (list v) o #f #f #f (string->symbol target) #f pred))))]
[(#\f)
;; Reads host fasl format, then writes target fasl format
(call-with-fasled
@ -54,11 +54,11 @@
(let ([result (get)])
(put-num out (bytevector-length result))
(put-bytevector out result)
(let ([len (vector-length sfd-paths)])
(let ([len (vector-length literals)])
(put-num out len)
(let loop ([i 0])
(unless (fx= i len)
(put-num out (vector-ref sfd-paths i))
(put-num out (vector-ref literals i))
(loop (fx+ i 1)))))
(flush-output-port out)))
(loop)))))))
@ -76,30 +76,41 @@
;; ----------------------------------------
(define-record-type path-placeholder
(define-record-type literal-placeholder
(fields pos))
(define (call-with-fasled in proc)
(let* ([fasled-bv (get-bytevector-n in (get-num in))]
[num-sfd-paths (get-num in)]
[sfd-paths (list->vector
(let loop ([i 0])
(if (fx= i num-sfd-paths)
'()
(cons (make-path-placeholder i)
(loop (fx+ i 1))))))]
[literals-bv (get-bytevector-n in (get-num in))]
[transparent-placeholders (make-eq-hashtable)]
[literals (let ([vec (fasl-read (open-bytevector-input-port literals-bv))])
;; Use a placeholder for opaque literals that could not be
;; communicated from the Racket world. "Transparent" literals
;; are things like strings and bytevectors that can affect
;; compilation, since code might be specialized to a string
;; or bytevector literal.
(let loop ([i 0])
(if (fx= i (vector-length vec))
vec
(let ([e (vector-ref vec i)]
[ph (make-literal-placeholder i)])
(cond
[(not e) (vector-set! vec i ph)]
[else (hashtable-set! transparent-placeholders e ph)])
(loop (fx+ i 1))))))]
[used-placeholders '()]
;; v is the Chez Scheme value communicated from the client,
;; but with each path replace by a `path-placeholder`:
;; but with each opaque literal replaced by a `literal-placeholder`:
[v (fasl-read (open-bytevector-input-port fasled-bv)
'load
sfd-paths)])
literals)])
(proc v
(lambda (a)
(and (path-placeholder? a)
(begin
(set! used-placeholders (cons a used-placeholders))
#t))))
;; Return indices of paths used in new fasled output, in the
;; order that they're used
(list->vector (map path-placeholder-pos used-placeholders))))
(let ([a (eq-hashtable-ref transparent-placeholders a a)])
(and (literal-placeholder? a)
(begin
(set! used-placeholders (cons a used-placeholders))
#t)))))
;; Return indices of literals used in new fasled output in the order
;; that they're used.
(list->vector (reverse (map literal-placeholder-pos used-placeholders)))))

View File

@ -113,8 +113,8 @@
[whole-program?
(unless (= 1 (length deps))
(error 'compile-file "expected a single dependency for whole-program compilation"))
(printf "Whole-program optimizaton for Racket core...\n")
(printf " [If this runs out of memory, try configuring with `--disable-wpo`]\n")
(printf "Whole-program optimization for Racket core...\n")
(printf "[If this step runs out of memory, try configuring with `--disable-wpo`]\n")
(unless (equal? build-dir "")
(library-directories (list (cons "." build-dir))))
(compile-whole-program (car deps) src #t)]

View File

@ -5,7 +5,6 @@
racket/file
racket/extflonum
"../schemify/schemify.rkt"
"../schemify/serialize.rkt"
"../schemify/known.rkt"
"../schemify/lift.rkt"
"../schemify/reinfer-name.rkt"
@ -13,7 +12,6 @@
"known.rkt")
(define skip-export? #f)
(define for-cify? #f)
(define unsafe-mode? #f)
(define-values (in-file out-file)
@ -21,8 +19,6 @@
#:once-each
[("--skip-export") "Don't generate an `export` form"
(set! skip-export? #t)]
[("--for-cify") "Keep `make-struct-type` as-is, etc."
(set! for-cify? #t)]
[("--unsafe") "Compile for unsafe mode"
(set! unsafe-mode? #t)]
#:args
@ -111,8 +107,7 @@
(lift (car v))
(lift (cdr v))]))
(unless for-cify?
(lift l))
(lift l)
(define prim-knowns (get-prim-knowns))
(define primitives (get-primitives))
@ -121,97 +116,86 @@
;; Convert:
(define schemified-body
(let ()
(define-values (bodys/constants-lifted lifted-constants)
(if for-cify?
(begin
(printf "Serializable...\n")
(time (convert-for-serialize l for-cify?)))
(values (recognize-inferred-names l) null)))
(define bodys (recognize-inferred-names l))
(printf "Schemify...\n")
(define body
(time
(schemify-body bodys/constants-lifted prim-knowns primitives #hasheq() #hasheq() for-cify? unsafe-mode?
(schemify-body bodys prim-knowns primitives #hasheq() #hasheq() #f unsafe-mode?
#t ; no-prompt?
#f))) ; explicit-unnamed?
(printf "Lift...\n")
;; Lift functions to avoid closure creation:
(define lifted-body
(time
(lift-in-schemified-body body #t)))
(append (for/list ([p (in-list lifted-constants)])
(cons 'define p))
lifted-body)))
(time
(lift-in-schemified-body body #t))))
;; ----------------------------------------
(unless for-cify?
;; Set a hook to redirect literal regexps and
;; hash tables to lifted bindings
(pretty-print-size-hook
(lambda (v display? out)
(cond
[(and (pair? v)
(pair? (cdr v))
(eq? 'quote (car v))
(or (regexp? (cadr v))
(byte-regexp? (cadr v))
(pregexp? (cadr v))
(byte-pregexp? (cadr v))
(hash? (cadr v))
(nested-hash? (cadr v))
(keyword? (cadr v))
(list-of-keywords? (cadr v))
(extflonum? (cadr v))))
10]
[(and (pair? v)
(pair? (cdr v))
(eq? 'quote (car v))
(void? (cadr v)))
6]
[(bytes? v) (* 3 (bytes-length v))]
[(and (symbol? v) (regexp-match? #rx"#" (symbol->string v)))
(+ 2 (string-length (symbol->string v)))]
[(char? v) 5]
[(single-flonum? v) 5]
[(or (keyword? v)
(regexp? v)
(pregexp? v)
(hash? v))
(error 'lift "value that needs lifting is in an unrecognized context: ~v" v)]
[else #f])))
;; Set a hook to redirect literal regexps and
;; hash tables to lifted bindings
(pretty-print-size-hook
(lambda (v display? out)
(cond
[(and (pair? v)
(pair? (cdr v))
(eq? 'quote (car v))
(or (regexp? (cadr v))
(byte-regexp? (cadr v))
(pregexp? (cadr v))
(byte-pregexp? (cadr v))
(hash? (cadr v))
(nested-hash? (cadr v))
(keyword? (cadr v))
(list-of-keywords? (cadr v))
(extflonum? (cadr v))))
10]
[(and (pair? v)
(pair? (cdr v))
(eq? 'quote (car v))
(void? (cadr v)))
6]
[(bytes? v) (* 3 (bytes-length v))]
[(and (symbol? v) (regexp-match? #rx"#" (symbol->string v)))
(+ 2 (string-length (symbol->string v)))]
[(char? v) 5]
[(single-flonum? v) 5]
[(or (keyword? v)
(regexp? v)
(pregexp? v)
(hash? v))
(error 'lift "value that needs lifting is in an unrecognized context: ~v" v)]
[else #f])))
;; This hook goes with `pretty-print-size-hook`
(pretty-print-print-hook
(lambda (v display? out)
(cond
[(and (pair? v)
(eq? 'quote (car v))
(or (regexp? (cadr v))
(byte-regexp? (cadr v))
(pregexp? (cadr v))
(byte-pregexp? (cadr v))
(hash? (cadr v))
(nested-hash? (cadr v))
(keyword? (cadr v))
(list-of-keywords? (cadr v))
(extflonum? (cadr v))))
(write (hash-ref lifts (cadr v)) out)]
[(and (pair? v)
(pair? (cdr v))
(eq? 'quote (car v))
(void? (cadr v)))
(write '(void) out)]
[(bytes? v)
(display "#vu8")
(write (bytes->list v) out)]
[(symbol? v)
(write-string (format "|~a|" v) out)]
[(char? v)
(write-string (format "#\\x~x" (char->integer v)) out)]
[(single-flonum? v)
(write (real->double-flonum v) out)]
[else #f]))))
;; This hook goes with `pretty-print-size-hook`
(pretty-print-print-hook
(lambda (v display? out)
(cond
[(and (pair? v)
(eq? 'quote (car v))
(or (regexp? (cadr v))
(byte-regexp? (cadr v))
(pregexp? (cadr v))
(byte-pregexp? (cadr v))
(hash? (cadr v))
(nested-hash? (cadr v))
(keyword? (cadr v))
(list-of-keywords? (cadr v))
(extflonum? (cadr v))))
(write (hash-ref lifts (cadr v)) out)]
[(and (pair? v)
(pair? (cdr v))
(eq? 'quote (car v))
(void? (cadr v)))
(write '(void) out)]
[(bytes? v)
(display "#vu8")
(write (bytes->list v) out)]
[(symbol? v)
(write-string (format "|~a|" v) out)]
[(char? v)
(write-string (format "#\\x~x" (char->integer v)) out)]
[(single-flonum? v)
(write (real->double-flonum v) out)]
[else #f])))
;; ----------------------------------------

View File

@ -28,9 +28,7 @@
(thread)
(regexp)
(io)
(linklet)
(only (schemify)
force-unfasl))
(linklet))
(include "place-register.ss")
(define-place-register-define define expander-register-start expander-register-count)

View File

@ -14,6 +14,4 @@
(thread)
(io)
(regexp)
(linklet)
(only (schemify)
force-unfasl)))
(linklet)))

View File

@ -180,7 +180,7 @@
(define post-lambda-on? (getenv "PLT_LINKLET_SHOW_POST_LAMBDA"))
(define post-interp-on? (getenv "PLT_LINKLET_SHOW_POST_INTERP"))
(define jit-demand-on? (getenv "PLT_LINKLET_SHOW_JIT_DEMAND"))
(define paths-on? (getenv "PLT_LINKLET_SHOW_PATHS"))
(define literals-on? (getenv "PLT_LINKLET_SHOW_LITERALS"))
(define known-on? (getenv "PLT_LINKLET_SHOW_KNOWN"))
(define cp0-on? (getenv "PLT_LINKLET_SHOW_CP0"))
(define assembly-on? (getenv "PLT_LINKLET_SHOW_ASSEMBLY"))
@ -190,7 +190,7 @@
post-lambda-on?
post-interp-on?
jit-demand-on?
paths-on?
literals-on?
known-on?
cp0-on?
assembly-on?
@ -237,24 +237,27 @@
(call-with-system-wind (lambda () (interpret e))))
(define (fasl-write* s o)
(call-with-system-wind (lambda () (fasl-write s o))))
(define (fasl-write/paths* s o)
(define (fasl-write/literals* s quoteds o)
(call-with-system-wind (lambda ()
(call-getting-sfd-paths
(call-getting-literals
quoteds
(lambda (pred)
(fasl-write s o pred))))))
(define (fasl-write-code* s o)
(define (fasl-write-code* s quoteds o)
(call-with-system-wind (lambda ()
(parameterize ([fasl-compressed compress-code?])
(call-getting-sfd-paths
(call-getting-literals
quoteds
(lambda (pred)
(fasl-write s o pred 'omit-rtds)))))))
(define (compile-to-port* s o unsafe?)
(define (compile-to-port* s quoteds o unsafe?)
(call-with-system-wind (lambda ()
(parameterize ([fasl-compressed compress-code?]
[optimize-level (if unsafe?
3
(optimize-level))])
(call-getting-sfd-paths
(call-getting-literals
quoteds
(lambda (pred)
(compile-to-port s o #f #f #f (machine-type) #f pred 'omit-rtds)))))))
(define (expand/optimize* e unsafe?)
@ -264,14 +267,18 @@
(optimize-level))])
(#%expand/optimize e)))))
(define (call-getting-sfd-paths proc)
(let ([sfd-paths '()])
(define (call-getting-literals quoteds proc)
;; `quoteds` is a list of literal values detected by schemify,
;; but we may discover srclocs attached as procedure names
(let ([literals '()])
(proc (lambda (v)
(and (path? v)
(and (or (srcloc? v)
(and quoteds
(hash-ref quoteds v #f)))
(begin
(set! sfd-paths (cons v sfd-paths))
(set! literals (cons v literals))
#t))))
(list->vector (reverse sfd-paths))))
(list->vector (reverse literals))))
(define (eval/foreign e mode)
(performance-region
@ -293,66 +300,60 @@
(install-primitives-table! primitives))
;; Runs the result of `interpretable-jitified-linklet`
(define (run-interpret s paths)
(interpret-linklet s paths))
(define (run-interpret s)
(interpret-linklet s))
(define (compile-to-proc s paths format unsafe?)
(define (compile-to-proc s format unsafe?)
(if (eq? format 'interpret)
(run-interpret s paths)
(let ([proc (compile* s unsafe?)])
(if (null? paths)
proc
(#%apply proc paths)))))
(run-interpret s)
(compile* s unsafe?)))
;; returns code bytevector and sfd-paths vector
(define (compile*-to-bytevector s unsafe?)
;; returns code bytevector and literals vector
(define (compile*-to-bytevector s quoteds unsafe?)
(let-values ([(o get) (open-bytevector-output-port)])
(let ([sfd-paths (compile-to-port* (list `(lambda () ,s)) o unsafe?)])
(values (get) sfd-paths))))
(let ([literals (compile-to-port* (list s) quoteds o unsafe?)])
(values (get) literals))))
;; returns code bytevector and sfd-paths vector
(define (compile-to-bytevector s format unsafe?)
;; returns code bytevector and literals vector
(define (compile-to-bytevector s quoteds format unsafe?)
(cond
[(eq? format 'interpret)
(let-values ([(o get) (open-bytevector-output-port)])
(let ([sfd-paths (fasl-write-code* s o)])
(values (get) sfd-paths)))]
[else (compile*-to-bytevector s unsafe?)]))
(let ([literals (fasl-write-code* s quoteds o)])
(values (get) literals)))]
[else (compile*-to-bytevector s quoteds unsafe?)]))
;; returns code bytevector and sfd-paths vector
(define (cross-compile-to-bytevector machine s format unsafe?)
;; returns code bytevector and literals vector
(define (cross-compile-to-bytevector machine s quoteds format unsafe?)
(cond
[(eq? format 'interpret) (cross-fasl-to-string machine s)]
[else (cross-compile machine s unsafe?)]))
[(eq? format 'interpret) (cross-fasl-to-string machine s quoteds)]
[else (cross-compile machine s quoteds unsafe?)]))
(define (eval-from-bytevector bv paths sfd-paths format)
(define (eval-from-bytevector bv literals format)
(add-performance-memory! 'faslin-code (bytevector-length bv))
(cond
[(eq? format 'interpret)
(let ([r (performance-region
'faslin-code
(fasl-read (open-bytevector-input-port bv) 'load sfd-paths))])
(performance-region
'outer
(run-interpret r paths)))]
(fasl-read (open-bytevector-input-port bv) 'load literals))])
(run-interpret r))]
[else
(let ([proc (performance-region
'faslin-code
(code-from-bytevector bv sfd-paths))])
(if (null? paths)
proc
(#%apply proc paths)))]))
(performance-region
'faslin-code
(code-from-bytevector bv literals))]))
(define (code-from-bytevector bv sfd-paths)
(define (code-from-bytevector bv literals)
(let ([i (open-bytevector-input-port bv)])
(let ([r (load-compiled-from-port i sfd-paths)])
(performance-region
'outer
(r)))))
(load-compiled-from-port i literals)))
(define (extract-literals v)
(performance-region
'faslin-literals
(force-unfasl-literals v)))
(define-record-type wrapped-code
(fields (mutable content) ; bytevector for 'lambda mode; annotation or (vector hash annotation) for 'jit mode
sfd-paths
literals
arity-mask
name)
(nongenerative #{wrapped-code p6o2m72rgmi36pm8vy559b-1}))
@ -365,7 +366,7 @@
'on-demand
(cond
[(bytevector? f)
(let* ([f (code-from-bytevector f (wrapped-code-sfd-paths wc))])
(let* ([f (code-from-bytevector f (wrapped-code-literals wc))])
(wrapped-code-content-set! wc f)
f)]
[else
@ -427,8 +428,7 @@
(define-record-type linklet
(fields (mutable code) ; the procedure or interpretable form
paths ; list of paths and other fasled; if non-empty, `code` expects them as arguments
sfd-paths ; vector of additional source-location paths intercepted during fasl
literals ; vector of literals, including paths, that have to be serialized by racket/fasl
format ; 'compile or 'interpret (where the latter may have compiled internal parts)
(mutable preparation) ; 'faslable, 'faslable-strict, 'faslable-unsafe, 'callable, 'lazy, or (cons 'cross <machine>)
importss-abi ; ABI for each import, in parallel to `importss`
@ -440,8 +440,7 @@
(define (set-linklet-code linklet code preparation)
(make-linklet code
(linklet-paths linklet)
(linklet-sfd-paths linklet)
(linklet-literals linklet)
(linklet-format linklet)
preparation
(linklet-importss-abi linklet)
@ -450,10 +449,9 @@
(linklet-importss linklet)
(linklet-exports linklet)))
(define (set-linklet-paths linklet paths sfd-paths)
(define (set-linklet-literals linklet literals)
(make-linklet (linklet-code linklet)
paths
sfd-paths
literals
(linklet-format linklet)
(linklet-preparation linklet)
(linklet-importss-abi linklet)
@ -464,8 +462,7 @@
(define (set-linklet-preparation linklet preparation)
(make-linklet (linklet-code linklet)
(linklet-paths linklet)
(linklet-sfd-paths linklet)
(linklet-literals linklet)
(linklet-format linklet)
preparation
(linklet-importss-abi linklet)
@ -509,6 +506,7 @@
(define quick-mode? (or default-compile-quick?
(and (not serializable?)
(#%memq 'quick options))))
(define serializable?-box (and serializable? (box #f)))
(define sfd-cache (if serializable?
;; For determinism: a fresh, non-weak cache per linklet
(make-hash)
@ -530,7 +528,7 @@
;; Convert the linklet S-expression to a `lambda` S-expression:
(define-values (impl-lam importss exports new-import-keys importss-abi exports-info)
(schemify-linklet (show "linklet" c)
serializable?
serializable?-box
(not (#%memq 'uninterned-literal options))
(eq? format 'interpret)
(|#%app| compile-allow-set!-undefined)
@ -583,44 +581,39 @@
'compile-nested
(let ([expr (show lambda-on? "lambda" (correlated->annotation expr serializable? sfd-cache))])
(if serializable?
(let-values ([(code sfd-paths) (if cross-machine
(cross-compile cross-machine expr unsafe?)
(compile*-to-bytevector expr unsafe?))])
(make-wrapped-code code sfd-paths arity-mask (extract-inferred-name expr name)))
(let ([quoteds (unbox serializable?-box)])
(let-values ([(code literals) (if cross-machine
(cross-compile cross-machine expr quoteds unsafe?)
(compile*-to-bytevector expr quoteds unsafe?))])
(make-wrapped-code code literals arity-mask (extract-inferred-name expr name))))
(compile* expr unsafe?)))))])))]))
(define-values (paths impl-lam/paths)
(if serializable?
(extract-paths-and-fasls-from-schemified-linklet impl-lam/jitified (eq? format 'compile))
(values '() impl-lam/jitified)))
(define impl-lam/interpable
(let ([impl-lam (case (and jitify-mode?
linklet-compilation-mode)
[(mach) (show post-lambda-on? "post-lambda" impl-lam/paths)]
[else (show "schemified" impl-lam/paths)])])
[(mach) (show post-lambda-on? "post-lambda" impl-lam/jitified)]
[else (show "schemified" impl-lam/jitified)])])
(if (eq? format 'interpret)
(interpretable-jitified-linklet impl-lam serializable?)
(correlated->annotation impl-lam serializable? sfd-cache))))
(when paths-on?
(show "paths" paths))
(when known-on?
(show "known" (hash-map exports-info (lambda (k v) (list k v)))))
(when (and cp0-on? (eq? format 'compile))
(show "cp0" (expand/optimize* (correlated->annotation impl-lam/paths) unsafe?)))
(show "cp0" (expand/optimize* (correlated->annotation impl-lam/jitified) unsafe?)))
(performance-region
'compile-linklet
;; Create the linklet:
(let ([impl (show (and (eq? format 'interpret) post-interp-on?) "post-interp" impl-lam/interpable)])
(let-values ([(code sfd-paths)
(let-values ([(code literals)
(if serializable?
(if cross-machine
(cross-compile-to-bytevector cross-machine impl format unsafe?)
(compile-to-bytevector impl format unsafe?))
(values (compile-to-proc impl paths format unsafe?) '#()))])
(when paths-on?
(show "source paths" sfd-paths))
(let ([quoteds (unbox serializable?-box)])
(if cross-machine
(cross-compile-to-bytevector cross-machine impl quoteds format unsafe?)
(compile-to-bytevector impl quoteds format unsafe?)))
(values (compile-to-proc impl format unsafe?) '#()))])
(when literals-on?
(show "literals" literals))
(let ([lk (make-linklet code
paths
sfd-paths
literals
format
(if serializable? (if cross-machine (cons 'cross cross-machine) 'faslable) 'callable)
importss-abi
@ -680,8 +673,7 @@
[(faslable-strict)
(set-linklet-code linklet
(eval-from-bytevector (linklet-code linklet)
(linklet-paths linklet)
(linklet-sfd-paths linklet)
(extract-literals (linklet-literals linklet))
(linklet-format linklet))
'callable)]
[(faslable-unsafe)
@ -719,8 +711,7 @@
(when (eq? 'lazy (linklet-preparation linklet))
;; Trigger lazy conversion of code from bytevector
(let ([code (eval-from-bytevector (linklet-code linklet)
(linklet-paths linklet)
(linklet-sfd-paths linklet)
(extract-literals (linklet-literals linklet))
(linklet-format linklet))])
(with-interrupts-disabled
(when (eq? 'lazy (linklet-preparation linklet))
@ -740,8 +731,7 @@
(if (eq? 'callable (linklet-preparation linklet))
(linklet-code linklet)
(eval-from-bytevector (linklet-code linklet)
(linklet-paths linklet)
(linklet-sfd-paths linklet)
(extract-literals (linklet-literals linklet))
(linklet-format linklet)))
(make-variable-reference target-instance #f)
(extract-imported-variabless target-instance
@ -771,7 +761,7 @@
(raise-argument-error 'linklet-fasled-code+arguments "linklet?" linklet))
(case (linklet-preparation linklet)
[(faslable faslable-strict faslable-unsafe lazy)
(values (linklet-format linklet) (linklet-code linklet) (linklet-sfd-paths linklet) (linklet-paths linklet))]
(values (linklet-format linklet) (linklet-code linklet) (extract-literals (linklet-literals linklet)))]
[else (values #f #f #f #f)]))
(define (linklet-interpret-jitified? v)

View File

@ -75,7 +75,14 @@
(hash-ref sfd-cache src #f))
;; We'll use a file-position object in source objects, so
;; the sfd checksum doesn't matter
(let ([sfd (source-file-descriptor src 0)])
(let ([sfd (source-file-descriptor
;; Wrap path as a srcloc so that absolute paths are just
;; dropped when serializing the path (while paths relative
;; to the containing source can be preserved):
(if (path? src)
(srcloc src #f #f #f #f)
src)
0)])
(with-interrupts-disabled
(hash-set! sfd-cache src sfd))
sfd)))

View File

@ -52,22 +52,23 @@
(unsafe-place-local-set! cross-machine-compiler-cache
(cons a (unsafe-place-local-ref cross-machine-compiler-cache)))))
(define (do-cross cmd machine v)
(define (do-cross cmd machine v quoteds)
(let* ([a (find-cross 'cross-compile machine)]
[ch (cadr a)]
[reply-ch (make-channel)])
(channel-put ch (list cmd
v
quoteds
reply-ch))
(let ([bv+paths (channel-get reply-ch)])
(let ([bv+literals (channel-get reply-ch)])
(cache-cross-compiler a)
(values (car bv+paths) (cdr bv+paths)))))
(values (car bv+literals) (cdr bv+literals)))))
(define (cross-compile machine v unsafe?)
(do-cross (if unsafe? 'u 'c) machine v))
(define (cross-compile machine v quoteds unsafe?)
(do-cross (if unsafe? 'u 'c) machine v quoteds))
(define (cross-fasl-to-string machine v)
(do-cross 'f machine v))
(define (cross-fasl-to-string machine v quoteds)
(do-cross 'f machine v quoteds))
;; Start a compiler as a Racket thread under the root custodian.
;; Using Racket's scheduler lets us use the event and I/O system,
@ -114,33 +115,47 @@
(let ([msg (channel-get msg-ch)])
;; msg is (list <command> <value> <reply-channel>)
(write-string (#%format "~a\n" (car msg)) to)
(let-values ([(bv sfd-paths) (fasl-to-bytevector (cadr msg))])
;; We can't send paths to the cross compiler, but we can tell it
;; how many paths there were, and the cross compiler can report
;; which of those remain used in the compiled form
(write-bytes (integer->integer-bytes (bytevector-length bv) 8 #f #f) to)
(write-bytes bv to)
(write-bytes (integer->integer-bytes (vector-length sfd-paths) 8 #f #f) to)
(flush-output to)
(let-values ([(bv literals) (fasl-to-bytevector (cadr msg) (caddr msg))])
;; We can't send all literals to the cross compiler, but we can send
;; strings and byte stringa, which might affect compilation. Otherwise,
;; we report the existence of other literals, and the cross compiler can
;; report which of those remain used in the compiled form.
(let-values ([(literals-bv ignored) (fasl-to-bytevector (strip-opaque literals) #f)])
(write-bytes (integer->integer-bytes (bytevector-length bv) 8 #f #f) to)
(write-bytes bv to)
(write-bytes (integer->integer-bytes (bytevector-length literals-bv) 8 #f #f) to)
(write-bytes literals-bv to)
(flush-output to))
(let* ([read-num (lambda ()
(integer-bytes->integer (read-bytes 8 from) #f #f))]
[len (read-num)]
[bv (read-bytes len from)]
[kept-sfd-paths-count (read-num)] ; number of used-path indices
[kept-sfd-paths (list->vector
(let loop ([i 0])
(if (fx= i kept-sfd-paths-count)
'()
(cons (vector-ref sfd-paths (read-num))
(loop (fx+ i 1))))))])
(channel-put (caddr msg) (cons bv kept-sfd-paths))))
[kept-literals-count (read-num)] ; number of used-literal indices
[kept-literals (list->vector
(let loop ([i 0])
(if (fx= i kept-literals-count)
'()
(cons (vector-ref literals (read-num))
(loop (fx+ i 1))))))])
(channel-put (cadddr msg) (cons bv kept-literals))))
(loop)))))))
(list machine msg-ch))))
(define (fasl-to-bytevector v)
(define (fasl-to-bytevector v quoteds)
(let-values ([(o get) (open-bytevector-output-port)])
(let ([sfd-paths (fasl-write/paths* v o)])
(values (get) sfd-paths))))
(let ([literals (fasl-write/literals* v quoteds o)])
(values (get) literals))))
(define (strip-opaque vec)
(let ([vec2 (make-vector (vector-length vec) #f)])
(let loop ([i 0])
(unless (fx= i (vector-length vec))
(let ([e (vector-ref vec i)])
(when (or (string? e)
(bytevector? e))
(vector-set! vec2 i e)))
(loop (fx+ i 1))))
vec2))
(define (find-exe exe)
(let-values ([(base name dir?) (split-path exe)])

View File

@ -106,9 +106,9 @@
[name-len (apply max (hash-table-map region-times (lambda (k v) (string-length (symbol->string k)))))]
[len (string-length (number->string total))]
[gc-len (string-length (number->string gc-total))]
[categories '((read (read-bundle faslin-code))
[categories '((read (read-bundle faslin-code faslin-literals))
(comp-ffi (comp-ffi-call comp-ffi-back))
(run (instantiate outer))
(run (instantiate))
(compile (compile-linklet compile-nested))
(compile-pass (regalloc other)))]
[region-subs (make-eq-hashtable)]

View File

@ -4,7 +4,7 @@
'read-linklet
(let* ([len (integer-bytes->integer (read-bytes 4 in) #f #f)]
[bstr (read-bytes len in)])
(adjust-linklet-bundle-laziness-and-paths
(adjust-linklet-bundle-laziness-and-literals
(fasl-read (open-bytevector-input-port bstr))))))
(define read-on-demand-source
@ -18,7 +18,7 @@
v)
'read-on-demand-source))
(define (adjust-linklet-bundle-laziness-and-paths ls)
(define (adjust-linklet-bundle-laziness-and-literals ls)
(let loop ([ls ls] [ht (hasheq)])
(cond
[(null? ls) ht]
@ -30,7 +30,7 @@
key
(if (linklet? val)
(adjust-linklet-laziness
(decode-linklet-paths val))
(decode-linklet-literals val))
val))))])))
(define (adjust-linklet-laziness linklet)
@ -50,14 +50,10 @@
[else
'faslable-strict])))
(define (decode-linklet-paths linklet)
(let ([paths (linklet-paths linklet)]
[sfd-paths (linklet-sfd-paths linklet)])
(define (decode-linklet-literals linklet)
(let ([literals (linklet-literals linklet)])
(cond
[(and (null? paths)
(fxzero? (#%vector-length sfd-paths)))
linklet]
[(vector? literals) linklet]
[else
(set-linklet-paths linklet
(#%map compiled-path->path paths)
(#%vector-map compiled-path->path sfd-paths))])))
(set-linklet-literals linklet
(unfasl-literals/lazy literals))])))

View File

@ -4,10 +4,11 @@
#vu8(99 104 101 122 45 115 99 104 101 109 101))
(define (write-linklet-bundle-hash ht dest-o)
(let-values ([(ls cross-machine) (encode-linklet-paths ht)])
(let-values ([(ls cross-machine) (encode-linklet-literals ht)])
(let ([bstr (if cross-machine
(let-values ([(bstr sfd-paths) (cross-fasl-to-string cross-machine ls)])
;; sfd-paths should be empty
(let-values ([(bstr literals) (cross-fasl-to-string cross-machine ls #f)])
(unless (equal? literals '#())
(#%error 'write-linklet "cross fasl produced additional literals"))
bstr)
(let-values ([(o get) (open-bytevector-output-port)])
(fasl-write* ls o)
@ -15,37 +16,35 @@
(write-bytes (integer->integer-bytes (bytes-length bstr) 4 #f #f) dest-o)
(write-bytes bstr dest-o))))
(define (encode-linklet-paths orig-ht)
(let ([path->compiled-path (make-path->compiled-path 'write-linklet)])
(let loop ([i (hash-iterate-first orig-ht)] [accum '()] [cross-machine #f])
(cond
[(not i) (values accum cross-machine)]
[else
(let-values ([(key v) (hash-iterate-key+value orig-ht i)])
(when (linklet? v) (check-fasl-preparation v))
(let ([new-v (cond
(define (encode-linklet-literals orig-ht)
(let loop ([i (hash-iterate-first orig-ht)] [accum '()] [cross-machine #f])
(cond
[(not i) (values accum cross-machine)]
[else
(let-values ([(key v) (hash-iterate-key+value orig-ht i)])
(when (linklet? v) (check-fasl-preparation v))
(let ([new-v (cond
[(linklet? v)
(cond
[(or (pair? (linklet-paths v))
(fxpositive? (#%vector-length (linklet-sfd-paths v))))
(adjust-cross-perparation
(set-linklet-paths
v
(#%map path->compiled-path
(linklet-paths v))
(#%vector-map (lambda (p) (path->compiled-path p #t))
(linklet-sfd-paths v))))]
[else (adjust-cross-perparation v)])]
(adjust-cross-perparation
(let ([literals (linklet-literals v)])
(cond
[(and (#%vector? literals)
(fx= 0 (#%vector-length literals)))
v]
[else
(set-linklet-literals
v
(fasl-literals (extract-literals literals) uninterned-symbol?))])))]
[else v])])
(when (linklet? new-v)
(linklet-pack-exports-info! new-v))
(let ([accum (cons* key new-v accum)])
(loop (hash-iterate-next orig-ht i)
accum
(or cross-machine
(and (linklet? v)
(let ([prep (linklet-preparation v)])
(and (pair? prep) (cdr prep)))))))))]))))
(when (linklet? new-v)
(linklet-pack-exports-info! new-v))
(let ([accum (cons* key new-v accum)])
(loop (hash-iterate-next orig-ht i)
accum
(or cross-machine
(and (linklet? v)
(let ([prep (linklet-preparation v)])
(and (pair? prep) (cdr prep)))))))))])))
;; Before fasl conversion, change 'cross or 'faslable-unsafe to 'faslable
(define (adjust-cross-perparation l)

View File

@ -34,8 +34,6 @@
[make-pthread-parameter (known-procedure 2)]
[engine-block (known-procedure 1)]
[force-unfasl (known-procedure 2)]
[ptr-ref/int8 (known-procedure 8)]
[ptr-ref/uint8 (known-procedure 8)]
[ptr-ref/int16 (known-procedure 8)]

View File

@ -548,8 +548,8 @@
[make-will-executor (known-procedure/pure 1)]
[map (known-procedure -4)]
[max (known-procedure/folding -2)]
[mcar (known-procedure/no-prompt 2)]
[mcdr (known-procedure/no-prompt 2)]
[mcar (known-procedure/has-unsafe 2 'unsafe-mcar)]
[mcdr (known-procedure/has-unsafe 2 'unsafe-mcdr)]
[mcons (known-procedure/pure 4)]
[memory-order-acquire (known-procedure 1)]
[memory-order-release (known-procedure 1)]
@ -760,8 +760,8 @@
[semaphore? (known-procedure/pure/folding 2)]
[set-box! (known-procedure 4)]
[set-box*! (known-procedure/has-unsafe 4 'unsafe-set-box*!)]
[set-mcar! (known-procedure/no-prompt 4)]
[set-mcdr! (known-procedure/no-prompt 4)]
[set-mcar! (known-procedure/has-unsafe 4 'unsafe-set-mcar!)]
[set-mcdr! (known-procedure/has-unsafe 4 'unsafe-set-mcdr!)]
[set-phantom-bytes! (known-procedure/no-prompt 4)]
[set-port-next-location! (known-procedure 16)]
[sha1-bytes (known-procedure 14)]

View File

@ -668,7 +668,12 @@
[loc (and (cdr p)
(call-with-values (lambda ()
(let* ([src (cdr p)]
[path (source-file-descriptor-path (source-object-sfd src))])
[path (source-file-descriptor-path (source-object-sfd src))]
[path (if (srcloc? path)
;; The linklet layer wraps paths in `srcloc` to trigger specific
;; marshaling behavior
(srcloc-source path)
path)])
(if (source-object-line src)
(values path
(source-object-line src)

View File

@ -206,6 +206,13 @@
(#%$string-set-immutable! s)
s]))
(define (unsafe-vector*->immutable-vector! v)
(vector->immutable-vector v)
;; The implementation below is not right, because the vector
;; may contain elements allocated after the vector itself, and
;; wrong-way pointers are not supposed to show up in mutable
;; vectors. Maybe the GC should treat immutable vectors like
;; mutable ones, and then morphing to immutable would be ok.
#;
(cond
[(= (vector-length v) 0) (immutable-constant #())]
[else

File diff suppressed because it is too large Load Diff

View File

@ -21691,13 +21691,13 @@
(if (mpair? v_0)
(if (not print-graph?_0)
(if (not (eq? mode_0 0))
(let ((app_0 (mcdr v_0)))
(let ((app_0 (unsafe-mcdr v_0)))
(quick-no-graph?_0
config_0
mode_0
print-graph?_0
app_0
(let ((app_1 (mcar v_0)))
(let ((app_1 (unsafe-mcar v_0)))
(quick-no-graph?_0
config_0
mode_0
@ -22005,7 +22005,7 @@
counter_0
cycle?_0
ht_0
(mcar v_0)
(unsafe-mcar v_0)
mode_0)
(build-graph_0
checking-port_0
@ -22014,7 +22014,7 @@
counter_0
cycle?_0
ht_0
(mcdr v_0)
(unsafe-mcdr v_0)
mode_0)
(done!_0
constructor?_0
@ -22547,12 +22547,12 @@
(begin
(if (eq? max-length_2 'full)
'full
(if (if (null? (mcdr v_1)) (not unquoted?_0) #f)
(if (if (null? (unsafe-mcdr v_1)) (not unquoted?_0) #f)
(let ((max-length_3
(|#%app|
p_0
who_0
(mcar v_1)
(unsafe-mcar v_1)
mode_0
o_0
max-length_2
@ -22562,11 +22562,12 @@
(if curly?_0 "}" ")")
o_0
max-length_3))
(if (if (mpair? (mcdr v_1))
(if (if (mpair? (unsafe-mcdr v_1))
(if (let ((or-part_0 (not graph_0)))
(if or-part_0
or-part_0
(not (hash-ref graph_0 (mcdr v_1) #f))))
(not
(hash-ref graph_0 (unsafe-mcdr v_1) #f))))
(not unquoted?_0)
#f)
#f)
@ -22574,13 +22575,13 @@
(|#%app|
p_0
who_0
(mcar v_1)
(unsafe-mcar v_1)
mode_0
o_0
max-length_2
graph_0
config_0)))
(let ((app_0 (mcdr v_1)))
(let ((app_0 (unsafe-mcdr v_1)))
(loop_0
app_0
(write-string/max " " o_0 max-length_3))))
@ -22588,7 +22589,7 @@
(|#%app|
p_0
who_0
(mcar v_1)
(unsafe-mcar v_1)
mode_0
o_0
max-length_2
@ -22602,7 +22603,7 @@
(|#%app|
p_0
who_0
(mcdr v_1)
(unsafe-mcdr v_1)
mode_0
o_0
max-length_4

File diff suppressed because it is too large Load Diff

View File

@ -3,14 +3,14 @@
lift-in-schemified-linklet
jitify-schemified-linklet
xify
extract-paths-and-fasls-from-schemified-linklet
interpreter-link!
interpretable-jitified-linklet
interpret-linklet
linklet-bigger-than?
make-path->compiled-path
compiled-path->path
(rename [1/force-unfasl force-unfasl])
fasl-literal?
fasl-literals
unfasl-literals/lazy
force-unfasl-literals
prim-knowns
known-procedure
known-procedure/pure

View File

@ -76,7 +76,6 @@
call-with-module-prompt
make-pthread-parameter
engine-block
force-unfasl
make-record-type-descriptor
make-record-type-descriptor*
make-record-constructor-descriptor

View File

@ -0,0 +1,95 @@
#lang racket/base
(require racket/fasl
racket/unsafe/undefined
racket/extflonum)
(provide fasl-literal?
fasl-literals
unfasl-literals/lazy
force-unfasl-literals)
(define (fasl-literal? q need-exposed?)
(cond
[(impersonator? q) #t] ; i.e., strip impersonators when serializaing
[(path? q) #t]
[(regexp? q) #t]
[(srcloc? q) #t]
[(byte-regexp? q) #t]
[(keyword? q) #t]
[(hash? q) #t]
[(string? q) #t] ; to intern
[(bytes? q) #t] ; to intern
[(prefab-struct-key q) #t] ; to intern
[(need-exposed? q) #t] ; to expose to full linklet directory
;; No case for numbers, because they are historically not interned
;; on bytecode read, but extflonums are special
[(extflonum? q) #t]
;; Assume that anything else can be handled; rejecting
;; non-serializable values is someone else's problem
[else #f]))
(struct to-unfasl (bstr externals wrt))
(define (empty-literals? v)
(and (vector? v)
(eqv? 0 (vector-length v))))
(define (fasl-literals v need-exposed?)
(cond
[(empty-literals? v) v]
[else
(define exposed '())
(define bstr (s-exp->fasl v
#:skip-prefix? #t
#:handle-fail cannot-fasl
;; We have to keep uninterned symbols exposed, so they're
;; fasled with the encloding linklet directory
#:external-lift? (lambda (v)
(and (need-exposed? v)
(begin
(set! exposed (cons v exposed))
#t)))))
(if (null? exposed)
bstr
(cons bstr (list->vector (reverse exposed))))]))
(define (unfasl-literals/lazy v)
(cond
[(empty-literals? v) v]
[else
(box (to-unfasl (if (pair? v) (car v) v)
(if (pair? v) (cdr v) '#())
(current-load-relative-directory)))]))
(define (force-unfasl-literals b)
(cond
[(box? b)
(define v (unbox b))
(cond
[(to-unfasl? v)
(define new-v
(parameterize ([current-load-relative-directory (to-unfasl-wrt v)])
(fasl->s-exp (to-unfasl-bstr v)
#:datum-intern? #t
#:skip-prefix? #t
#:external-lifts (to-unfasl-externals v))))
(let loop ()
(cond
[(box-cas! b v new-v)
new-v]
[else
(let ([v (unbox b)])
(cond
[(to-unfasl? v)
;; must be a spurious CAS failure
(loop)]
[else
;; other thread beat us to it
v]))]))]
[else v])]
[else b]))
(define (cannot-fasl v)
(error 'write
"cannot marshal value that is embedded in compiled code\n value: ~v"
v))

View File

@ -4,8 +4,6 @@
racket/symbol
"match.rkt"
"wrap.rkt"
"path-for-srcloc.rkt"
"to-fasl.rkt"
"interp-match.rkt"
"interp-stack.rkt"
"gensym.rkt")
@ -56,8 +54,7 @@
(set! make-interp-procedure* make-proc))
(define (interpretable-jitified-linklet linklet-e serializable?)
;; Return a compiled linklet in two parts: a vector expression for
;; constants to be run once, and a expression for the linklet body.
;; Return a compiled linklet as an expression for the linklet body.
;; Conceptually, the run-time environment is implemented as a list,
;; and identifiers are mapped to positions in that list, where 0
@ -83,41 +80,10 @@
;; the list, for example.
(define (start linklet-e)
(match linklet-e
[`(lambda . ,_)
;; No constants:
(define-values (compiled-body num-body-vars)
(compile-linklet-body linklet-e '#hasheq() 0))
(vector #f
num-body-vars
compiled-body)]
[`(let* ,bindings ,body)
(define bindings-stk-i (make-stack-info))
(let loop ([bindings bindings] [elem 0] [env '#hasheq()] [accum '()])
(cond
[(null? bindings)
(define-values (compiled-body num-body-vars)
(compile-linklet-body body env 1))
(vector (list->vector (reverse accum))
num-body-vars
compiled-body)]
[else
(let ([binding (car bindings)])
(loop (cdr bindings)
(fx+ elem 1)
(hash-set env (car binding) (indirect 0 elem))
(let ([rhs (cadr binding)])
(cons (cond
[(or (path? rhs)
(path-for-srcloc? rhs)
(to-fasl? rhs))
;; The caller must extract all the paths from the bindings
;; and pass them back in at interp time; assume '#%path is
;; not a primitive
'#%path]
[else
(compile-expr rhs env 1 bindings-stk-i #t '#hasheq())])
accum))))]))]))
(define-values (compiled-body num-body-vars)
(compile-linklet-body linklet-e '#hasheq() 0))
(vector num-body-vars
compiled-body))
(define (compile-linklet-body v env stack-depth)
(match v
@ -627,35 +593,19 @@
;; ----------------------------------------
(define (interpret-linklet b ; compiled form
paths) ; unmarshaled paths
(define (interpret-linklet b)
(interp-match
b
[#(,consts ,num-body-vars ,b)
(let ([consts (and consts
(let ([vec (make-vector (vector*-length consts))])
(define stack (stack-set empty-stack 0 vec))
(for/fold ([paths paths]) ([b (in-vector consts)]
[i (in-naturals)])
(cond
[(eq? b '#%path)
(vector-set! vec i (car paths))
(cdr paths)]
[else
(vector-set! vec i (interpret-expr b stack))
paths]))
vec))])
(lambda args
(define start-stack (if consts
(stack-set empty-stack 0 consts)
empty-stack))
(define args-stack (for/fold ([stack start-stack]) ([arg (in-list args)]
[i (in-naturals (if consts 1 0))])
(stack-set stack i arg)))
(define post-args-pos (stack-count args-stack))
(define stack (for/fold ([stack args-stack]) ([i (in-range num-body-vars)])
(stack-set stack (+ i post-args-pos) (box unsafe-undefined))))
(interpret-expr b stack)))]))
[#(,num-body-vars ,b)
(lambda args
(define start-stack empty-stack)
(define args-stack (for/fold ([stack start-stack]) ([arg (in-list args)]
[i (in-naturals 0)])
(stack-set stack i arg)))
(define post-args-pos (stack-count args-stack))
(define stack (for/fold ([stack args-stack]) ([i (in-range num-body-vars)])
(stack-set stack (+ i post-args-pos) (box unsafe-undefined))))
(interpret-expr b stack))]))
(define (interpret-expr b stack)

View File

@ -1,9 +1,12 @@
#lang racket/base
(require "wrap.rkt")
(require racket/unsafe/undefined
racket/extflonum
"wrap.rkt")
(provide literal?
unwrap-literal
wrap-literal)
wrap-literal
register-literal-serialization)
(define (literal? v)
(define u (unwrap v))
@ -47,3 +50,67 @@
[(eof-object? x) 'eof]
[else
`(quote ,x)]))
(define (register-literal-serialization q serializable?-box datum-intern?)
(let check-register ([q q] [seen #hasheq()])
(define-syntax-rule (check-cycle new-seen e0 e ...)
(cond
[(hash-ref seen q #f)
(raise-arguments-error 'compile "cannot compile cyclic value"
"value" q)]
[else
(let ([new-seen (hash-set seen q #t)])
e0 e ...)]))
(define (register! q)
(unless (unbox serializable?-box)
(set-box! serializable?-box (make-hasheq)))
(hash-set! (unbox serializable?-box) q #t))
(cond
[(symbol? q)
;; gensyms need to be exposed to the whole linklet directory:
(unless (or (symbol-interned? q)
(symbol-unreadable? q))
(register! q))]
[(or (null? q)
(number? q)
(char? q)
(boolean? q)
(eof-object? q)
(void? q)
(eq? q unsafe-undefined))
(void)]
[(or (string? q)
(bytes? q))
(when datum-intern?
(register! q))]
[(pair? q)
(check-cycle
seen
(check-register (car q) seen)
(check-register (cdr q) seen))]
[(vector? q)
(check-cycle
seen
(for ([e (in-vector q)])
(check-register e seen)))]
[(hash? q)
(register! q)
(check-cycle
seen
(for ([(k v) (in-hash q)])
(check-register k seen)
(check-register v seen)))]
[(box? q)
(check-cycle
seen
(check-register (unbox q) seen))]
[(srcloc? q)
(register! q)
(srcloc-source q)]
[(prefab-struct-key q)
(register! q)
(check-cycle
seen
(check-register (struct->vector q) seen))]
[else
(register! q)])))

View File

@ -4,7 +4,7 @@
"lift.rkt"
"jitify.rkt"
"xify.rkt"
"path-and-fasl.rkt"
"fasl-literal.rkt"
"interpret.rkt"
"size.rkt"
"fasl.rkt")
@ -21,9 +21,10 @@
xify
extract-paths-and-fasls-from-schemified-linklet
make-path->compiled-path
compiled-path->path
fasl-literal?
fasl-literals
unfasl-literals/lazy
force-unfasl-literals
interpreter-link!
interpretable-jitified-linklet

View File

@ -1,163 +0,0 @@
#lang racket/base
(require racket/private/relative-path
racket/private/truncate-path
racket/fasl
"match.rkt"
"path-for-srcloc.rkt"
"to-fasl.rkt")
(provide extract-paths-and-fasls-from-schemified-linklet
make-path->compiled-path
compiled-path->path
force-unfasl)
;; Recognize lifted paths and `to-fasl`s in a schemified linklet, and
;; return the list of path and `to-fasl` values. If `convert?`, then
;; change the schemified linklet to expect the paths as arguments.
;;
;; In addition to paths, this extraction deals with values that have
;; been packages as `to-fasl`, either because they are large values
;; that are best handled in fasl form, because they are not
;; serializable (and we want to delay complaining in case no
;; serialization is needed), or because they are uninterned symbols
;; that need to be exposed to the Scheme-level `fasl` for a full
;; linklet.
(define (extract-paths-and-fasls-from-schemified-linklet linklet-e convert?)
(match linklet-e
[`(lambda . ,_)
;; No constants, so no paths:
(values '() linklet-e)]
[`(let* ,bindings ,body)
(define (path-binding? b)
(define rhs (cadr b))
(or (path? rhs)
(path-for-srcloc? rhs)
(to-fasl? rhs)))
(define any-path?
(for/or ([b (in-list bindings)])
(path-binding? b)))
(cond
[any-path?
(define paths (for/list ([b (in-list bindings)]
#:when (path-binding? b))
(cadr b)))
(cond
[convert?
(define path-ids (for/list ([b (in-list bindings)]
#:when (path-binding? b))
(car b)))
(define other-bindings (for/list ([b (in-list bindings)]
#:unless (path-binding? b))
b))
(values paths
`(lambda ,path-ids
(let* ,other-bindings ,body)))]
[else
(values paths linklet-e)])]
[else
(values '() linklet-e)])]))
(define (make-path->compiled-path who)
(define path->relative-path-elements (make-path->relative-path-elements #:who who))
(lambda (orig-p [for-srcloc? #f])
(cond
[(to-fasl? orig-p)
(define v (force-unfasl orig-p))
(cond
[(symbol? v)
;; Shortcut for just an uninterned symbol:
(box v)]
[else
(define lifts '())
(define bstr (s-exp->fasl v
#:handle-fail cannot-fasl
;; We have to keep uninterned symbols exposed, so they're
;; fasled with the encloding linklet directory
#:external-lift? (lambda (v)
(and (symbol? v)
(not (symbol-interned? v))
(not (symbol-unreadable? v))
(begin
(set! lifts (cons v lifts))
#t)))))
(if (null? lifts)
(box bstr)
(box (cons bstr (list->vector (reverse lifts)))))])]
[(symbol? orig-p)
;; Must be an uninterned symbol:
orig-p]
[else
(define p (if (path-for-srcloc? orig-p)
(path-for-srcloc-path orig-p)
orig-p))
(cond
[(path? p)
(or (path->relative-path-elements p)
(cond
[(or for-srcloc?
(path-for-srcloc? orig-p))
;; Can't make relative, so create a string that keeps up
;; to two path elements
(truncate-path p)]
[else (path->bytes p)]))]
[(or (string? p) (bytes? p) (symbol? p) (not p))
;; Allowed in compiled form
p]
[else
(error 'write
"cannot marshal value that is embedded in compiled code: ~V"
p)])])))
(define (compiled-path->path e)
(cond
[(box? e)
(define c (unbox e))
(to-fasl (box (if (pair? c) (car c) c))
(if (pair? c) (cdr c) '#())
(and (not (symbol? c))
(or (current-load-relative-directory)
(current-directory))))]
[(symbol? e)
;; Must be an uninterned symbol:
e]
[(bytes? e) (bytes->path e)]
[(string? e) e] ; was `path-for-srcloc` on write
[else (relative-path-elements->path e)]))
(define (force-unfasl tf)
(cond
[(not (to-fasl? tf))
;; act as identity on other values for the benefit of `raco decompile`
tf]
[else
(define vb (to-fasl-vb tf))
(define v (unbox vb))
(cond
[(bytes? v)
(define v2 (parameterize ([current-load-relative-directory (to-fasl-wrt tf)])
(fasl->s-exp v
#:datum-intern? #t
#:external-lifts (to-fasl-lifts tf))))
(let loop ()
(cond
[(box-cas! vb v v2)
(set-to-fasl-wrt! tf #f)
v2]
[else
(let ([v (unbox vb)])
(cond
[(bytes? v)
;; must be a spurious CAS failure
(loop)]
[else
;; other thread beat us to it
v]))]))]
[else
;; already forced (or never fasled)
v])]))
(define (cannot-fasl v)
(error 'write
"cannot marshal value that is embedded in compiled code\n value: ~v"
v))

View File

@ -1,5 +0,0 @@
#lang racket/base
(provide (struct-out path-for-srcloc))
(struct path-for-srcloc (path))

View File

@ -1,63 +0,0 @@
#lang racket/base
(require racket/extflonum
racket/fixnum
racket/unsafe/undefined)
(provide lift-quoted?
large-quoted?)
;; Check whether a quoted value needs to be lifted to run-time construction
(define (lift-quoted? q for-cify? datum-intern?)
(let lift-quoted? ([q q])
(cond
[for-cify?
(not (or (and (exact-integer? q)
;; always a fixnum:
(<= (- (expt 2 29)) q (sub1 (expt 2 29))))
(boolean? q)
(null? q)
(void? q)))]
[(impersonator? q) #t] ; i.e., strip impersonators when serializaing
[(path? q) #t]
[(regexp? q) #t]
[(srcloc? q) #t]
[(byte-regexp? q) #t]
[(keyword? q) #t]
[(hash? q) #t]
[(string? q) datum-intern?]
[(bytes? q) datum-intern?]
[(pair? q) (or (lift-quoted? (car q))
(lift-quoted? (cdr q)))]
[(vector? q) (for/or ([e (in-vector q)])
(lift-quoted? e))]
[(box? q) (lift-quoted? (unbox q))]
[(prefab-struct-key q) #t]
[(extflonum? q) #t]
[(or (null? q)
(number? q)
(char? q)
(boolean? q)
(and (symbol? q)
;; lift out gensym for sharing across phases
(or (symbol-interned? q)
(symbol-unreadable? q)))
(eof-object? q)
(void? q)
(eq? q unsafe-undefined))
#f]
[else #t])))
;; Check whether a quoted value is large enough to be worth representing
;; in fasl format:
(define (large-quoted? q)
(define fuel
(let remain ([q q] [fuel 128])
(cond
[(fx= fuel 0) 0]
[(pair? q) (remain (cdr q) (remain (car q) (fx- fuel 1)))]
[(vector? q) (for/fold ([fuel (fx- fuel 1)]) ([e (in-vector q)])
(remain e fuel))]
[(box? q) (remain (unbox q) (fx- fuel 1))]
[(prefab-struct-key q) (remain (struct->vector q) fuel)]
[else (fx- fuel 1)])))
(fx= fuel 0))

View File

@ -11,7 +11,6 @@
"mutated.rkt"
"mutated-state.rkt"
"left-to-right.rkt"
"serialize.rkt"
"let.rkt"
"equal.rkt"
"optimize.rkt"
@ -77,7 +76,9 @@
;; An import ABI is a list of list of booleans, parallel to the
;; linklet imports, where #t to means that a value is expected, and #f
;; means that a variable (which boxes a value) is expected.
(define (schemify-linklet lk serializable? datum-intern? for-interp? allow-set!-undefined?
;; If `serializable?-box` is not #f, it is filled with a
;; hash table of objects that need to be handled by `racket/fasl`.
(define (schemify-linklet lk serializable?-box datum-intern? for-interp? allow-set!-undefined?
unsafe-mode? enforce-constant? allow-inline? no-prompt?
prim-knowns primitives get-import-knowns import-keys)
(with-deterministic-gensym
@ -127,31 +128,24 @@
(for/fold ([exports (hasheq)]) ([ex-id (in-list ex-ids)])
(define id (ex-int-id ex-id))
(hash-set exports id (export (deterministic-gensym id) (ex-ext-id ex-id)))))
;; Lift any quoted constants that can't be serialized
(define-values (bodys/constants-lifted lifted-constants)
(if serializable?
(convert-for-serialize bodys #f datum-intern?)
(values bodys null)))
;; Collect source names for defined identifiers, to the degree that the
;; original source name differs from the current name
(define src-syms (get-definition-source-syms bodys))
;; Schemify the body, collecting information about defined names:
(define-values (new-body defn-info mutated)
(schemify-body* bodys/constants-lifted prim-knowns primitives imports exports
for-interp? allow-set!-undefined? add-import! #f
(schemify-body* bodys prim-knowns primitives imports exports
serializable?-box datum-intern? for-interp? allow-set!-undefined? add-import! #f
unsafe-mode? enforce-constant? allow-inline? no-prompt? #t))
(define all-grps (append grps (reverse new-grps)))
(values
;; Build `lambda` with schemified body:
(make-let*
lifted-constants
`(lambda (instance-variable-reference
,@(for*/list ([grp (in-list all-grps)]
[im (in-list (import-group-imports grp))])
(import-id im))
,@(for/list ([ex-id (in-list ex-ids)])
(export-id (hash-ref exports (ex-int-id ex-id)))))
,@new-body))
`(lambda (instance-variable-reference
,@(for*/list ([grp (in-list all-grps)]
[im (in-list (import-group-imports grp))])
(import-id im))
,@(for/list ([ex-id (in-list ex-ids)])
(export-id (hash-ref exports (ex-int-id ex-id)))))
,@new-body)
;; Imports (external names), possibly extended via inlining:
(for/list ([grp (in-list all-grps)])
(for/list ([im (in-list (import-group-imports grp))])
@ -184,7 +178,7 @@
(define id (ex-int-id ex-id))
(define v (known-inline->export-known (hash-ref defn-info id #f)
prim-knowns imports exports
serializable?))
serializable?-box))
(cond
[(not (set!ed-mutated-state? (hash-ref mutated id #f)))
(define ext-id (ex-ext-id ex-id))
@ -193,16 +187,17 @@
;; ----------------------------------------
(define (schemify-body l prim-knowns primitives imports exports for-cify? unsafe-mode? no-prompt? explicit-unnamed?)
(define (schemify-body l prim-knowns primitives imports exports
for-cify? unsafe-mode? no-prompt? explicit-unnamed?)
(with-deterministic-gensym
(define-values (new-body defn-info mutated)
(schemify-body* l prim-knowns primitives imports exports
#f #f (lambda (im ext-id index) #f)
#f #f #f #f (lambda (im ext-id index) #f)
for-cify? unsafe-mode? #t #t no-prompt? explicit-unnamed?))
new-body))
(define (schemify-body* l prim-knowns primitives imports exports
for-interp? allow-set!-undefined? add-import!
serializable?-box datum-intern? for-interp? allow-set!-undefined? add-import!
for-cify? unsafe-mode? enforce-constant? allow-inline? no-prompt? explicit-unnamed?)
;; Keep simple checking efficient by caching results
(define simples (make-hasheq))
@ -283,7 +278,7 @@
prim-knowns primitives knowns mutated imports exports simples
allow-set!-undefined?
add-import!
for-cify? for-interp?
serializable?-box datum-intern? for-cify? for-interp?
unsafe-mode? allow-inline? no-prompt? explicit-unnamed?
(if (and no-prompt? (null? (cdr l)))
'tail
@ -479,7 +474,8 @@
;; a 'too-early state in `mutated` for a `letrec`-bound variable can be
;; effectively canceled with a mapping in `knowns`.
(define (schemify v prim-knowns primitives knowns mutated imports exports simples allow-set!-undefined? add-import!
for-cify? for-interp? unsafe-mode? allow-inline? no-prompt? explicit-unnamed? wcm-state)
serializable?-box datum-intern? for-cify? for-interp? unsafe-mode? allow-inline? no-prompt? explicit-unnamed?
wcm-state)
;; `wcm-state` is one of: 'tail (= unknown), 'fresh (= no marks), or 'marked (= some marks)
(let schemify/knowns ([knowns knowns] [inline-fuel init-inline-fuel] [wcm-state wcm-state] [v v])
(define (schemify v wcm-state)
@ -517,7 +513,10 @@
`(define ,id ,(schemify rhs 'fresh))]
[`(define-values ,ids ,rhs)
`(define-values ,ids ,(schemify rhs 'fresh))]
[`(quote ,_) v]
[`(quote ,q)
(when serializable?-box
(register-literal-serialization q serializable?-box datum-intern?))
v]
[`(let-values () ,body)
(schemify body wcm-state)]
[`(let-values () ,bodys ...)
@ -904,8 +903,7 @@
[`,_
(let ([u-v (unwrap v)])
(cond
[(not (symbol? u-v))
v]
[(not (symbol? u-v)) v]
[(eq? u-v 'call-with-values)
'#%call-with-values]
[else

View File

@ -1,286 +0,0 @@
#lang racket/base
(require racket/extflonum
racket/prefab
racket/unsafe/undefined
"match.rkt"
"wrap.rkt"
"path-for-srcloc.rkt"
"to-fasl.rkt"
"quoted.rkt")
(provide convert-for-serialize)
;; Some quoted Racket values cannot be serialized and deserialized
;; automatically by Scheme: keywords (because they need to be interned
;; when reading code), strings and byte strings (ditto), regexps
;; (because they contain function pointers), etc.
;;
;; For those kinds of values, lift a construction of the quoted value
;; out and replace the use of a quoted value with a variable
;; reference. This lifting can interefere with optimizations, so only
;; lift as a last resort.
;;
;; Also lift out paths so they can be made relative, convert large
;; constants to fasl form, and lift out other non-serializable values
;; (so that `compile` will be ok, even though `write` cannot write out
;; those values).
(define (convert-for-serialize bodys for-cify? datum-intern?)
(define lifted-eq-constants (make-hasheq))
(define lifted-equal-constants (make-hash))
(define lift-bindings null)
(define lifts-count 0)
(define (add-lifted rhs)
;; FIXME: make sure these `id`s don't collide with anything
(define id (string->symbol (format "q:~a" lifts-count)))
(set! lifts-count (add1 lifts-count))
(set! lift-bindings (cons (list id rhs) lift-bindings))
id)
(define new-bodys
(for/list ([v (in-list bodys)])
(cond
[(convert-any? v for-cify? datum-intern?)
(define (convert v)
(reannotate
v
(match v
[`(quote ,q)
(cond
[(lift-quoted? q for-cify? datum-intern?)
(make-construct q add-lifted lifted-eq-constants lifted-equal-constants
for-cify? datum-intern?)]
[else v])]
[`(lambda ,formals ,body ...)
`(lambda ,formals ,@(convert-function-body body))]
[`(case-lambda [,formalss ,bodys ...] ...)
`(case-lambda ,@(for/list ([formals (in-list formalss)]
[body (in-list bodys)])
`[,formals ,@(convert-function-body body)]))]
[`(define-values ,ids ,rhs)
`(define-values ,ids ,(convert rhs))]
[`(let-values ([,idss ,rhss] ...) ,bodys ...)
`(let-values ,(for/list ([ids (in-list idss)]
[rhs (in-list rhss)])
`[,ids ,(convert rhs)])
,@(convert-body bodys))]
[`(letrec-values ([,idss ,rhss] ...) ,bodys ...)
`(letrec-values ,(for/list ([ids (in-list idss)]
[rhs (in-list rhss)])
`[,ids ,(convert rhs)])
,@(convert-body bodys))]
[`(if ,tst ,thn ,els)
`(if ,(convert tst) ,(convert thn) ,(convert els))]
[`(with-continuation-mark* ,mode ,key ,val ,body)
`(with-continuation-mark* ,mode ,(convert key) ,(convert val) ,(convert body))]
[`(begin ,exps ...)
`(begin . ,(convert-body exps))]
[`(begin-unsafe ,exps ...)
`(begin-unsafe . ,(convert-body exps))]
[`(begin0 ,exps ...)
`(begin0 . ,(convert-body exps))]
[`(set! ,id ,rhs)
`(set! ,id ,(convert rhs))]
[`(#%variable-reference) v]
[`(#%variable-reference ,_) v]
[`(,rator ,exps ...)
`(,(convert rator) ,@(convert-body exps))]
[`,_
(cond
[(and (not (symbol? v))
(lift-quoted? v for-cify? datum-intern?))
(convert `(quote ,v))]
[else v])])))
(define (convert-body body)
(for/list ([e (in-list body)])
(convert e)))
(define (convert-function-body body)
(if for-cify?
;; Detect the function-name pattern and avoid
;; mangling it:
(match body
[`((begin (quote ,name) ,body . ,bodys))
`((begin (quote ,name) ,@(convert-body (cons body bodys))))]
[`,_ (convert-body body)])
(convert-body body)))
(convert v)]
[else v])))
(values new-bodys
(reverse lift-bindings)))
;; v is a form or a list of forms
(define (convert-any? v for-cify? datum-intern?)
(let convert-any? ([v v])
(match v
[`(quote ,q) (lift-quoted? q for-cify? datum-intern?)]
[`(lambda ,formals ,body ...)
(convert-any? body)]
[`(case-lambda [,formalss ,bodys ...] ...)
(convert-any? bodys)]
[`(define-values ,ids ,rhs)
(convert-any? rhs)]
[`(let-values ([,idss ,rhss] ...) ,bodys ...)
(or (convert-any? rhss)
(convert-any? bodys))]
[`(letrec-values ([,idss ,rhss] ...) ,bodys ...)
(or (convert-any? rhss)
(convert-any? bodys))]
[`(if ,tst ,thn ,els)
(or (convert-any? tst)
(convert-any? thn)
(convert-any? els))]
[`(with-continuation-mark* ,_ ,key ,val ,body)
(or (convert-any? key)
(convert-any? val)
(convert-any? body))]
[`(begin ,exps ...)
(convert-any? exps)]
[`(begin-unsafe ,exps ...)
(convert-any? exps)]
[`(begin0 ,exps ...)
(convert-any? exps)]
[`(set! ,id ,rhs)
(convert-any? rhs)]
[`(#%variable-reference) #f]
[`(#%variable-reference ,_) #f]
[`(,exps ...)
(for/or ([exp (in-list exps)])
(convert-any? exp))]
[`,_ (and (not (symbol? v))
(lift-quoted? v for-cify? datum-intern?))])))
;; Construct an expression to be lifted
(define (make-construct q add-lifted lifted-eq-constants lifted-equal-constants
for-cify? datum-intern?)
(define (quote? e) (and (pair? e) (eq? 'quote (car e))))
(define seen #hasheq())
(define (check-cycle v)
(when (hash-ref seen v #f)
(raise-arguments-error 'compile "cannot compile cyclic value"
"value" q))
(set! seen (hash-set seen v #t)))
(define (done-cycle v)
(set! seen (hash-remove seen v)))
(cond
[(and (not for-cify?)
(large-quoted? q))
;; a `to-fasl` struct is recognized like
;; paths and `path-for-srcloc`:
(define id (add-lifted (to-fasl (box q) '#() #f)))
`(force-unfasl ,id)]
[else
(let make-construct ([q q])
(define lifted-constants (if (or (string? q) (bytes? q))
lifted-equal-constants
lifted-eq-constants))
(cond
[(hash-ref lifted-constants q #f)
=> (lambda (id) id)]
[else
(define rhs
(cond
[(path? q)
(if for-cify?
`(bytes->path ,(path->bytes q)
',(path-convention-type q))
;; We expect paths to be recognized in lifted bindings
;; and handled specially, so no conversion here:
q)]
[(path-for-srcloc? q) q]
[(regexp? q)
`(,(if (pregexp? q) 'pregexp 'regexp) ,(object-name q))]
[(srcloc? q)
`(unsafe-make-srcloc
,(let ([src (srcloc-source q)])
(if (and (not for-cify?)
;; Need to handle paths, need to reject (later) anything other
;; than a few types like strings and byte strings
(not (or (string? src) (bytes? src) (symbol? src) (not src))))
;; Like paths, `path-for-srcloc` must be recognized later
(make-construct (path-for-srcloc src))
(make-construct src)))
,(make-construct (srcloc-line q))
,(make-construct (srcloc-column q))
,(make-construct (srcloc-position q))
,(make-construct (srcloc-span q)))]
[(byte-regexp? q)
`(,(if (byte-pregexp? q) 'byte-pregexp 'byte-regexp) ,(object-name q))]
[(keyword? q)
`(string->keyword ,(keyword->string q))]
[(hash? q)
(define mut? (not (immutable? q)))
(when mut? (check-cycle q))
(define new-q
`(,(cond
[(hash-eq? q) 'hasheq]
[(hash-eqv? q) 'hasheqv]
[else 'hash])
,@(apply append
(for/list ([(k v) (in-hash q)])
(list (make-construct k)
(make-construct v))))))
(when mut? (done-cycle q))
new-q]
[(string? q) `(datum-intern-literal ,q)]
[(bytes? q) `(datum-intern-literal ,q)]
[(pair? q)
(if (list? q)
(let ([args (map make-construct q)])
(if (andmap quote? args)
`(quote ,q)
`(list ,@(map make-construct q))))
(let ([a (make-construct (car q))]
[d (make-construct (cdr q))])
(if (and (quote? a) (quote? d))
`(quote ,q)
`(cons ,a ,d))))]
[(vector? q)
(let ([args (map make-construct (vector->list q))])
`(vector->immutable-vector
,(if (and (andmap quote? args)
(not (impersonator? q)))
`(quote ,q)
`(vector ,@args))))]
[(box? q)
(let ([arg (make-construct (unbox q))])
`(box-immutable ,arg))]
[(prefab-struct-key q)
=> (lambda (key)
(define mut? (not (prefab-key-all-fields-immutable? key)))
(when mut? (check-cycle q))
(define new-q
`(make-prefab-struct ',key ,@(map make-construct
(cdr (vector->list (struct->vector q))))))
(when mut? (done-cycle q))
new-q)]
[(extflonum? q)
`(string->number ,(format "~a" q) 10 'read)]
[(or for-cify?
(null? q)
(number? q)
(char? q)
(boolean? q)
(and (symbol? q)
(or (symbol-interned? q)
(symbol-unreadable? q)))
(eof-object? q)
(void? q)
(eq? q unsafe-undefined))
;; Serializable in-place:
`(quote ,q)]
[(symbol? q)
;; Must be an uninterned symbol
`(force-unfasl ,(add-lifted (to-fasl (box q) '#() #f)))]
[else
;; Lift out anything non-serializable, so we can deal with those
;; values like we deal with paths:
(define id (add-lifted (to-fasl (box q) '#() #f)))
`(force-unfasl ,id)]))
(cond
[(and (quote? rhs)
(or (not for-cify?)
(not (lift-quoted? (cadr rhs) #t datum-intern?))))
rhs]
[else
(define id (add-lifted rhs))
(hash-set! lifted-constants q id)
id])]))]))

View File

@ -1,7 +1,6 @@
#lang racket/base
(require "wrap.rkt"
"match.rkt"
"quoted.rkt")
"match.rkt")
;; The `linklet-bigger-than?` function is practically an S-expression
;; counter, but it parses expressions properly so it can stop at
@ -38,13 +37,7 @@
(body-leftover-size body (sub1 size))]
[`(begin0 . ,body)
(body-leftover-size body (sub1 size))]
[`(quote ,v) (if (and serializable?
(lift-quoted? v #f #t))
;; pessimistically assume that full
;; strcuture must be lifted for
;; serialization:
(s-expr-leftover-size v size)
(sub1 size))]
[`(quote ,v) (sub1 size)]
[`(set! ,id ,rhs) (leftover-size rhs (sub1 size))]
[`(#%variable-reference . ,_) (sub1 size)]
[`(,_ . ,_) (body-leftover-size e size)]

View File

@ -1,8 +0,0 @@
#lang racket/base
(provide (struct-out to-fasl))
(struct to-fasl (vb ; box containing byte string as marshaled or other as unmarshaled
lifts ; vector of external lifts
wrt) ; directory for unmarshaling
#:mutable)

View File

@ -16,7 +16,7 @@
#define MZSCHEME_VERSION_X 7
#define MZSCHEME_VERSION_Y 9
#define MZSCHEME_VERSION_Z 0
#define MZSCHEME_VERSION_W 6
#define MZSCHEME_VERSION_W 7
/* A level of indirection makes `#` work as needed: */
#define AS_a_STR_HELPER(x) #x