diff --git a/pkgs/racket-test-core/tests/racket/chaperone.rktl b/pkgs/racket-test-core/tests/racket/chaperone.rktl index 6014ec7e00..6d79d6dadc 100644 --- a/pkgs/racket-test-core/tests/racket/chaperone.rktl +++ b/pkgs/racket-test-core/tests/racket/chaperone.rktl @@ -223,6 +223,65 @@ (define-values (a b c) (vector->values b2)) (test '(1 2 3) list a b c))) +(define unsafe-chaperone-vector-name "unsafe-chaperone-vector") +(define unsafe-impersonate-vector-name "unsafe-impersonate-vector") +(define chaperone-vector*-name "chaperone-vector*") +(define impersonate-vector*-name "impersonate-vector*") +(define chaperone-vector-name "chaperone-vector") +(define impersonate-vector-name "impersonate-vector") + + +;; properties and chaperones +(as-chaperone-or-impersonator + ([chaperone-vector impersonate-vector] + [chaperone-vector* impersonate-vector*] + [unsafe-chaperone-vector unsafe-impersonate-vector]) + (let () + + (define-values (p1 has1 get1) (make-impersonator-property 'p1)) + (define-values (p2 has2 get2) (make-impersonator-property 'p2)) + + (define v (vector 1 2 3)) + (define u (vector 7 8 9)) + (define red (lambda (v i x) x)) + (define red* (lambda (c v i x) x)) + + (define v1 (chaperone-vector v #f #f)) + (define v2 (chaperone-vector* v #f #f)) + (define v3 (unsafe-chaperone-vector v u)) + (define v4 (chaperone-vector v #f #f p2 5)) + (define v5 (chaperone-vector* v #f #f p2 5)) + (define v6 (unsafe-chaperone-vector v u p2 5)) + (define v7 (chaperone-vector v red red)) + (define v8 (chaperone-vector* v red* red*)) + (define v9 (chaperone-vector v red red p2 5)) + (define v10 (chaperone-vector* v red* red* p2 5)) + + (test 5 get2 v4) + (test 5 get2 v5) + (test 5 get2 v6) + (test 5 get2 v9) + (test 5 get2 v10) + + (define handler + (lambda (exn) + (test #t + regexp-match? + "p1-accessor: contract violation" + (exn-message exn)))) + + (err/rt-test (get1 v1) handler) + (err/rt-test (get1 v2) handler) + (err/rt-test (get1 v3) handler) + (err/rt-test (get1 v4) handler) + (err/rt-test (get1 v5) handler) + (err/rt-test (get1 v6) handler) + (err/rt-test (get1 v7) handler) + (err/rt-test (get1 v8) handler) + (err/rt-test (get1 v9) handler) + (err/rt-test (get1 v10) handler))) + + ;; check property-only chaperones (as-chaperone-or-impersonator ([chaperone-vector impersonate-vector chaperone-vector* impersonate-vector*] @@ -686,9 +745,6 @@ (test '(set p1-prop p2-prop) unbox b) (test 17 vector-ref c2 1)) -(define unsafe-chaperone-vector-name "unsafe-chaperone-vector") -(define unsafe-impersonate-vector-name "unsafe-impersonate-vector") - (as-chaperone-or-impersonator ([chaperone-vector impersonate-vector] [chaperone-vector* impersonate-vector*] diff --git a/racket/src/racket/src/eval.c b/racket/src/racket/src/eval.c index 54efffc720..8953a9e53f 100644 --- a/racket/src/racket/src/eval.c +++ b/racket/src/racket/src/eval.c @@ -3084,8 +3084,7 @@ scheme_do_eval(Scheme_Object *obj, int num_rands, Scheme_Object **rands, the chaperone may guard access to the function as a field inside the struct. We'll need to keep track of the original object as we unwrap to discover procedure chaperones. */ - && (SCHEME_VECTORP(((Scheme_Chaperone *)obj)->redirects)) - && !(SCHEME_VEC_SIZE(((Scheme_Chaperone *)obj)->redirects) & 1)) + && SCHEME_REDIRECTS_STRUCTP(((Scheme_Chaperone *) obj)->redirects)) /* A raw pair is from scheme_apply_chaperone(), propagating the original object for an applicable structure. */ || (type == scheme_raw_pair_type)) { @@ -3150,8 +3149,7 @@ scheme_do_eval(Scheme_Object *obj, int num_rands, Scheme_Object **rands, goto apply_top; } else { - if (SCHEME_VECTORP(((Scheme_Chaperone *)obj)->redirects) - && !(SCHEME_VEC_SIZE(((Scheme_Chaperone *)obj)->redirects) & 1)) + if (SCHEME_REDIRECTS_STRUCTP(((Scheme_Chaperone *)obj)->redirects)) obj = ((Scheme_Chaperone *)obj)->prev; else if (SAME_TYPE(SCHEME_TYPE(((Scheme_Chaperone *)obj)->redirects), scheme_nack_guard_evt_type)) /* Chaperone is for evt, not function arguments */ diff --git a/racket/src/racket/src/fun.c b/racket/src/racket/src/fun.c index 57c29bd666..b8e6e9130c 100644 --- a/racket/src/racket/src/fun.c +++ b/racket/src/racket/src/fun.c @@ -3631,7 +3631,7 @@ static Scheme_Object *do_chaperone_procedure(const char *name, const char *whati to pass the self proc along. */ for (val = px->prev; SCHEME_P_CHAPERONEP(val); val = ((Scheme_Chaperone *)val)->prev) { px2 = (Scheme_Chaperone *)val; - if (SCHEME_VECTORP(px2->redirects) && (SCHEME_VEC_SIZE(px2->redirects) & 0x1)) { + if (SCHEME_REDIRECTS_PROCEDUREP(px2->redirects)) { if ((SCHEME_VEC_SIZE(px2->redirects) > 3) || SCHEME_IMMUTABLEP(px2->redirects)) SCHEME_SET_IMMUTABLE(px->redirects); diff --git a/racket/src/racket/src/schnapp.inc b/racket/src/racket/src/schnapp.inc index f871df0783..67e7b83283 100644 --- a/racket/src/racket/src/schnapp.inc +++ b/racket/src/racket/src/schnapp.inc @@ -60,8 +60,7 @@ Scheme_Object *PRIM_APPLY_NAME(Scheme_Object *rator, t = _SCHEME_TYPE(rator); if ((t == scheme_proc_chaperone_type) - && SCHEME_VECTORP(((Scheme_Chaperone *)rator)->redirects) - && (SCHEME_VEC_SIZE(((Scheme_Chaperone *)rator)->redirects) & 0x1) + && SCHEME_REDIRECTS_PROCEDUREP((((Scheme_Chaperone *)rator)->redirects)) && (SCHEME_CHAPERONE_FLAGS((Scheme_Chaperone *)rator) == SCHEME_PROC_CHAPERONE_CALL_DIRECT)) { if (SCHEME_FALSEP(SCHEME_VEC_ELS(((Scheme_Chaperone *)rator)->redirects)[1]) || SCHEME_INT_VAL(SCHEME_VEC_ELS(((Scheme_Chaperone *)rator)->redirects)[1]) == argc) { diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index 671bd30a48..1f7467d2bb 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -1170,6 +1170,15 @@ so we can safely reuse the bit. #define SCHEME_P_CHAPERONEP(obj) (SAME_TYPE(SCHEME_TYPE(obj), scheme_proc_chaperone_type)) #define SCHEME_NP_CHAPERONEP(obj) (SAME_TYPE(SCHEME_TYPE(obj), scheme_chaperone_type)) +/* Does the shape of the redirects field match the pattern for particular chaperone types */ +#define SCHEME_REDIRECTS_PROCEDUREP(red) (SCHEME_VECTORP(red) \ + && (SCHEME_VEC_SIZE(red) & 1)) +#define SCHEME_REDIRECTS_STRUCTP(red) (SCHEME_VECTORP(red) \ + && SCHEME_VEC_SIZE(red) \ + && !(SCHEME_VEC_SIZE(red) & 1)) +#define SCHEME_REDIRECTS_PROP_ONLY_VECTORP(red) (SCHEME_VECTORP(red) \ + && !(SCHEME_VEC_SIZE(red))) + #define SCHEME_CHAPERONE_VECTORP(obj) (SCHEME_VECTORP(obj) \ || (SCHEME_NP_CHAPERONEP(obj) && SCHEME_VECTORP(SCHEME_CHAPERONE_VAL(obj)))) #define SCHEME_CHAPERONE_BOXP(obj) (SCHEME_BOXP(obj) \ diff --git a/racket/src/racket/src/struct.c b/racket/src/racket/src/struct.c index 454db342ec..dd5897b81d 100644 --- a/racket/src/racket/src/struct.c +++ b/racket/src/racket/src/struct.c @@ -1182,9 +1182,8 @@ static Scheme_Object *do_chaperone_prop_accessor(const char *who, Scheme_Object return v; } - if (!SCHEME_VECTORP(px->redirects) - || (SCHEME_VEC_SIZE(px->redirects) & 1) - || SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[0])) + if (!SCHEME_REDIRECTS_STRUCTP(px->redirects) + || SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[0])) arg = px->prev; else { ht = (Scheme_Hash_Tree *)SCHEME_VEC_ELS(px->redirects)[0]; @@ -2253,8 +2252,7 @@ static Scheme_Object *chaperone_struct_ref(const char *who, Scheme_Object *prim, Scheme_Chaperone *px = (Scheme_Chaperone *)o; Scheme_Object *a[2], *red, *orig; - if (SCHEME_VECTORP(px->redirects) - && !(SCHEME_VEC_SIZE(px->redirects) & 1) + if (SCHEME_REDIRECTS_STRUCTP(px->redirects) && SAME_OBJ(SCHEME_VEC_ELS(px->redirects)[1], scheme_undefined)) { /* chaperone on every field: check that result is not undefined */ o = px->prev; @@ -2269,8 +2267,7 @@ static Scheme_Object *chaperone_struct_ref(const char *who, Scheme_Object *prim, } return orig; - } else if (!SCHEME_VECTORP(px->redirects) - || (SCHEME_VEC_SIZE(px->redirects) & 1) + } else if (!SCHEME_REDIRECTS_STRUCTP(px->redirects) || SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[PRE_REDIRECTS + i])) { o = px->prev; } else { @@ -2385,8 +2382,7 @@ static void chaperone_struct_set(const char *who, Scheme_Object *prim, int half; o = px->prev; - if (SCHEME_VECTORP(px->redirects) - && !(SCHEME_VEC_SIZE(px->redirects) & 1) + if (SCHEME_REDIRECTS_STRUCTP(px->redirects) && !SAME_OBJ(SCHEME_VEC_ELS(px->redirects)[1], scheme_undefined)) { half = (SCHEME_VEC_SIZE(px->redirects) - PRE_REDIRECTS) >> 1; red = SCHEME_VEC_ELS(px->redirects)[PRE_REDIRECTS + half + i]; @@ -2425,8 +2421,7 @@ static void chaperone_struct_set(const char *who, Scheme_Object *prim, return; } } - } else if (SCHEME_VECTORP(px->redirects) - && !(SCHEME_VEC_SIZE(px->redirects) & 1) + } else if (SCHEME_REDIRECTS_STRUCTP(px->redirects) && SAME_OBJ(SCHEME_VEC_ELS(px->redirects)[1], scheme_undefined)) { /* chaperone on every field: check that current value is not undefined --- unless check is disabled by a mark (bit it's faster to check @@ -2996,8 +2991,7 @@ static Scheme_Object *struct_info_chaperone(Scheme_Object *o, Scheme_Object *si, while (SCHEME_CHAPERONEP(o)) { px = (Scheme_Chaperone *)o; - if (SCHEME_VECTORP(px->redirects) - && !(SCHEME_VEC_SIZE(px->redirects) & 1)) { + if (SCHEME_REDIRECTS_STRUCTP(px->redirects)) { proc = SCHEME_VEC_ELS(px->redirects)[1]; if (SCHEME_TRUEP(proc) && !SAME_OBJ(proc, scheme_undefined)) { if (SCHEME_CHAPERONE_FLAGS(px) & SCHEME_CHAPERONE_IS_IMPERSONATOR) diff --git a/racket/src/racket/src/vector.c b/racket/src/racket/src/vector.c index 30d198349b..e836592b35 100644 --- a/racket/src/racket/src/vector.c +++ b/racket/src/racket/src/vector.c @@ -499,7 +499,7 @@ Scheme_Object *scheme_chaperone_vector_ref2(Scheme_Object *o, int i, Scheme_Obje orig = scheme_chaperone_vector_ref2(px->prev, i, outermost); - if (SCHEME_VECTORP(px->redirects)) { + if (SCHEME_REDIRECTS_PROP_ONLY_VECTORP(px->redirects)) { /* chaperone was on property accessors */ /* or vector chaperone is property only */ return orig; @@ -580,7 +580,7 @@ void scheme_chaperone_vector_set(Scheme_Object *o, int i, Scheme_Object *v) o = px->prev; - if (!SCHEME_VECTORP(red)) { + if (!SCHEME_REDIRECTS_PROP_ONLY_VECTORP(red)) { /* not a property only chaperone */ red = SCHEME_CDR(px->redirects);