cs: inline struct accessors/mutators across compilation units
Make schemify inline structure accessors and mutators across linklet boundaries --- or, in JIT mode, across function boundaries --- by replacing an accessor or mutator with a `#%record?` test and `unsafe-struct*-{ref,set!}` operation.
This commit is contained in:
parent
0f1088a150
commit
bff5989cde
|
@ -28,5 +28,6 @@
|
||||||
[record-predicate (known-constant)]
|
[record-predicate (known-constant)]
|
||||||
[record-accessor (known-constant)]
|
[record-accessor (known-constant)]
|
||||||
[record-mutator (known-constant)]
|
[record-mutator (known-constant)]
|
||||||
|
[unsafe-struct? (known-constant)]
|
||||||
|
|
||||||
[make-pthread-parameter (known-procedure 2)])
|
[make-pthread-parameter (known-procedure 2)])
|
||||||
|
|
|
@ -619,6 +619,7 @@
|
||||||
unsafe-struct-set!
|
unsafe-struct-set!
|
||||||
unsafe-struct*-ref
|
unsafe-struct*-ref
|
||||||
unsafe-struct*-set!
|
unsafe-struct*-set!
|
||||||
|
unsafe-struct? ; not exported to racket
|
||||||
|
|
||||||
unsafe-s16vector-ref
|
unsafe-s16vector-ref
|
||||||
unsafe-s16vector-set!
|
unsafe-s16vector-set!
|
||||||
|
|
|
@ -925,6 +925,8 @@
|
||||||
(#3%vector-ref s i))
|
(#3%vector-ref s i))
|
||||||
(define (unsafe-struct*-set! s i v)
|
(define (unsafe-struct*-set! s i v)
|
||||||
(#3%vector-set! s i v))
|
(#3%vector-set! s i v))
|
||||||
|
(define (unsafe-struct? v r)
|
||||||
|
(#3%record? v r))
|
||||||
|
|
||||||
(define (unsafe-struct-ref s i)
|
(define (unsafe-struct-ref s i)
|
||||||
(if (impersonator? s)
|
(if (impersonator? s)
|
||||||
|
|
|
@ -45,13 +45,26 @@
|
||||||
(unwrap s?)
|
(unwrap s?)
|
||||||
(known-predicate 2 type))]
|
(known-predicate 2 type))]
|
||||||
[knowns
|
[knowns
|
||||||
|
(let* ([immediate-count (struct-type-info-immediate-field-count info)]
|
||||||
|
[parent-count (- (struct-type-info-field-count info)
|
||||||
|
immediate-count)])
|
||||||
(for/fold ([knowns knowns]) ([id (in-list acc/muts)]
|
(for/fold ([knowns knowns]) ([id (in-list acc/muts)]
|
||||||
[maker (in-list make-acc/muts)])
|
[maker (in-list make-acc/muts)])
|
||||||
|
(match maker
|
||||||
|
[`(,make ,ref-or-set ,pos (quote ,name))
|
||||||
|
(or (and (exact-nonnegative-integer? pos)
|
||||||
|
(pos . < . immediate-count)
|
||||||
|
(symbol? name)
|
||||||
(cond
|
(cond
|
||||||
[(wrap-eq? (wrap-car maker) -ref)
|
[(and (wrap-eq? make 'make-struct-field-accessor)
|
||||||
(hash-set knowns (unwrap id) (known-accessor 2 type))]
|
(wrap-eq? ref-or-set -ref))
|
||||||
[else
|
(hash-set knowns (unwrap id) (known-field-accessor 2 type struct:s (+ parent-count pos)))]
|
||||||
(hash-set knowns (unwrap id) (known-mutator 4 type))]))])
|
[(and (wrap-eq? make 'make-struct-field-mutator)
|
||||||
|
(wrap-eq? ref-or-set -set!))
|
||||||
|
(hash-set knowns (unwrap id) (known-field-mutator 4 type struct:s (+ parent-count pos)))]
|
||||||
|
[else knowns]))
|
||||||
|
knowns)]
|
||||||
|
[`,_ knowns])))])
|
||||||
(values (hash-set knowns (unwrap struct:s) (known-struct-type type
|
(values (hash-set knowns (unwrap struct:s) (known-struct-type type
|
||||||
(struct-type-info-field-count info)
|
(struct-type-info-field-count info)
|
||||||
(struct-type-info-pure-constructor? info)))
|
(struct-type-info-pure-constructor? info)))
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
(provide init-inline-fuel
|
(provide init-inline-fuel
|
||||||
can-inline?
|
can-inline?
|
||||||
inline-clone
|
inline-clone
|
||||||
|
inline-type-id
|
||||||
known-inline->export-known)
|
known-inline->export-known)
|
||||||
|
|
||||||
(define inline-base 3)
|
(define inline-base 3)
|
||||||
|
@ -73,6 +74,33 @@
|
||||||
(inline-clone i-k im add-import! mutated imports)))]
|
(inline-clone i-k im add-import! mutated imports)))]
|
||||||
[else #f])])))
|
[else #f])])))
|
||||||
|
|
||||||
|
(define (inline-type-id k im add-import! mutated imports)
|
||||||
|
(define type-id (cond
|
||||||
|
[(known-field-accessor? k)
|
||||||
|
(known-field-accessor-type-id k)]
|
||||||
|
[(known-field-mutator? k)
|
||||||
|
(known-field-mutator-type-id k)]
|
||||||
|
[else #f]))
|
||||||
|
(define env
|
||||||
|
;; A `needed->env` setup can fail if a needed import cannot be
|
||||||
|
;; made available:
|
||||||
|
(cond
|
||||||
|
[(not type-id) #f]
|
||||||
|
[(not im) '()]
|
||||||
|
[(known-field-accessor/need-imports? k)
|
||||||
|
(needed->env (known-field-accessor/need-imports-needed k)
|
||||||
|
add-import!
|
||||||
|
im)]
|
||||||
|
[(known-field-mutator/need-imports? k)
|
||||||
|
(needed->env (known-field-mutator/need-imports-needed k)
|
||||||
|
add-import!
|
||||||
|
im)]
|
||||||
|
[else '()]))
|
||||||
|
(and env
|
||||||
|
(cond
|
||||||
|
[(null? env) type-id]
|
||||||
|
[else (clone-expr type-id env mutated)])))
|
||||||
|
|
||||||
;; Build a mapping from ids in the expr to imports into the current
|
;; Build a mapping from ids in the expr to imports into the current
|
||||||
;; linklet, where `add-import!` arranges for the import to exist as
|
;; linklet, where `add-import!` arranges for the import to exist as
|
||||||
;; needed and if possible. The result is #f if some import cannot be
|
;; needed and if possible. The result is #f if some import cannot be
|
||||||
|
@ -187,8 +215,31 @@
|
||||||
(known-procedure/can-inline/need-imports
|
(known-procedure/can-inline/need-imports
|
||||||
(known-procedure-arity-mask k)
|
(known-procedure-arity-mask k)
|
||||||
(known-procedure/can-inline-expr k)
|
(known-procedure/can-inline-expr k)
|
||||||
(for/list ([(k v) (in-hash needed)])
|
(hash->list needed))])]
|
||||||
(cons k v)))])]
|
[(known-field-accessor? k)
|
||||||
|
(define needed (needed-imports (known-field-accessor-type-id k) prim-knowns imports exports '() '#hasheq()))
|
||||||
|
(cond
|
||||||
|
[needed
|
||||||
|
(known-field-accessor/need-imports (known-procedure-arity-mask k)
|
||||||
|
(known-accessor-type k)
|
||||||
|
(known-field-accessor-type-id k)
|
||||||
|
(known-field-accessor-pos k)
|
||||||
|
(hash->list needed))]
|
||||||
|
[else
|
||||||
|
(known-accessor (known-procedure-arity-mask k)
|
||||||
|
(known-accessor-type k))])]
|
||||||
|
[(known-field-mutator? k)
|
||||||
|
(define needed (needed-imports (known-field-mutator-type-id k) prim-knowns imports exports '() '#hasheq()))
|
||||||
|
(cond
|
||||||
|
[needed
|
||||||
|
(known-field-mutator/need-imports (known-procedure-arity-mask k)
|
||||||
|
(known-mutator-type k)
|
||||||
|
(known-field-mutator-type-id k)
|
||||||
|
(known-field-mutator-pos k)
|
||||||
|
(hash->list needed))]
|
||||||
|
[else
|
||||||
|
(known-mutator (known-procedure-arity-mask k)
|
||||||
|
(known-mutator-type k))])]
|
||||||
[else k]))
|
[else k]))
|
||||||
|
|
||||||
(define (needed-imports v prim-knowns imports exports env needed)
|
(define (needed-imports v prim-knowns imports exports env needed)
|
||||||
|
@ -277,3 +328,7 @@
|
||||||
(wrap-cdr args))]
|
(wrap-cdr args))]
|
||||||
[else
|
[else
|
||||||
(cons (unwrap args) env)]))
|
(cons (unwrap args) env)]))
|
||||||
|
|
||||||
|
(define (hash->list needed)
|
||||||
|
(for/list ([(k v) (in-hash needed)])
|
||||||
|
(cons k v)))
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
known-predicate known-predicate? known-predicate-type
|
known-predicate known-predicate? known-predicate-type
|
||||||
known-accessor known-accessor? known-accessor-type
|
known-accessor known-accessor? known-accessor-type
|
||||||
known-mutator known-mutator? known-mutator-type
|
known-mutator known-mutator? known-mutator-type
|
||||||
|
known-field-accessor known-field-accessor? known-field-accessor-type-id known-field-accessor-pos
|
||||||
|
known-field-mutator known-field-mutator? known-field-mutator-type-id known-field-mutator-pos
|
||||||
|
known-field-accessor/need-imports known-field-accessor/need-imports? known-field-accessor/need-imports-needed
|
||||||
|
known-field-mutator/need-imports known-field-mutator/need-imports? known-field-mutator/need-imports-needed
|
||||||
known-struct-type-property/immediate-guard known-struct-type-property/immediate-guard?
|
known-struct-type-property/immediate-guard known-struct-type-property/immediate-guard?
|
||||||
a-known-constant
|
a-known-constant
|
||||||
a-known-consistent)
|
a-known-consistent)
|
||||||
|
@ -56,6 +60,10 @@
|
||||||
(struct known-predicate (type) #:prefab #:omit-define-syntaxes #:super struct:known-procedure/succeeds)
|
(struct known-predicate (type) #:prefab #:omit-define-syntaxes #:super struct:known-procedure/succeeds)
|
||||||
(struct known-accessor (type) #:prefab #:omit-define-syntaxes #:super struct:known-procedure)
|
(struct known-accessor (type) #:prefab #:omit-define-syntaxes #:super struct:known-procedure)
|
||||||
(struct known-mutator (type) #:prefab #:omit-define-syntaxes #:super struct:known-procedure)
|
(struct known-mutator (type) #:prefab #:omit-define-syntaxes #:super struct:known-procedure)
|
||||||
|
(struct known-field-accessor (type-id pos) #:prefab #:omit-define-syntaxes #:super struct:known-accessor)
|
||||||
|
(struct known-field-mutator (type-id pos) #:prefab #:omit-define-syntaxes #:super struct:known-mutator)
|
||||||
|
(struct known-field-accessor/need-imports (needed) #:prefab #:omit-define-syntaxes #:super struct:known-field-accessor)
|
||||||
|
(struct known-field-mutator/need-imports (needed) #:prefab #:omit-define-syntaxes #:super struct:known-field-mutator)
|
||||||
|
|
||||||
(struct known-struct-type-property/immediate-guard () #:prefab #:omit-define-syntaxes)
|
(struct known-struct-type-property/immediate-guard () #:prefab #:omit-define-syntaxes)
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,7 @@
|
||||||
prim-knowns knowns mutated imports exports
|
prim-knowns knowns mutated imports exports
|
||||||
allow-set!-undefined?
|
allow-set!-undefined?
|
||||||
add-import!
|
add-import!
|
||||||
for-cify?
|
for-cify? for-jitify?
|
||||||
unsafe-mode?))
|
unsafe-mode?))
|
||||||
(match form
|
(match form
|
||||||
[`(define-values ,ids ,_)
|
[`(define-values ,ids ,_)
|
||||||
|
@ -259,7 +259,7 @@
|
||||||
;; Schemify `let-values` to `let`, etc., and
|
;; Schemify `let-values` to `let`, etc., and
|
||||||
;; reorganize struct bindings.
|
;; reorganize struct bindings.
|
||||||
(define (schemify v prim-knowns knowns mutated imports exports allow-set!-undefined? add-import!
|
(define (schemify v prim-knowns knowns mutated imports exports allow-set!-undefined? add-import!
|
||||||
for-cify? unsafe-mode?)
|
for-cify? for-jitify? unsafe-mode?)
|
||||||
(let schemify/knowns ([knowns knowns] [inline-fuel init-inline-fuel] [v v])
|
(let schemify/knowns ([knowns knowns] [inline-fuel init-inline-fuel] [v v])
|
||||||
(let schemify ([v v])
|
(let schemify ([v v])
|
||||||
(define s-v
|
(define s-v
|
||||||
|
@ -278,7 +278,7 @@
|
||||||
,make2
|
,make2
|
||||||
,?2
|
,?2
|
||||||
,make-acc/muts ...)))
|
,make-acc/muts ...)))
|
||||||
#:guard (not for-cify?)
|
#:guard (not (or for-jitify? for-cify?))
|
||||||
;; Convert a `make-struct-type` binding into a
|
;; Convert a `make-struct-type` binding into a
|
||||||
;; set of bindings that Chez's cp0 recognizes,
|
;; set of bindings that Chez's cp0 recognizes,
|
||||||
;; and push the struct-specific extra work into
|
;; and push the struct-specific extra work into
|
||||||
|
@ -566,19 +566,74 @@
|
||||||
(left-left-lambda-convert
|
(left-left-lambda-convert
|
||||||
(inline-clone k (hash-ref imports u-rator #f) add-import! mutated imports)
|
(inline-clone k (hash-ref imports u-rator #f) add-import! mutated imports)
|
||||||
(sub1 inline-fuel))))))
|
(sub1 inline-fuel))))))
|
||||||
|
(define (maybe-tmp e name)
|
||||||
|
;; use `e` directly if it's ok to duplicate
|
||||||
|
(if (simple/can-copy? e prim-knowns knowns imports mutated)
|
||||||
|
e
|
||||||
|
(gensym name)))
|
||||||
|
(define (wrap-tmp tmp e body)
|
||||||
|
(if (eq? tmp e)
|
||||||
|
body
|
||||||
|
`(let ([,tmp ,e])
|
||||||
|
,body)))
|
||||||
|
(define (inline-field-access k s-rator u-rator args)
|
||||||
|
;; For imported accessors or for JIT mode, inline the
|
||||||
|
;; selector with an `unsafe-struct?` test plus `unsafe-struct*-ref`.
|
||||||
|
(define im (hash-ref imports u-rator #f))
|
||||||
|
(define type-id (and (or im for-jitify?)
|
||||||
|
(pair? args)
|
||||||
|
(null? (cdr args))
|
||||||
|
(inline-type-id k im add-import! mutated imports)))
|
||||||
|
(cond
|
||||||
|
[type-id
|
||||||
|
(define tmp (maybe-tmp (car args) 'v))
|
||||||
|
(define sel `(if (unsafe-struct? ,tmp ,(schemify type-id))
|
||||||
|
(unsafe-struct*-ref ,tmp ,(known-field-accessor-pos k))
|
||||||
|
(,s-rator ,tmp)))
|
||||||
|
(wrap-tmp tmp (car args)
|
||||||
|
sel)]
|
||||||
|
[else #f]))
|
||||||
|
(define (inline-field-mutate k s-rator u-rator args)
|
||||||
|
(define im (hash-ref imports u-rator #f))
|
||||||
|
(define type-id (and (or im for-jitify?)
|
||||||
|
(pair? args)
|
||||||
|
(pair? (cdr args))
|
||||||
|
(null? (cddr args))
|
||||||
|
(inline-type-id k im add-import! mutated imports)))
|
||||||
|
(cond
|
||||||
|
[type-id
|
||||||
|
(define tmp (maybe-tmp (car args) 'v))
|
||||||
|
(define tmp-rhs (maybe-tmp (cadr args) 'rhs))
|
||||||
|
(define mut `(if (unsafe-struct? ,tmp ,(schemify type-id))
|
||||||
|
(unsafe-struct*-set! ,tmp ,(known-field-mutator-pos k) ,tmp-rhs)
|
||||||
|
(,s-rator ,tmp ,tmp-rhs)))
|
||||||
|
(wrap-tmp tmp (car args)
|
||||||
|
(wrap-tmp tmp-rhs (cadr args)
|
||||||
|
mut))]
|
||||||
|
[else #f]))
|
||||||
(or (left-left-lambda-convert rator inline-fuel)
|
(or (left-left-lambda-convert rator inline-fuel)
|
||||||
(and (positive? inline-fuel)
|
(and (positive? inline-fuel)
|
||||||
(inline-rator))
|
(inline-rator))
|
||||||
(let ([s-rator (schemify rator)]
|
(let ([s-rator (schemify rator)]
|
||||||
[args (map schemify exps)]
|
[args (map schemify exps)]
|
||||||
[u-rator (unwrap rator)])
|
[u-rator (unwrap rator)])
|
||||||
(let ([plain-app?
|
(define k (find-known u-rator prim-knowns knowns imports mutated))
|
||||||
(or (known-procedure? (find-known u-rator prim-knowns knowns imports mutated))
|
(cond
|
||||||
(lambda? rator))])
|
[(and (not for-cify?)
|
||||||
|
(known-field-accessor? k)
|
||||||
|
(inline-field-access k s-rator u-rator args))
|
||||||
|
=> (lambda (e) e)]
|
||||||
|
[(and (not for-cify?)
|
||||||
|
(known-field-mutator? k)
|
||||||
|
(inline-field-mutate k s-rator u-rator args))
|
||||||
|
=> (lambda (e) e)]
|
||||||
|
[else
|
||||||
|
(define plain-app? (or (known-procedure? k)
|
||||||
|
(lambda? rator)))
|
||||||
(left-to-right/app s-rator
|
(left-to-right/app s-rator
|
||||||
args
|
args
|
||||||
plain-app? for-cify?
|
plain-app? for-cify?
|
||||||
prim-knowns knowns imports mutated))))]
|
prim-knowns knowns imports mutated)])))]
|
||||||
[`,_
|
[`,_
|
||||||
(let ([u-v (unwrap v)])
|
(let ([u-v (unwrap v)])
|
||||||
(cond
|
(cond
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
"import.rkt"
|
"import.rkt"
|
||||||
"mutated-state.rkt")
|
"mutated-state.rkt")
|
||||||
|
|
||||||
(provide simple?)
|
(provide simple?
|
||||||
|
simple/can-copy?)
|
||||||
|
|
||||||
;; Check whether an expression is simple in the sense that its order
|
;; Check whether an expression is simple in the sense that its order
|
||||||
;; of evaluation isn't detectable. This function receives both
|
;; of evaluation isn't detectable. This function receives both
|
||||||
|
@ -52,3 +53,18 @@
|
||||||
(string? e)
|
(string? e)
|
||||||
(bytes? e)
|
(bytes? e)
|
||||||
(regexp? e)))])))
|
(regexp? e)))])))
|
||||||
|
|
||||||
|
(define (simple/can-copy? e prim-knowns knowns imports mutated)
|
||||||
|
(match e
|
||||||
|
[`(quote ,v) (can-copy-literal? v)]
|
||||||
|
[`(,_ . ,_) #f]
|
||||||
|
[`,_
|
||||||
|
(let ([e (unwrap e)])
|
||||||
|
(or (and (symbol? e)
|
||||||
|
(simple-mutated-state? (hash-ref mutated e #f)))
|
||||||
|
(can-copy-literal? e)))]))
|
||||||
|
|
||||||
|
(define (can-copy-literal? e)
|
||||||
|
(or (integer? e)
|
||||||
|
(boolean? e)
|
||||||
|
(symbol? e)))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user