aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author卜部昌平 <shyouhei@ruby-lang.org>2019-12-16 17:38:41 +0900
committer卜部昌平 <shyouhei@ruby-lang.org>2019-12-16 17:52:18 +0900
commitba11a74745e10fac88a74c2da2e0032ccf254265 (patch)
tree90645559ab20180ea9eb0868a091e334b82b6fc8
parent6545d5bbb9517a9364bd59a12a98d3e00516e07e (diff)
downloadruby-ba11a74745e10fac88a74c2da2e0032ccf254265.tar.gz
ensure cc->def == cc->me->def
The equation shall hold for every call cache. However prior to this changeset cc->me could be updated without also updating cc->def. Let's make it sure by introducing new macro named CC_SET_ME which sets cc->me and cc->def at once.
-rw-r--r--vm_eval.c21
-rw-r--r--vm_insnhelper.c18
-rw-r--r--vm_insnhelper.h8
3 files changed, 29 insertions, 18 deletions
diff --git a/vm_eval.c b/vm_eval.c
index b0179423d8..cec1ea41f6 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -179,22 +179,25 @@ vm_call0_body(rb_execution_context_t *ec, struct rb_calling_info *calling, struc
super_class = RCLASS_ORIGIN(super_class);
}
else if (cc->me->def->body.refined.orig_me) {
- cc->me = refined_method_callable_without_refinement(cc->me);
+ CC_SET_ME(cc, refined_method_callable_without_refinement(cc->me));
goto again;
}
super_class = RCLASS_SUPER(super_class);
+ if (super_class) {
+ CC_SET_ME(cc, rb_callable_method_entry(super_class, ci->mid));
+ if (cc->me) {
+ RUBY_VM_CHECK_INTS(ec);
+ goto again;
+ }
+ }
- if (!super_class || !(cc->me = rb_callable_method_entry(super_class, ci->mid))) {
- enum method_missing_reason ex = (type == VM_METHOD_TYPE_ZSUPER) ? MISSING_SUPER : 0;
- ret = method_missing(calling->recv, ci->mid, calling->argc, argv, ex, calling->kw_splat);
- goto success;
- }
- RUBY_VM_CHECK_INTS(ec);
- goto again;
+ enum method_missing_reason ex = (type == VM_METHOD_TYPE_ZSUPER) ? MISSING_SUPER : 0;
+ ret = method_missing(calling->recv, ci->mid, calling->argc, argv, ex, calling->kw_splat);
+ goto success;
}
case VM_METHOD_TYPE_ALIAS:
- cc->me = aliased_callable_method_entry(cc->me);
+ CC_SET_ME(cc, aliased_callable_method_entry(cc->me));
goto again;
case VM_METHOD_TYPE_MISSING:
{
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 8487886886..e7e20ee3ca 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2655,7 +2655,7 @@ vm_call_opt_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct
DEC_SP(1);
}
- cc->me = rb_callable_method_entry_with_refinements(CLASS_OF(calling->recv), ci->mid, NULL);
+ CC_SET_ME(cc, rb_callable_method_entry_with_refinements(CLASS_OF(calling->recv), ci->mid, NULL));
ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | (calling->kw_splat ? VM_CALL_KW_SPLAT : 0);
return vm_call_method(ec, reg_cfp, calling, (CALL_DATA)&cd);
}
@@ -2752,14 +2752,14 @@ vm_call_zsuper(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_ca
const struct rb_call_info *ci = &cd->ci;
struct rb_call_cache *cc = &cd->cc;
klass = RCLASS_SUPER(klass);
- cc->me = klass ? rb_callable_method_entry(klass, ci->mid) : NULL;
+ CC_SET_ME(cc, klass ? rb_callable_method_entry(klass, ci->mid) : NULL);
if (!cc->me) {
return vm_call_method_nome(ec, cfp, calling, cd);
}
if (cc->me->def->type == VM_METHOD_TYPE_REFINED &&
cc->me->def->body.refined.orig_me) {
- cc->me = refined_method_callable_without_refinement(cc->me);
+ CC_SET_ME(cc, refined_method_callable_without_refinement(cc->me));
}
return vm_call_method_each_type(ec, cfp, calling, cd);
}
@@ -2885,24 +2885,24 @@ search_refined_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, ID mi
}
if (cc->me->def->type != VM_METHOD_TYPE_REFINED ||
cc->me->def != ref_me->def) {
- cc->me = ref_me;
+ CC_SET_ME(cc, ref_me);
}
if (ref_me->def->type != VM_METHOD_TYPE_REFINED) {
return TRUE;
}
}
else {
- cc->me = NULL;
+ CC_SET_ME(cc, NULL);
return FALSE;
}
}
if (cc->me->def->body.refined.orig_me) {
- cc->me = refined_method_callable_without_refinement(cc->me);
+ CC_SET_ME(cc, refined_method_callable_without_refinement(cc->me));
}
else {
VALUE klass = RCLASS_SUPER(cc->me->defined_class);
- cc->me = klass ? rb_callable_method_entry(klass, mid) : NULL;
+ CC_SET_ME(cc, klass ? rb_callable_method_entry(klass, mid) : NULL);
}
return TRUE;
}
@@ -2955,7 +2955,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st
return vm_call_bmethod(ec, cfp, calling, cd);
case VM_METHOD_TYPE_ALIAS:
- cc->me = aliased_callable_method_entry(cc->me);
+ CC_SET_ME(cc, aliased_callable_method_entry(cc->me));
VM_ASSERT(cc->me != NULL);
return vm_call_method_each_type(ec, cfp, calling, cd);
@@ -3156,7 +3156,7 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
}
else {
/* TODO: use inline cache */
- cc->me = rb_callable_method_entry(klass, ci->mid);
+ CC_SET_ME(cc, rb_callable_method_entry(klass, ci->mid));
CC_SET_FASTPATH(cc, vm_call_super_method, TRUE);
}
}
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index 99555fd4ed..c96522fc98 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -124,6 +124,14 @@ enum vm_regan_acttype {
if (LIKELY(enabled)) ((cc)->call = (func)); \
} while (0)
+#define CC_SET_ME(cc, newme) do { \
+ CALL_CACHE ccx = (cc); \
+ const rb_callable_method_entry_t *mex = (newme); \
+ const rb_method_definition_t *defx = mex ? mex->def : NULL; \
+ ccx->me = mex; \
+ ccx->def = defx; \
+} while (0)
+
#define GET_BLOCK_HANDLER() (GET_LEP()[VM_ENV_DATA_INDEX_SPECVAL])
/**********************************************************/