fix problems with continuation-mark-key chaperones

CS: When `with-continuation-mark` for a chaperoned key is in tail
position for a mark (such as a `parameterize`), make sure the existing
mark is still in place while (non-tail-)calling the chaperone's
interposition function.

BC: Don't collapse immediately nested `with-continuation-mark`s for
the same key if the key might be chaperoned. Also, repair treatment of
module-level bindings as potentially chaperoned.
This commit is contained in:
Matthew Flatt 2021-03-07 20:08:49 -07:00
parent 87d84a59c1
commit 73eeff4f60
4 changed files with 98 additions and 46 deletions

View File

@ -1074,6 +1074,29 @@
(err/rt-test (do-test bad-mark 5) exn:fail?)
(err/rt-test (do-test bad-mark-2 5) exn:fail?))
;; Make sure chaperoned keys are not collapsed, and make sure
;; parameters are in place for a chaperone invoked for a mark
;; that is in tail position with respect to `parameterize`
(module regression-test-for-chaperoned-keys racket/base
(provide f)
(define key
(chaperone-continuation-mark-key
(make-continuation-mark-key)
(lambda (v) (printf "get\n") v)
(lambda (v) (printf "set\n") v)))
(define (f)
(with-continuation-mark
key 1
(with-continuation-mark
key 2
'ok))))
(let ([o (open-output-bytes)])
(let ([f (dynamic-require ''regression-test-for-chaperoned-keys 'f)])
(parameterize ([current-output-port o])
(f)))
(test #"set\nset\n" get-output-bytes o))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Check that caching works right for marks in continuations that
;; capture metacontinuations

View File

@ -3953,7 +3953,7 @@
(define (f v)
(list (a-x v) #t))))
(test-comp #:except 'chez-scheme
(test-comp #:except 'chez-scheme ; cptypes can't see through chaperone support
'(module m racket/base
(require racket/unsafe/ops)
(struct a (x y))
@ -3965,7 +3965,8 @@
(define (f v)
(list (a-x v) #t))))
(test-comp '(module m racket/base
(test-comp #:except 'chez-scheme
'(module m racket/base
(require racket/unsafe/ops)
(struct a (x y))
(struct b a (z))
@ -3978,7 +3979,8 @@
(define (f v)
(and (b? v) (unsafe-struct-ref v 2)))))
(test-comp '(module m racket/base
(test-comp #:except 'chez-scheme
'(module m racket/base
(require racket/unsafe/ops)
(struct a (x y))
(struct b a (z))
@ -3991,7 +3993,8 @@
(define (f v)
(list (b-z v) #t))))
(test-comp '(module m racket/base
(test-comp #:except 'chez-scheme
'(module m racket/base
(require 'struct-a-for-optimize
racket/unsafe/ops)
(struct c b (m))
@ -4022,7 +4025,8 @@
(a? (a-x (a 1 2)))
5)))
(test-comp '(module m racket/base
(test-comp #:except 'chez-scheme ; `procedure?` is not primitive enough
'(module m racket/base
(struct a (x) #:omit-define-syntaxes #:mutable)
(procedure? a)
@ -4098,13 +4102,15 @@
#t
(lambda (x) (set-a-x! x 5))))
(test-comp '(lambda ()
(test-comp #:except 'chez-scheme ; not able to remove pure `make-struct-type`
'(lambda ()
(make-struct-type 'a #f 0 0 #f)
10)
'(lambda ()
10))
(test-comp '(lambda ()
(test-comp #:except 'chez-scheme ; not able to remove pure `make-struct-type-property`
'(lambda ()
(make-struct-type-property 'a)
10)
'(lambda ()
@ -4121,7 +4127,8 @@
'(lambda () 5)
#f)
(test-comp '(module m racket/base
(test-comp #:except 'chez-scheme
'(module m racket/base
(define-values (prop:a a? a-ref) (make-struct-type-property 'a))
(lambda (x)
(a? x)
@ -4130,7 +4137,8 @@
(define-values (prop:a a? a-ref) (make-struct-type-property 'a))
(lambda (x)
x)))
(test-comp '(module m racket/base
(test-comp #:except 'chez-scheme
'(module m racket/base
(define-values (prop:a a? a-ref) (make-struct-type-property 'a))
(procedure? a?)
@ -4168,10 +4176,10 @@
(struct b () #:property prop:a 'a)
(define (g y) (list y))))
(test-comp '(module m racket/base
(test-comp #:except 'racket ; a property type with a guard inhibits inlining, because the
;; guard might raise an error
'(module m racket/base
(define (f x) (list (g x) g))
;; A property type with a guard inhibits inlining, because the
;; guard might raise an error
(define-values (prop:a a? a-ref) (make-struct-type-property 'a error))
(struct b () #:property prop:a 'a)
(define (g y) (list y)))
@ -4179,8 +4187,7 @@
(define (f x) (list (list x) g))
(define-values (prop:a a? a-ref) (make-struct-type-property 'a error))
(struct b () #:property prop:a 'a)
(define (g y) (list y)))
#f)
(define (g y) (list y))))
(test-comp '(lambda ()
;; The built-in `prop:object-name` property has a guard:
@ -4189,9 +4196,10 @@
'(lambda () 5)
#f)
(module struct-type-property-a racket/base
(provide prop:a)
(define-values (prop:a a? a-ref) (make-struct-type-property 'a)))
(register-top-level-module
(module struct-type-property-a racket/base
(provide prop:a)
(define-values (prop:a a? a-ref) (make-struct-type-property 'a))))
(test-comp '(module m racket/base
(require 'struct-type-property-a)
@ -4204,11 +4212,13 @@
(struct b () #:property prop:a 'a)
(define (g y) (list y))))
(module struct-type-property-a-with-guard racket/base
(provide prop:a)
(define-values (prop:a a? a-ref) (make-struct-type-property 'a error)))
(register-top-level-module
(module struct-type-property-a-with-guard racket/base
(provide prop:a)
(define-values (prop:a a? a-ref) (make-struct-type-property 'a error))))
(test-comp '(module m racket/base
(test-comp #:except 'racket ; a property type with a guard inhibits inlining
'(module m racket/base
(require 'struct-type-property-a-with-guard)
(define (f x) (list (g x) g))
(struct b () #:property prop:a 'a)
@ -4217,10 +4227,10 @@
(require 'struct-type-property-a-with-guard)
(define (f x) (list (list x) g))
(struct b () #:property prop:a 'a)
(define (g y) (list y)))
#f)
(define (g y) (list y))))
(test-comp '(module m racket/base
(test-comp #:except 'chez-scheme ; not able to remove pure `make-struct-type`
'(module m racket/base
(struct posn (x y) #:prefab)
(let ()
;; Should be able to tell that `struct:posn` is prefab
@ -4277,6 +4287,16 @@
(with-continuation-mark 'x (values 1 2) (list 1)))
#f)
(test-comp `(lambda (x)
(with-continuation-mark
'x 1
(with-continuation-mark
'x 2
(x))))
`(lambda (x)
(with-continuation-mark
'x 2
(x))))
(test-comp `(lambda (x) ; `x` might be chaperoned
(with-continuation-mark
x 1
(with-continuation-mark
@ -4285,27 +4305,28 @@
`(lambda (x)
(with-continuation-mark
x 2
(x))))
(x)))
#f)
(test-comp `(lambda (x)
(with-continuation-mark
x (display x)
'x (display x)
(with-continuation-mark
x 2
'x 2
(x))))
`(lambda (x)
(display x)
(with-continuation-mark
x 2
'x 2
(x))))
(test-comp `(lambda (x)
(with-continuation-mark
x 1
'x 1
(with-continuation-mark
x (current-continuation-marks)
'x (current-continuation-marks)
(x))))
`(lambda (x)
(with-continuation-mark
x (current-continuation-marks)
'x (current-continuation-marks)
(x)))
#f)
(test-comp '(lambda (v)

View File

@ -530,7 +530,7 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int flags,
if (!(flags & OMITTABLE_KEEP_VARS)
&& ((SCHEME_IR_TOPLEVEL_FLAGS((Scheme_IR_Toplevel *)o) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_READY))
return 1;
else if ((SCHEME_IR_TOPLEVEL_FLAGS((Scheme_IR_Toplevel *)o) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_FIXED)
else if ((SCHEME_IR_TOPLEVEL_FLAGS((Scheme_IR_Toplevel *)o) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_CONST)
return 1;
else
return 0;
@ -6296,7 +6296,7 @@ static Scheme_Object *optimize_wcm(Scheme_Object *o, Optimize_Info *info, int co
{
Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)o;
Scheme_Object *k, *v, *b;
int init_vclock;
int init_vclock, can_omit_key;
Optimize_Info_Sequence info_seq;
optimize_info_seq_init(info, &info_seq);
@ -6337,7 +6337,8 @@ static Scheme_Object *optimize_wcm(Scheme_Object *o, Optimize_Info *info, int co
/* If the body cannot inspect the continution, and if the key is not
a chaperone, no need to add the mark: */
if (omittable_key(k, info)
can_omit_key = omittable_key(k, info);
if (can_omit_key
&& scheme_omittable_expr(b, -1, 20, 0, info, info))
return make_discarding_first_sequence(v, b, info);
@ -6358,7 +6359,8 @@ static Scheme_Object *optimize_wcm(Scheme_Object *o, Optimize_Info *info, int co
(with-continuation-mark <same-key> <val2>
<body>))
as long as <val2> doesn't inspect the continuation. */
if (SAME_TYPE(SCHEME_TYPE(wcm->body), scheme_with_cont_mark_type)
if (can_omit_key
&& SAME_TYPE(SCHEME_TYPE(wcm->body), scheme_with_cont_mark_type)
&& equivalent_exprs(wcm->key, ((Scheme_With_Continuation_Mark *)wcm->body)->key, NULL, NULL, 0)
&& scheme_omittable_expr(((Scheme_With_Continuation_Mark *)wcm->body)->val, 1, 20, 0, info, info))
return make_discarding_first_sequence(wcm->val, wcm->body, info);

View File

@ -998,7 +998,7 @@
[(pair? a)
(if (eq? key (car a))
(cons key val)
(make-mark-frame (mark-table-add/replace* (pair->mark-table a) key val)
(make-mark-frame (mark-table-add/replace* (pair->mark-table a) a key val)
#f))]
[(eq? a 'empty)
;; The current frame is the mark-splice frame, so update
@ -1006,7 +1006,7 @@
(current-mark-splice (mark-frame-update (current-mark-splice) key val))
'empty]
[(mark-frame? a)
(make-mark-frame (mark-table-add/replace* (mark-frame-table a) key val)
(make-mark-frame (mark-table-add/replace* (mark-frame-table a) a key val)
(mark-frame-end-uninterupted? a))]
[else
;; assert: (elem+cache? a)
@ -1578,7 +1578,7 @@
(authentic-continuation-mark-key? (impersonator-val v)))))
;; Like `mark-table-add/replace`, but handles continuation-mark-key impersonators
(define (mark-table-add/replace* ht k v)
(define (mark-table-add/replace* ht old-a k v)
(cond
[(and (impersonator? k)
(authentic-continuation-mark-key? (impersonator-val k)))
@ -1586,14 +1586,20 @@
(cond
[(or (continuation-mark-key-impersonator? k)
(continuation-mark-key-chaperone? k))
(let ([new-v (|#%app|
(if (continuation-mark-key-impersonator? k)
(continuation-mark-key-impersonator-set k)
(continuation-mark-key-chaperone-set k))
v)])
(unless (or (continuation-mark-key-impersonator? k)
(chaperone-of? new-v v))
(raise-chaperone-error 'with-continuation-mark "value" v new-v))
(let ([new-v
;; Restore attachment while interposing
(call-setting-continuation-attachment
old-a
(lambda ()
(let ([new-v (|#%app|
(if (continuation-mark-key-impersonator? k)
(continuation-mark-key-impersonator-set k)
(continuation-mark-key-chaperone-set k))
v)])
(unless (or (continuation-mark-key-impersonator? k)
(chaperone-of? new-v v))
(raise-chaperone-error 'with-continuation-mark "value" v new-v))
new-v)))])
(loop (impersonator-next k) new-v))]
[(impersonator? k)
(loop (impersonator-next k) v)]