schemify: optimize with-continuation-marks

Prune some `with-continuation-marks` forms that aren't observable
(because the body is simple enough that it won't inspect marks). More
significantly, specialize `with-continuation-marks` forms to indicate
when the current frame is known to have no marks and to indicate
when tthe key expression is known to produce a non-impersonator.
This commit is contained in:
Matthew Flatt 2019-09-20 10:38:41 -06:00
parent 7ae4943a57
commit 7d725ab48b
16 changed files with 221 additions and 77 deletions

View File

@ -19,7 +19,7 @@
[acos (known-procedure/folding 2)]
[add1 (known-procedure/folding 2)]
[alarm-evt (known-procedure/no-prompt 2)]
[always-evt (known-constant)]
[always-evt (known-authentic)]
[andmap (known-procedure -4)]
[angle (known-procedure/folding 2)]
[append (known-procedure/no-prompt -1)]
@ -552,7 +552,7 @@
[mpair? (known-procedure/pure/folding 2)]
[nack-guard-evt (known-procedure/no-prompt 2)]
[negative? (known-procedure/folding 2)]
[never-evt (known-constant)]
[never-evt (known-authentic)]
[newline (known-procedure 3)]
[not (known-procedure/pure/folding 2)]
[null (known-literal '())]

View File

@ -1,11 +1,11 @@
(define-primitive-table paramz-table
[break-enabled-key (known-constant)]
[break-enabled-key (known-authentic)]
[cache-configuration (known-procedure 4)]
[check-for-break (known-procedure 1)]
[exception-handler-key (known-constant)]
[exception-handler-key (known-authentic)]
[extend-parameterization (known-procedure -2)]
[parameterization-key (known-constant)]
[parameterization-key (known-authentic)]
[reparameterize (known-procedure 2)]
[security-guard-check-file (known-procedure 8)]
[security-guard-check-file-link (known-procedure 8)]

View File

@ -29,6 +29,7 @@
unsafe-call-with-composable-continuation/no-wind
with-continuation-mark
with-continuation-mark* ; not exported to Racket
(rename [call-with-immediate-continuation-mark/inline
call-with-immediate-continuation-mark]
[call-with-immediate-continuation-mark

View File

@ -940,6 +940,48 @@
(lambda ()
body)))))]))
;; Specializations of `with-continuation-mark*` as determined by a mode:
(define-syntax with-continuation-mark*
(lambda (stx)
(syntax-case stx ()
[(_ mode key val body)
(case (syntax->datum #'mode)
[(general)
#'(with-continuation-mark key val body)]
[(push)
;; Assume no mark in place for this frame
#'(let* ([k key]
[v val])
(call-setting-continuation-attachment
(if (impersonator? k)
(mark-frame-update empty-mark-frame k v)
(cons k v))
(lambda ()
body)))]
[(authentic)
;; Assume `key` produces an authentic value
#'(let* ([k key]
[v val])
(call-consuming-continuation-attachment
empty-mark-frame
(lambda (a)
(call-setting-continuation-attachment
(if a
(mark-frame-update a k v)
(cons k v))
(lambda ()
body)))))]
[(push-authentic)
;; Assume no mark in place, and `key` produces an authentic value
#'(let* ([k key]
[v val])
(call-setting-continuation-attachment
(cons k v)
(lambda ()
body)))]
[else
(#%error 'with-continuation-mark* "unrecognized mode: ~s" #'mode)])])))
;; Return a continuation that expects a thunk to resume. That way, we
;; can can an `(end-uninterrupted)` and check for breaks in the
;; destination continuation

View File

@ -57,6 +57,7 @@
letrec*
define
$value
with-continuation-mark*
pariah
variable-set!
variable-ref

View File

@ -0,0 +1,36 @@
#lang racket/base
(require "wrap.rkt"
"match.rkt"
"known.rkt"
"import.rkt"
"mutated-state.rkt")
(provide authentic-valued?)
;; Check whether pre-schemifed `v` is known to produce a non-impersonator
(define (authentic-valued? v knowns prim-knowns imports mutated)
(let authentic-valued? ([v v])
(match v
[`(quote ,v)
(not (impersonator? v))]
[`,_
(define u-v (unwrap v))
(cond
[(symbol? u-v)
(cond
[(not (simple-mutated-state? (hash-ref mutated u-v #f)))
#f]
[(or (hash-ref prim-knowns u-v #f)
(hash-ref-either knowns imports u-v))
=> (lambda (k)
(or (known-authentic? k)
(known-procedure? k)
(and (known-literal? k)
(not (impersonator? (known-literal-value k))))
(and (known-copy? k)
(authentic-valued? (known-copy-id k)))))]
[else #f])]
[else
;; Any literal allows as unquoted is authentic
(not (pair? u-v))])])))

View File

@ -243,7 +243,7 @@
(compile-expr tst env stack-depth stk-i #f)
(add-clears new-then then-stk-i all-clear)
(add-clears new-else else-stk-i all-clear))]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,mode ,key ,val ,body)
(define new-body (compile-expr body env stack-depth stk-i tail?))
(define new-val (compile-expr val env stack-depth stk-i #f))
(vector 'wcm
@ -841,7 +841,8 @@
(letrec ([ok 'ok])
(set! other (call-with-values (lambda () (values 71 (begin0 88 ok)))
(lambda (v q) (list q v))))
(with-continuation-mark
(with-continuation-mark*
general
'x 'cm/x
(list (if s s #f) x ok other
(f 'vec) (g 'also-vec 'more)

View File

@ -286,7 +286,7 @@
(values (reannotate v `(if ,new-tst ,new-thn ,new-els))
new-free/els
new-lifts/els)]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,mode ,key ,val ,body)
(define sub-convert-mode (convert-mode-non-tail convert-mode))
(define-values (new-key new-free/key new-lifts/key)
(jitify-expr key env mutables free lifts sub-convert-mode #f in-name))
@ -294,7 +294,7 @@
(jitify-expr val env mutables new-free/key new-lifts/key sub-convert-mode #f in-name))
(define-values (new-body new-free/body new-lifts/body)
(jitify-expr body env mutables new-free/val new-lifts/val convert-mode name in-name))
(values (reannotate v `(with-continuation-mark ,new-key ,new-val ,new-body))
(values (reannotate v `(with-continuation-mark* ,mode ,new-key ,new-val ,new-body))
new-free/body
new-lifts/body)]
[`(quote ,_) (values v free lifts)]
@ -651,7 +651,7 @@
(find-mutable env tst
(find-mutable env thn
(find-mutable env els accum)))]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,mode ,key ,val ,body)
(find-mutable env key
(find-mutable env val
(find-mutable env body accum)))]
@ -797,7 +797,7 @@
(record-sizes! tst sizes)
(record-sizes! thn sizes)
(record-sizes! els sizes))]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,mode ,key ,val ,body)
(+ 1
(record-sizes! key sizes)
(record-sizes! val sizes)

View File

@ -5,6 +5,7 @@
(provide known-constant known-constant?
known-consistent known-consistent?
known-authentic known-authentic?
known-copy? known-copy known-copy-id
known-literal known-literal? known-literal-value
known-procedure known-procedure? known-procedure-arity-mask
@ -46,6 +47,9 @@
;; being a predicate for a structure type
(struct known-consistent () #:prefab #:omit-define-syntaxes #:super struct:known-constant)
;; the value at run time is never an impersonator
(struct known-authentic () #:prefab #:omit-define-syntaxes #:super struct:known-constant)
;; copy propagation --- use for local bindings or copies of primitives, only
(struct known-copy (id) #:prefab #:omit-define-syntaxes #:super struct:known-constant)
@ -77,7 +81,7 @@
;; procedure that never raises an exception or otherwise captures/escapes the calling context
(struct known-procedure/succeeds () #:prefab #:omit-define-syntaxes #:super struct:known-procedure/no-prompt)
;; procedure that accepts any arguments and is functional so that it can be reordered
;; procedure that accepts any arguments, returns a single value, and is functional so that it can be reordered
(struct known-procedure/pure () #:prefab #:omit-define-syntaxes #:super struct:known-procedure/succeeds)
;; pure and folding:

View File

@ -102,7 +102,7 @@
(lift-in-expr? v))]
[`(if ,tst ,thn ,els)
(or (lift-in-expr? tst) (lift-in-expr? thn) (lift-in-expr? els))]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,_ ,key ,val ,body)
(or (lift-in-expr? key) (lift-in-expr? val) (lift-in-expr? body))]
[`(quote ,_) #f]
[`(#%variable-reference . ,_) (error 'internal-error "unexpected variable reference")]
@ -143,7 +143,7 @@
[`(quote . ,_) #f]
[`(if ,tst ,thn ,els)
(or (lift? tst) (lift? thn) (lift? els))]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,_ ,key ,val ,body)
(or (lift? key) (lift? val) (lift? body))]
[`(set! ,_ ,rhs) (lift? rhs)]
[`(#%variable-reference) #f]
@ -229,10 +229,12 @@
(reannotate v `(if ,(lift-in-expr tst)
,(lift-in-expr thn)
,(lift-in-expr els)))]
[`(with-continuation-mark ,key ,val ,body)
(reannotate v `(with-continuation-mark ,(lift-in-expr key)
,(lift-in-expr val)
,(lift-in-expr body)))]
[`(with-continuation-mark* ,mode ,key ,val ,body)
(reannotate v `(with-continuation-mark*
,mode
,(lift-in-expr key)
,(lift-in-expr val)
,(lift-in-expr body)))]
[`(quote ,_) v]
[`(#%variable-reference . ,_) (error 'internal-error "unexpected variable reference")]
[`(set! ,id ,rhs)
@ -310,7 +312,7 @@
[frees+binds (compute-lifts! thn frees+binds lifts locals)]
[frees+binds (compute-lifts! els frees+binds lifts locals)])
frees+binds)]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,_ ,key ,val ,body)
(let* ([frees+binds (compute-lifts! key frees+binds lifts locals)]
[frees+binds (compute-lifts! val frees+binds lifts locals)]
[frees+binds (compute-lifts! body frees+binds lifts locals)])
@ -519,8 +521,8 @@
[`(quote . ,_) v]
[`(if ,tst ,thn ,els)
(reannotate v `(if ,(convert tst) ,(convert thn) ,(convert els)))]
[`(with-continuation-mark ,key ,val ,body)
(reannotate v `(with-continuation-mark ,(convert key) ,(convert val) ,(convert body)))]
[`(with-continuation-mark* ,mode ,key ,val ,body)
(reannotate v `(with-continuation-mark* ,mode ,(convert key) ,(convert val) ,(convert body)))]
[`(set! ,id ,rhs)
(define info (and (hash-ref lifts (unwrap id) #f)))
(cond

View File

@ -21,6 +21,8 @@
(if (literal? t)
(if (unwrap t) e1 e2)
v)]
[`(begin (quote ,_) ,e . ,es) ; avoid `begin` that looks like it provides a name
(optimize (reannotate v `(begin ,e . ,es)) prim-knowns primitives knowns imports mutated)]
[`(not ,t)
(if (literal? t)
`,(not (unwrap t))
@ -76,8 +78,8 @@
;; ----------------------------------------
;; Recursive optimization --- useful when not fused with schemify,
;; such as for an initial optimization pass on a definition of a
;; Recursive optimization on pre-schemified --- useful when not fused with
;; schemify, such as for an initial optimization pass on a definition of a
;; function that can be inlined (where converting away
;; `variable-reference-from-unsafe?` is particularly important)

View File

@ -21,7 +21,9 @@
"letrec.rkt"
"infer-name.rkt"
"ptr-ref-set.rkt"
"literal.rkt")
"literal.rkt"
"authentic.rkt"
"single-valued.rkt")
(provide schemify-linklet
schemify-body)
@ -428,8 +430,9 @@
;; 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-jitify? unsafe-mode? allow-inline? no-prompt?)
(let schemify/knowns ([knowns knowns] [inline-fuel init-inline-fuel] [v v])
(define (schemify v)
;; `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 'tail] [v v])
(define (schemify v wcm-state)
(define s-v
(reannotate
v
@ -437,13 +440,13 @@
[`(lambda ,formals ,body ...)
(infer-procedure-name
v
`(lambda ,formals ,@(schemify-body body)))]
`(lambda ,formals ,@(schemify-body body 'tail)))]
[`(case-lambda [,formalss ,bodys ...] ...)
(infer-procedure-name
v
`(case-lambda ,@(for/list ([formals (in-list formalss)]
[body (in-list bodys)])
`[,formals ,@(schemify-body body)])))]
`[,formals ,@(schemify-body body 'tail)])))]
[`(define-values (,struct:s ,make-s ,s? ,acc/muts ...)
(let-values (((,struct: ,make ,?1 ,-ref ,-set!) ,mk))
(values ,struct:2
@ -453,20 +456,20 @@
#:guard (not (or for-jitify? for-cify?))
(define new-seq
(struct-convert v prim-knowns knowns imports mutated
(lambda (v knowns) (schemify/knowns knowns inline-fuel v)) no-prompt?))
(lambda (v knowns) (schemify/knowns knowns inline-fuel 'fresh v)) no-prompt?))
(or new-seq
(match v
[`(,_ ,ids ,rhs)
`(define-values ,ids ,(schemify rhs))]))]
`(define-values ,ids ,(schemify rhs 'fresh))]))]
[`(define-values (,id) ,rhs)
`(define ,id ,(schemify rhs))]
`(define ,id ,(schemify rhs 'fresh))]
[`(define-values ,ids ,rhs)
`(define-values ,ids ,(schemify rhs))]
`(define-values ,ids ,(schemify rhs 'fresh))]
[`(quote ,_) v]
[`(let-values () ,body)
(schemify body)]
(schemify body wcm-state)]
[`(let-values () ,bodys ...)
(schemify `(begin . ,bodys))]
(schemify `(begin . ,bodys) wcm-state)]
[`(let-values ([(,ids) ,rhss] ...) ,bodys ...)
(define new-knowns
(for/fold ([knowns knowns]) ([id (in-list ids)]
@ -487,29 +490,29 @@
(for/list ([id (in-list ids)]
[rhs (in-list rhss)]
#:unless (merely-a-copy? id))
(schemify rhs))
(schemify rhs 'fresh))
(for/list ([body (in-list bodys)])
(schemify/knowns new-knowns inline-fuel body))
(schemify/knowns new-knowns inline-fuel wcm-state body))
prim-knowns knowns imports mutated simples)]
[`(let-values ([() (begin ,rhss ... (values))]) ,bodys ...)
`(begin ,@(schemify-body rhss) ,@(schemify-body bodys))]
`(begin ,@(schemify-body rhss 'fresh) ,@(schemify-body bodys wcm-state))]
[`(let-values ([,idss ,rhss] ...) ,bodys ...)
(or (struct-convert-local v prim-knowns knowns imports mutated simples
(lambda (v knowns) (schemify/knowns knowns inline-fuel v))
(lambda (v knowns) (schemify/knowns knowns inline-fuel 'fresh v))
#:unsafe-mode? unsafe-mode?)
(left-to-right/let-values idss
(for/list ([rhs (in-list rhss)])
(schemify rhs))
(schemify-body bodys)
(schemify rhs 'fresh))
(schemify-body bodys wcm-state)
mutated
for-cify?))]
[`(letrec-values () ,bodys ...)
(schemify `(begin . ,bodys))]
(schemify `(begin . ,bodys) wcm-state)]
[`(letrec-values ([() (values)]) ,bodys ...)
(schemify `(begin . ,bodys))]
(schemify `(begin . ,bodys) wcm-state)]
[`(letrec-values ([(,id) (values ,rhs)]) ,bodys ...)
;; special case of splitable values:
(schemify `(letrec-values ([(,id) ,rhs]) . ,bodys))]
(schemify `(letrec-values ([(,id) ,rhs]) . ,bodys) wcm-state)]
[`(letrec-values ([(,ids) ,rhss] ...) ,bodys ...)
(define-values (rhs-knowns body-knowns)
(for/fold ([rhs-knowns knowns] [body-knowns knowns]) ([id (in-list ids)]
@ -525,18 +528,19 @@
ids mutated for-cify?
`(letrec* ,(for/list ([id (in-list ids)]
[rhs (in-list rhss)])
`[,id ,(schemify/knowns rhs-knowns inline-fuel rhs)])
`[,id ,(schemify/knowns rhs-knowns inline-fuel 'fresh rhs)])
,@(for/list ([body (in-list bodys)])
(schemify/knowns body-knowns inline-fuel body))))]
(schemify/knowns body-knowns inline-fuel wcm-state body))))]
[`(letrec-values ([,idss ,rhss] ...) ,bodys ...)
(cond
[(struct-convert-local v #:letrec? #t prim-knowns knowns imports mutated simples
(lambda (v knowns) (schemify/knowns knowns inline-fuel v))
(lambda (v knowns) (schemify/knowns knowns inline-fuel 'fresh v))
#:unsafe-mode? unsafe-mode?)
=> (lambda (form) form)]
[(letrec-splitable-values-binding? idss rhss)
(schemify
(letrec-split-values-binding idss rhss bodys))]
(letrec-split-values-binding idss rhss bodys)
wcm-state)]
[else
;; Convert
;; (letrec*-values ([(id ...) rhs] ...) ....)
@ -551,7 +555,7 @@
append
(for/list ([ids (in-wrap-list idss)]
[rhs (in-list rhss)])
(let ([rhs (schemify rhs)])
(let ([rhs (schemify rhs 'fresh)])
(cond
[(null? ids)
`([,(gensym "lr")
@ -564,21 +568,41 @@
,@(for/list ([id (in-list ids)]
[pos (in-naturals)])
`[,id (unsafe-vector*-ref ,lr ,pos)]))]))))
,@(schemify-body bodys)))])]
,@(schemify-body bodys wcm-state)))])]
[`(if ,tst ,thn ,els)
`(if ,(schemify tst) ,(schemify thn) ,(schemify els))]
`(if ,(schemify tst 'fresh) ,(schemify thn wcm-state) ,(schemify els wcm-state))]
[`(with-continuation-mark ,key ,val ,body)
`(with-continuation-mark ,(schemify key) ,(schemify val) ,(schemify body))]
(define s-key (schemify key 'fresh))
(define s-val (schemify val 'fresh))
(define s-body (schemify body 'marked))
(define authentic-key?
(authentic-valued? key knowns prim-knowns imports mutated))
(cond
[(and authentic-key?
(simple? s-body prim-knowns knowns imports mutated simples))
`(begin ,(ensure-single-valued s-key knowns prim-knowns imports mutated)
,(ensure-single-valued s-val knowns prim-knowns imports mutated)
,s-body)]
[for-cify?
`(with-continuation-mark ,s-key ,s-val ,s-body)]
[else
(define mode
(case wcm-state
[(fresh) (if authentic-key? 'push-authentic 'push)]
[else (if authentic-key? 'authentic 'general)]))
`(with-continuation-mark* ,mode ,s-key ,s-val ,s-body)])]
[`(begin ,exp)
(schemify exp)]
(schemify exp wcm-state)]
[`(begin ,exps ...)
`(begin . ,(schemify-body exps))]
[`(begin0 ,exps ...)
`(begin0 . ,(schemify-body exps))]
`(begin . ,(schemify-body exps wcm-state))]
[`(begin0 ,exp)
(schemify exp wcm-state)]
[`(begin0 ,exp ,exps ...)
`(begin0 ,(schemify exp 'fresh) . ,(schemify-body exps 'fresh))]
[`(set! ,id ,rhs)
(define int-id (unwrap id))
(define ex (hash-ref exports int-id #f))
(define new-rhs (schemify rhs))
(define new-rhs (schemify rhs 'fresh))
(define state (hash-ref mutated int-id #f))
(cond
[ex
@ -612,7 +636,7 @@
[(known-constant? (import-lookup im)) #t]
[else
;; Not statically known
`(variable-reference-constant? ,(schemify `(#%variable-reference ,id)))])])]
`(variable-reference-constant? ,(schemify `(#%variable-reference ,id) 'fresh))])])]
[`(variable-reference-from-unsafe? (#%variable-reference))
unsafe-mode?]
[`(#%variable-reference)
@ -634,8 +658,8 @@
[(hash-ref prim-knowns u #f) u] ; assuming that `mutable` and `constant` are not primitives
[else 'constant])))]
[`(equal? ,exp1 ,exp2)
(let ([exp1 (schemify exp1)]
[exp2 (schemify exp2)])
(let ([exp1 (schemify exp1 'fresh)]
[exp2 (schemify exp2 'fresh)])
(cond
[(or (equal-implies-eq? exp1) (equal-implies-eq? exp2))
`(eq? ,exp1 ,exp2)]
@ -650,17 +674,17 @@
(cond
[(and (lambda? generator)
(lambda? receiver))
`(call-with-values ,(schemify generator) ,(schemify receiver))]
`(call-with-values ,(schemify generator 'fresh) ,(schemify receiver 'fresh))]
[else
(left-to-right/app (if for-cify? 'call-with-values '#%call-with-values)
(list (schemify generator) (schemify receiver))
(list (schemify generator 'fresh) (schemify receiver 'fresh))
#t for-cify?
prim-knowns knowns imports mutated simples)])]
[`(single-flonum-available?)
;; Fold to a boolean to allow earlier simplification
for-cify?]
[`((letrec-values ,binds ,rator) ,rands ...)
(schemify `(letrec-values ,binds (,rator . ,rands)))]
(schemify `(letrec-values ,binds (,rator . ,rands)) wcm-state)]
[`(,rator ,exps ...)
(define (left-left-lambda-convert rator inline-fuel)
(match rator
@ -672,6 +696,7 @@
(and (wrap-null? args)
(schemify/knowns knowns
inline-fuel
wcm-state
`(let-values ,(reverse binds) . ,bodys)))]
[(null? args) #f]
[(not (wrap-pair? formal-args))
@ -719,7 +744,7 @@
(cond
[type-id
(define tmp (maybe-tmp (car args) 'v))
(define sel `(if (unsafe-struct? ,tmp ,(schemify type-id))
(define sel `(if (unsafe-struct? ,tmp ,(schemify type-id 'fresh))
(unsafe-struct*-ref ,tmp ,(known-field-accessor-pos k))
(,s-rator ,tmp)))
(wrap-tmp tmp (car args)
@ -735,7 +760,7 @@
[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))
(define mut `(if (unsafe-struct? ,tmp ,(schemify type-id 'fresh))
(unsafe-struct*-set! ,tmp ,(known-field-mutator-pos k) ,tmp-rhs)
(,s-rator ,tmp ,tmp-rhs)))
(wrap-tmp tmp (car args)
@ -745,8 +770,8 @@
(or (left-left-lambda-convert rator inline-fuel)
(and (positive? inline-fuel)
(inline-rator))
(let ([s-rator (schemify rator)]
[args (schemify-body exps)]
(let ([s-rator (schemify rator 'fresh)]
[args (schemify-body exps 'fresh)]
[u-rator (unwrap rator)])
(define-values (k im) (find-known+import u-rator prim-knowns knowns imports mutated))
(cond
@ -820,7 +845,7 @@
(cond
[(and (known-copy? k)
(simple-mutated-state? (hash-ref mutated u-v #f)))
(schemify (known-copy-id k))]
(schemify (known-copy-id k) wcm-state)]
[else v]))]
[(and (too-early-mutated-state? state)
(not for-cify?))
@ -830,8 +855,13 @@
[else v])]))])))
(optimize s-v prim-knowns primitives knowns imports mutated))
(define (schemify-body l)
(for/list ([e (in-list l)])
(schemify e)))
(define (schemify-body l wcm-state)
(cond
[(null? l) null]
[(null? (cdr l))
(list (schemify (car l) wcm-state))]
[else
(cons (schemify (car l) 'fresh)
(schemify-body (cdr l) wcm-state))]))
(schemify v)))
(schemify v 'fresh)))

View File

@ -64,8 +64,8 @@
,@(convert-body bodys))]
[`(if ,tst ,thn ,els)
`(if ,(convert tst) ,(convert thn) ,(convert els))]
[`(with-continuation-mark ,key ,val ,body)
`(with-continuation-mark ,(convert key) ,(convert val) ,(convert body))]
[`(with-continuation-mark* ,mode ,key ,val ,body)
`(with-continuation-mark* ,mode ,(convert key) ,(convert val) ,(convert body))]
[`(begin ,exps ...)
`(begin . ,(convert-body exps))]
[`(begin0 ,exps ...)
@ -120,7 +120,7 @@
(or (convert-any? tst)
(convert-any? thn)
(convert-any? els))]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,_ ,key ,val ,body)
(or (convert-any? key)
(convert-any? val)
(convert-any? body))]

View File

@ -0,0 +1,25 @@
#lang racket/base
(require "match.rkt"
"wrap.rkt"
"known.rkt"
"import.rkt"
"mutated-state.rkt")
(provide ensure-single-valued)
(define (ensure-single-valued v knowns prim-knowns imports mutated)
(match v
[`(quote ,_) v]
[`(lambda . ,_) v]
[`(case-lambda . ,_) v]
[`(,proc-or-form . ,_)
(define u (unwrap proc-or-form))
(cond
[(and (symbol? u)
(simple-mutated-state? (hash-ref mutated u #f))
(let ([k (or (hash-ref prim-knowns u #f)
(hash-ref-either knowns imports u))])
(known-procedure/pure? k)))
v]
[else `($value ,v)])]
[`,_ v]))

View File

@ -32,7 +32,7 @@
(body-leftover-size (cons rhss body) (sub1 size))]
[`(if ,tst ,thn ,els)
(leftover-size els (leftover-size thn (leftover-size tst (sub1 size))))]
[`(with-continuation-mark ,key ,val ,body)
[`(with-continuation-mark* ,_ ,key ,val ,body)
(leftover-size body (leftover-size val (leftover-size key (sub1 size))))]
[`(begin0 . ,body)
(body-leftover-size body (sub1 size))]

View File

@ -32,8 +32,8 @@
`(begin . ,(xify-body body env))]
[`(if ,tst ,thn ,els)
`(if ,(xify tst env) ,(xify thn env) ,(xify els env))]
[`(with-continuation-mark ,key ,val ,body)
`(with-continuation-mark ,(xify key env) ,(xify val env) ,(xify body env))]
[`(with-continuation-mark* ,mode ,key ,val ,body)
`(with-continuation-mark* ,mode ,(xify key env) ,(xify val env) ,(xify body env))]
[`(set! ,id ,rhs)
`(set! ,(xify id env) ,(xify rhs env))]
;; Catch-all for other forms, which we can treat like applications