fix mark handling for impersonatored procedures to match docs

Using an impersonator property to represent an application mark was
a bad choice. The property gets propagated, so it is also on any later
chaperone layer, and then things go bad: the docs say that special
treatment is triggered by supplying an argument to `impersonate-property',
but it was actually triggered by the chaperone having the property.

Change the implementation to match the documentation. Using an
impersonator property to supply the mark should be regarded as a hack,
but now the implementaiton is at least consistent with the documentaiton.
This commit is contained in:
Matthew Flatt 2013-03-03 09:52:32 -07:00
parent 8c3eb7dcb4
commit 5e20f51415
4 changed files with 65 additions and 19 deletions

View File

@ -1226,6 +1226,26 @@
(test (list 11 '(11)) j 10) (test (list 11 '(11)) j 10)
(test '(12 #f 9 #f) values saved)) (test '(12 #f 9 #f) values saved))
;; Make sure that `impersonator-prop:application-mark'
;; is not propagated to further wrapping chaperones:
(let ()
(define msgs '())
(define f
(chaperone-procedure
(λ (x) 'wrong)
(λ (x)
(call-with-immediate-continuation-mark
'key
(λ (m)
(set! msgs (cons m msgs))
(values x))))
impersonator-prop:application-mark
(cons 'key 'skip-this-check)))
(void ((chaperone-procedure f (lambda (x) x)) 42)
(f 42))
(test '(#f #f) values msgs))
;; ---------------------------------------- ;; ----------------------------------------
;; Check that supplying a procedure `to make-keyword-procedure' that ;; Check that supplying a procedure `to make-keyword-procedure' that

View File

@ -2946,7 +2946,8 @@ 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 chaperone may guard access to the function as a field inside
the struct. We'll need to keep track of the original object the struct. We'll need to keep track of the original object
as we unwrap to discover procedure chaperones. */ as we unwrap to discover procedure chaperones. */
&& (SCHEME_VECTORP(((Scheme_Chaperone *)obj)->redirects))) && (SCHEME_VECTORP(((Scheme_Chaperone *)obj)->redirects))
&& !(SCHEME_VEC_SIZE(((Scheme_Chaperone *)obj)->redirects) & 1))
/* A raw pair is from scheme_apply_chaperone(), propagating the /* A raw pair is from scheme_apply_chaperone(), propagating the
original object for an applicable structure. */ original object for an applicable structure. */
|| (type == scheme_raw_pair_type)) { || (type == scheme_raw_pair_type)) {
@ -3016,7 +3017,8 @@ scheme_do_eval(Scheme_Object *obj, int num_rands, Scheme_Object **rands,
goto apply_top; goto apply_top;
} else { } else {
if (SCHEME_VECTORP(((Scheme_Chaperone *)obj)->redirects)) if (SCHEME_VECTORP(((Scheme_Chaperone *)obj)->redirects)
&& !(SCHEME_VEC_SIZE(((Scheme_Chaperone *)obj)->redirects) & 1))
obj = ((Scheme_Chaperone *)obj)->prev; obj = ((Scheme_Chaperone *)obj)->prev;
else if (SAME_TYPE(SCHEME_TYPE(((Scheme_Chaperone *)obj)->redirects), scheme_nack_guard_evt_type)) else if (SAME_TYPE(SCHEME_TYPE(((Scheme_Chaperone *)obj)->redirects), scheme_nack_guard_evt_type))
/* Chaperone is for evt, not function arguments */ /* Chaperone is for evt, not function arguments */

View File

@ -3237,7 +3237,7 @@ static Scheme_Object *do_chaperone_procedure(const char *name, const char *whati
int is_impersonator, int argc, Scheme_Object *argv[]) int is_impersonator, int argc, Scheme_Object *argv[])
{ {
Scheme_Chaperone *px; Scheme_Chaperone *px;
Scheme_Object *val = argv[0], *orig, *naya, *r; Scheme_Object *val = argv[0], *orig, *naya, *r, *app_mark;
Scheme_Hash_Tree *props; Scheme_Hash_Tree *props;
if (SCHEME_CHAPERONEP(val)) if (SCHEME_CHAPERONEP(val))
@ -3261,14 +3261,35 @@ static Scheme_Object *do_chaperone_procedure(const char *name, const char *whati
argv[0]); argv[0]);
props = scheme_parse_chaperone_props(name, 2, argc, argv); props = scheme_parse_chaperone_props(name, 2, argc, argv);
if (props) {
app_mark = scheme_hash_tree_get(props, scheme_app_mark_impersonator_property);
if (app_mark) {
/* don't need to keep the property */
if (props->count == 1)
props = NULL;
else
props = scheme_hash_tree_set(props, scheme_app_mark_impersonator_property, NULL);
/* app_mark should be (cons mark val) */
if (!SCHEME_PAIRP(app_mark))
app_mark = scheme_false;
} else
app_mark = scheme_false;
} else
app_mark = scheme_false;
px = MALLOC_ONE_TAGGED(Scheme_Chaperone); px = MALLOC_ONE_TAGGED(Scheme_Chaperone);
px->iso.so.type = scheme_proc_chaperone_type; px->iso.so.type = scheme_proc_chaperone_type;
px->val = val; px->val = val;
px->prev = argv[0]; px->prev = argv[0];
px->props = props; px->props = props;
/* put procedure with known-good arity (to speed checking) in a mutable pair: */
r = scheme_make_mutable_pair(argv[1], scheme_make_integer(-1)); /* put procedure with known-good arity (to speed checking) in a vector: */
r = scheme_make_vector(3, scheme_make_integer(-1));
SCHEME_VEC_ELS(r)[0] = argv[1];
SCHEME_VEC_ELS(r)[2] = app_mark;
/* Vector of odd size for redirects means a procedure chaperone,
vector with even slots means a structure chaperone. */
px->redirects = r; px->redirects = r;
if (is_impersonator) if (is_impersonator)
@ -3372,7 +3393,7 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
Scheme_Cont_Frame_Data cframe; Scheme_Cont_Frame_Data cframe;
if (argv == MZ_RUNSTACK) { if (argv == MZ_RUNSTACK) {
/* Pushing onto the runstack ensures that `(mcar px->redirects)' won't /* Pushing onto the runstack ensures that `(vector-ref px->redirects 0)' won't
modify argv. */ modify argv. */
if (MZ_RUNSTACK > MZ_RUNSTACK_START) { if (MZ_RUNSTACK > MZ_RUNSTACK_START) {
--MZ_RUNSTACK; --MZ_RUNSTACK;
@ -3404,7 +3425,7 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
what = "impersonator"; what = "impersonator";
/* Ensure that the original procedure accepts `argc' arguments: */ /* Ensure that the original procedure accepts `argc' arguments: */
if (argc != SCHEME_INT_VAL(SCHEME_CDR(px->redirects))) { if (argc != SCHEME_INT_VAL(SCHEME_VEC_ELS(px->redirects)[1])) {
a[0] = px->prev; a[0] = px->prev;
if (!scheme_check_proc_arity(NULL, argc, 0, 0, a)) { if (!scheme_check_proc_arity(NULL, argc, 0, 0, a)) {
/* Apply the original procedure, in case the chaperone would accept /* Apply the original procedure, in case the chaperone would accept
@ -3417,15 +3438,11 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
} }
/* record that argc is ok, on the grounds that the function is likely /* record that argc is ok, on the grounds that the function is likely
to be applied to argc arguments again */ to be applied to argc arguments again */
SCHEME_CDR(px->redirects) = scheme_make_integer(argc); SCHEME_VEC_ELS(px->redirects)[1] = scheme_make_integer(argc);
} }
if (px->props) { app_mark = SCHEME_VEC_ELS(px->redirects)[2];
app_mark = scheme_hash_tree_get(px->props, scheme_app_mark_impersonator_property); if (SCHEME_FALSEP(app_mark))
/* app_mark should be (cons mark val) */
if (app_mark && !SCHEME_PAIRP(app_mark))
app_mark = NULL;
} else
app_mark = NULL; app_mark = NULL;
if (app_mark) { if (app_mark) {
@ -3440,7 +3457,7 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
} else } else
need_pop_mark = 0; need_pop_mark = 0;
v = SCHEME_CAR(px->redirects); v = SCHEME_VEC_ELS(px->redirects)[0];
if (SAME_TYPE(SCHEME_TYPE(v), scheme_native_closure_type)) if (SAME_TYPE(SCHEME_TYPE(v), scheme_native_closure_type))
v = _apply_native(v, argc, argv); v = _apply_native(v, argc, argv);
else else
@ -3500,7 +3517,7 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
" expected: %d or %d\n" " expected: %d or %d\n"
" received: %d", " received: %d",
what, what,
SCHEME_CAR(px->redirects), SCHEME_VEC_ELS(px->redirects)[0],
argc, argc + 1, argc, argc + 1,
c); c);
return NULL; return NULL;
@ -3556,7 +3573,7 @@ Scheme_Object *scheme_apply_chaperone(Scheme_Object *o, int argc, Scheme_Object
" wrapper: %V\n" " wrapper: %V\n"
" received: %V", " received: %V",
what, what,
SCHEME_CAR(px->redirects), SCHEME_VEC_ELS(px->redirects)[0],
post); post);
if (app_mark) { if (app_mark) {

View File

@ -185,6 +185,8 @@ static Scheme_Object *make_chaperone_property_from_c(Scheme_Object *name);
static Scheme_Object *is_liberal_def_ctx(int argc, Scheme_Object **argv, Scheme_Object *self); static Scheme_Object *is_liberal_def_ctx(int argc, Scheme_Object **argv, Scheme_Object *self);
/* This needs to be even, so that structure chaperones are
distingiushed from procedure chaperones: */
#define PRE_REDIRECTS 2 #define PRE_REDIRECTS 2
#ifdef MZ_PRECISE_GC #ifdef MZ_PRECISE_GC
@ -1054,6 +1056,7 @@ static Scheme_Object *do_chaperone_prop_accessor(const char *who, Scheme_Object
} }
if (!SCHEME_VECTORP(px->redirects) if (!SCHEME_VECTORP(px->redirects)
|| (SCHEME_VEC_SIZE(px->redirects) & 1)
|| SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[0])) || SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[0]))
arg = px->prev; arg = px->prev;
else { else {
@ -1972,6 +1975,7 @@ static Scheme_Object *chaperone_struct_ref(const char *who, Scheme_Object *o, in
Scheme_Object *a[2], *red, *orig; Scheme_Object *a[2], *red, *orig;
if (!SCHEME_VECTORP(px->redirects) if (!SCHEME_VECTORP(px->redirects)
|| (SCHEME_VEC_SIZE(px->redirects) & 1)
|| SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[PRE_REDIRECTS + i])) { || SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[PRE_REDIRECTS + i])) {
o = px->prev; o = px->prev;
} else { } else {
@ -2025,7 +2029,8 @@ static void chaperone_struct_set(const char *who, Scheme_Object *o, int i, Schem
int half; int half;
o = px->prev; o = px->prev;
if (SCHEME_VECTORP(px->redirects)) { if (SCHEME_VECTORP(px->redirects)
&& !(SCHEME_VEC_SIZE(px->redirects) & 1)) {
half = (SCHEME_VEC_SIZE(px->redirects) - PRE_REDIRECTS) >> 1; half = (SCHEME_VEC_SIZE(px->redirects) - PRE_REDIRECTS) >> 1;
red = SCHEME_VEC_ELS(px->redirects)[PRE_REDIRECTS + half + i]; red = SCHEME_VEC_ELS(px->redirects)[PRE_REDIRECTS + half + i];
if (SCHEME_TRUEP(red)) { if (SCHEME_TRUEP(red)) {
@ -2560,7 +2565,8 @@ static Scheme_Object *struct_info_chaperone(Scheme_Object *o, Scheme_Object *si,
while (SCHEME_CHAPERONEP(o)) { while (SCHEME_CHAPERONEP(o)) {
px = (Scheme_Chaperone *)o; px = (Scheme_Chaperone *)o;
if (SCHEME_VECTORP(px->redirects)) { if (SCHEME_VECTORP(px->redirects)
&& !(SCHEME_VEC_SIZE(px->redirects) & 1)) {
proc = SCHEME_VEC_ELS(px->redirects)[1]; proc = SCHEME_VEC_ELS(px->redirects)[1];
if (SCHEME_TRUEP(proc)) { if (SCHEME_TRUEP(proc)) {
if (SCHEME_CHAPERONE_FLAGS(px) & SCHEME_CHAPERONE_IS_IMPERSONATOR) if (SCHEME_CHAPERONE_FLAGS(px) & SCHEME_CHAPERONE_IS_IMPERSONATOR)
@ -5314,6 +5320,7 @@ static Scheme_Object *do_chaperone_struct(const char *name, int is_impersonator,
if (SCHEME_STRUCTP(val)) { if (SCHEME_STRUCTP(val)) {
stype = ((Scheme_Structure *)val)->stype; stype = ((Scheme_Structure *)val)->stype;
/* vector size needs to be even to distinguish it from procedure chaperones: */
redirects = scheme_make_vector(PRE_REDIRECTS + 2 * stype->num_slots, scheme_false); redirects = scheme_make_vector(PRE_REDIRECTS + 2 * stype->num_slots, scheme_false);
} else { } else {
stype = NULL; stype = NULL;