diff --git a/pkgs/racket-test-core/tests/racket/contmark.rktl b/pkgs/racket-test-core/tests/racket/contmark.rktl index 7ea3541a87..1720533b05 100644 --- a/pkgs/racket-test-core/tests/racket/contmark.rktl +++ b/pkgs/racket-test-core/tests/racket/contmark.rktl @@ -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 diff --git a/pkgs/racket-test-core/tests/racket/optimize.rktl b/pkgs/racket-test-core/tests/racket/optimize.rktl index a5c859340e..fabd6bfbd9 100644 --- a/pkgs/racket-test-core/tests/racket/optimize.rktl +++ b/pkgs/racket-test-core/tests/racket/optimize.rktl @@ -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) diff --git a/racket/src/bc/src/optimize.c b/racket/src/bc/src/optimize.c index 76c247a709..de25896ace 100644 --- a/racket/src/bc/src/optimize.c +++ b/racket/src/bc/src/optimize.c @@ -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 )) as long as 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); diff --git a/racket/src/cs/rumble/control.ss b/racket/src/cs/rumble/control.ss index 68b172f4cc..074db692bf 100644 --- a/racket/src/cs/rumble/control.ss +++ b/racket/src/cs/rumble/control.ss @@ -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)]