From 5e8a147480f87f19a8b96ad3fb33a25fb4bb19b9 Mon Sep 17 00:00:00 2001 From: ko1 Date: Fri, 3 Jul 2015 11:24:50 +0000 Subject: * method.h: introduce rb_callable_method_entry_t to remove rb_control_frame_t::klass. [Bug #11278], [Bug #11279] rb_method_entry_t data belong to modules/classes. rb_method_entry_t::owner points defined module or class. module M def foo; end end In this case, owner is M. rb_callable_method_entry_t data belong to only classes. For modules, MRI creates corresponding T_ICLASS internally. rb_callable_method_entry_t can also belong to T_ICLASS. rb_callable_method_entry_t::defined_class points T_CLASS or T_ICLASS. rb_method_entry_t data for classes (not for modules) are also rb_callable_method_entry_t data because it is completely same data. In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class. For example, there are classes C and D, and incldues M, class C; include M; end class D; include M; end then, two T_ICLASS objects for C's super class and D's super class will be created. When C.new.foo is called, then M#foo is searcheed and rb_callable_method_t data is used by VM to invoke M#foo. rb_method_entry_t data is only one for M#foo. However, rb_callable_method_entry_t data are two (and can be more). It is proportional to the number of including (and prepending) classes (the number of T_ICLASS which point to the module). Now, created rb_callable_method_entry_t are collected when the original module M was modified. We can think it is a cache. We need to select what kind of method entry data is needed. To operate definition, then you need to use rb_method_entry_t. You can access them by the following functions. * rb_method_entry(VALUE klass, ID id); * rb_method_entry_with_refinements(VALUE klass, ID id); * rb_method_entry_without_refinements(VALUE klass, ID id); * rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me); To invoke methods, then you need to use rb_callable_method_entry_t which you can get by the following APIs corresponding to the above listed functions. * rb_callable_method_entry(VALUE klass, ID id); * rb_callable_method_entry_with_refinements(VALUE klass, ID id); * rb_callable_method_entry_without_refinements(VALUE klass, ID id); * rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me); VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry() returns rb_callable_method_entry_t. You can check a super class of current method by rb_callable_method_entry_t::defined_class. * method.h: renamed from rb_method_entry_t::klass to rb_method_entry_t::owner. * internal.h: add rb_classext_struct::callable_m_tbl to cache rb_callable_method_entry_t data. We need to consider abotu this field again because it is only active for T_ICLASS. * class.c (method_entry_i): ditto. * class.c (rb_define_attr): rb_method_entry() does not takes defiend_class_ptr. * gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS. * cont.c (fiber_init): rb_control_frame_t::klass is removed. * proc.c: fix `struct METHOD' data structure because rb_callable_method_t has all information. * vm_core.h: remove several fields. * rb_control_frame_t::klass. * rb_block_t::klass. And catch up changes. * eval.c: catch up changes. * gc.c: ditto. * insns.def: ditto. * vm.c: ditto. * vm_args.c: ditto. * vm_backtrace.c: ditto. * vm_dump.c: ditto. * vm_eval.c: ditto. * vm_insnhelper.c: ditto. * vm_method.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm_insnhelper.c | 250 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 155 insertions(+), 95 deletions(-) (limited to 'vm_insnhelper.c') diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 76f5bbe42a..639efeef1c 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -22,8 +22,7 @@ #define INLINE inline #endif -static rb_control_frame_t * -vm_get_ruby_level_caller_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp); +static rb_control_frame_t *vm_get_ruby_level_caller_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp); VALUE ruby_vm_sysstack_error_copy(void) @@ -40,6 +39,34 @@ vm_stackoverflow(void) } #if VM_CHECK_MODE > 0 + +static int +callable_class_p(VALUE klass) +{ +#if VM_CHECK_MODE >= 2 + while (klass) { + if (klass == rb_cBasicObject) { + return TRUE; + } + klass = RCLASS_SUPER(klass); + } + return FALSE; +#else + return klass != 0; +#endif +} + +static int +callable_method_entry_p(const rb_callable_method_entry_t *me) +{ + if (me == NULL || callable_class_p(me->defined_class)) { + return TRUE; + } + else { + return FALSE; + } +} + static void check_frame(int magic, int req_block, int req_me, int req_cref, VALUE specval, VALUE cref_or_me) { @@ -76,6 +103,14 @@ check_frame(int magic, int req_block, int req_me, int req_cref, VALUE specval, V } } } + + if (cref_or_me_type == imemo_ment) { + const rb_callable_method_entry_t *me = (const rb_callable_method_entry_t *)cref_or_me; + + if (!callable_method_entry_p(me)) { + rb_bug("vm_push_frame: ment (%s) should be callable on %x frame.", rb_obj_info(cref_or_me), magic); + } + } } #endif @@ -84,7 +119,6 @@ vm_push_frame(rb_thread_t *th, const rb_iseq_t *iseq, VALUE type, VALUE self, - VALUE klass, VALUE specval, VALUE cref_or_me, const VALUE *pc, @@ -147,19 +181,6 @@ vm_push_frame(rb_thread_t *th, cfp->block_iseq = 0; cfp->proc = 0; - if (klass) { - cfp->klass = klass; - } - else { - rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); - if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, prev_cfp)) { - cfp->klass = Qnil; - } - else { - cfp->klass = prev_cfp->klass; - } - } - if (VMDEBUG == 2) { SDR(); } @@ -334,7 +355,7 @@ vm_getspecial(rb_thread_t *th, VALUE *lep, rb_num_t key, rb_num_t type) return val; } -static rb_method_entry_t * +static rb_callable_method_entry_t * check_method_entry(VALUE obj, int can_be_svar) { if (obj == Qfalse) return NULL; @@ -345,7 +366,7 @@ check_method_entry(VALUE obj, int can_be_svar) switch (imemo_type(obj)) { case imemo_ment: - return (rb_method_entry_t *)obj; + return (rb_callable_method_entry_t *)obj; case imemo_cref: return NULL; case imemo_svar: @@ -360,11 +381,11 @@ check_method_entry(VALUE obj, int can_be_svar) } } -const rb_method_entry_t * +const rb_callable_method_entry_t * rb_vm_frame_method_entry(const rb_control_frame_t *cfp) { VALUE *ep = cfp->ep; - rb_method_entry_t *me; + rb_callable_method_entry_t *me; while (!VM_EP_LEP_P(ep)) { if ((me = check_method_entry(ep[-1], FALSE)) != NULL) return me; @@ -375,7 +396,7 @@ rb_vm_frame_method_entry(const rb_control_frame_t *cfp) } static rb_cref_t * -method_entry_cref(rb_method_entry_t *me) +method_entry_cref(rb_callable_method_entry_t *me) { switch (me->def->type) { case VM_METHOD_TYPE_ISEQ: @@ -396,7 +417,7 @@ check_cref(VALUE obj, int can_be_svar) switch (imemo_type(obj)) { case imemo_ment: - return method_entry_cref((rb_method_entry_t *)obj); + return method_entry_cref((rb_callable_method_entry_t *)obj); case imemo_cref: return (rb_cref_t *)obj; case imemo_svar: @@ -558,15 +579,7 @@ vm_check_if_namespace(VALUE klass) static inline VALUE vm_get_iclass(rb_control_frame_t *cfp, VALUE klass) { - if (RB_TYPE_P(klass, T_MODULE) && - FL_TEST(klass, RMODULE_IS_OVERLAID) && - RB_TYPE_P(cfp->klass, T_ICLASS) && - RBASIC(cfp->klass)->klass == klass) { - return cfp->klass; - } - else { - return klass; - } + return klass; } static inline VALUE @@ -1040,7 +1053,8 @@ vm_search_method(rb_call_info_t *ci, VALUE recv) } #endif - ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class); + ci->me = rb_callable_method_entry(klass, ci->mid); + VM_ASSERT(callable_method_entry_p(ci->me)); ci->klass = klass; ci->call = vm_call_general; #if OPT_INLINE_METHOD_CACHE @@ -1050,7 +1064,7 @@ vm_search_method(rb_call_info_t *ci, VALUE recv) } static inline int -check_cfunc(const rb_method_entry_t *me, VALUE (*func)()) +check_cfunc(const rb_callable_method_entry_t *me, VALUE (*func)()) { if (me && me->def->type == VM_METHOD_TYPE_CFUNC && me->def->body.cfunc.func == func) { @@ -1114,12 +1128,11 @@ rb_equal_opt(VALUE obj1, VALUE obj2) ci.klass = 0; ci.method_state = 0; ci.me = NULL; - ci.defined_class = 0; + ci.class_serial = 0; return opt_eq_func(obj1, obj2, &ci); } -static VALUE -vm_call0(rb_thread_t*, VALUE, ID, int, const VALUE*, const rb_method_entry_t*, VALUE); +static VALUE vm_call0(rb_thread_t*, VALUE, ID, int, const VALUE*, const rb_callable_method_entry_t *); static VALUE check_match(VALUE pattern, VALUE target, enum vm_check_match_type type) @@ -1133,10 +1146,9 @@ check_match(VALUE pattern, VALUE target, enum vm_check_match_type type) } /* fall through */ case VM_CHECKMATCH_TYPE_CASE: { - VALUE defined_class; - const rb_method_entry_t *me = rb_method_entry_with_refinements(CLASS_OF(pattern), idEqq, &defined_class); + const rb_callable_method_entry_t *me = rb_callable_method_entry_with_refinements(CLASS_OF(pattern), idEqq); if (me) { - return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me, defined_class); + return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me); } else { /* fallback to funcall (e.g. method_missing) */ @@ -1352,7 +1364,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info { int i, local_size; VALUE *argv = cfp->sp - ci->argc; - const rb_method_entry_t *me = ci->me; + const rb_callable_method_entry_t *me = ci->me; rb_iseq_t *iseq = def_iseq_ptr(me->def); VALUE *sp = argv + iseq->param.size; @@ -1361,7 +1373,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info *sp++ = Qnil; } - vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class, + vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me, iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, iseq->stack_max); @@ -1374,7 +1386,7 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in { int i; VALUE *argv = cfp->sp - ci->argc; - const rb_method_entry_t *me = ci->me; + const rb_callable_method_entry_t *me = ci->me; rb_iseq_t *iseq = def_iseq_ptr(me->def); VALUE *src_argv = argv; VALUE *sp_orig, *sp; @@ -1401,8 +1413,7 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in } vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag, - ci->recv, ci->defined_class, - VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me, + ci->recv, VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me, iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, iseq->stack_max); cfp->sp = sp_orig; @@ -1541,7 +1552,7 @@ vm_profile_show_result(void) static inline const rb_method_cfunc_t * -vm_method_cfunc_entry(const rb_method_entry_t *me) +vm_method_cfunc_entry(const rb_callable_method_entry_t *me) { #if VM_DEBUG_VERIFY_METHOD_CACHE switch (me->def->type) { @@ -1571,20 +1582,19 @@ static VALUE vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) { VALUE val; - const rb_method_entry_t *me = ci->me; + const rb_callable_method_entry_t *me = ci->me; const rb_method_cfunc_t *cfunc = vm_method_cfunc_entry(me); int len = cfunc->argc; /* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */ VALUE recv = ci->recv; - VALUE defined_class = ci->defined_class; rb_block_t *blockptr = ci->blockptr; int argc = ci->argc; - RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id); - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef); + RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, me->called_id); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->owner, Qundef); - vm_push_frame(th, NULL, VM_FRAME_MAGIC_CFUNC, recv, defined_class, + vm_push_frame(th, NULL, VM_FRAME_MAGIC_CFUNC, recv, VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)me, 0, th->cfp->sp, 1, 0); @@ -1600,8 +1610,8 @@ vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_i vm_pop_frame(th); - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val); - RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->owner, val); + RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->called_id); return val; } @@ -1644,15 +1654,15 @@ static VALUE vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) { VALUE val; - const rb_method_entry_t *me = ci->me; + const rb_callable_method_entry_t *me = ci->me; int len = vm_method_cfunc_entry(me)->argc; VALUE recv = ci->recv; CALLER_SETUP_ARG(reg_cfp, ci); if (len >= 0) rb_check_arity(ci->argc, len, len); - RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id); - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qnil); + RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, me->called_id); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->owner, Qnil); if (!(ci->me->def->flag & METHOD_VISI_PROTECTED) && !(ci->flag & VM_CALL_ARGS_SPLAT) && @@ -1661,8 +1671,8 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) } val = vm_call_cfunc_latter(th, reg_cfp, ci); - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val); - RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->owner, val); + RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->called_id); return val; } @@ -1671,11 +1681,11 @@ void rb_vm_call_cfunc_push_frame(rb_thread_t *th) { rb_call_info_t *ci = th->passed_ci; - const rb_method_entry_t *me = ci->me; + const rb_callable_method_entry_t *me = ci->me; th->passed_ci = 0; - vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class, - VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me /* cref */, + vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, + ci->recv, VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me /* cref */, 0, th->cfp->sp + ci->aux.inc_sp, 1, 0); if (ci->call != vm_call_general) { @@ -1716,7 +1726,7 @@ vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv) /* control block frame */ th->passed_bmethod_me = ci->me; GetProcPtr(ci->me->def->body.proc, proc); - val = vm_invoke_bmethod(th, proc, ci->recv, ci->defined_class, ci->argc, argv, ci->blockptr); + val = vm_invoke_bmethod(th, proc, ci->recv, ci->argc, argv, ci->blockptr); return val; } @@ -1790,7 +1800,7 @@ vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *c ci->argc -= 1; DEC_SP(1); } - ci->me = rb_method_entry_without_refinements(CLASS_OF(ci->recv), ci->mid, &ci->defined_class); + ci->me = rb_callable_method_entry_without_refinements(CLASS_OF(ci->recv), ci->mid); ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND; @@ -1828,7 +1838,7 @@ vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf ci_entry.mid = idMethodMissing; ci_entry.blockptr = ci->blockptr; ci_entry.recv = ci->recv; - ci_entry.me = rb_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing, &ci_entry.defined_class); + ci_entry.me = rb_callable_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing); ci_entry.kw_arg = NULL; /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */ @@ -1892,6 +1902,55 @@ find_defined_class_by_owner(VALUE current_class, VALUE target_owner) return current_class; /* maybe module function */ } +static rb_method_definition_t *method_definition_create(rb_method_type_t type, ID mid); +static void method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts); + +static const rb_callable_method_entry_t * +aliased_callable_method_entry(const rb_callable_method_entry_t *me) +{ + const rb_method_entry_t *orig_me = me->def->body.alias.original_me; + const rb_callable_method_entry_t *cme; + + if (orig_me->defined_class == 0) { + VALUE defined_class = find_defined_class_by_owner(me->defined_class, orig_me->owner); + VM_ASSERT(RB_TYPE_P(orig_me->owner, T_MODULE)); + cme = rb_method_entry_complement_defined_class(orig_me, defined_class); + + if (me->def->alias_count == 0) { + RB_OBJ_WRITE(me, &me->def->body.alias.original_me, cme); + } + else { + method_definition_set((rb_method_entry_t *)me, + method_definition_create(VM_METHOD_TYPE_ALIAS, me->def->original_id), + (void *)cme); + } + } + else { + cme = (const rb_callable_method_entry_t *)orig_me; + } + + VM_ASSERT(callable_method_entry_p(cme)); + return cme; +} + +static const rb_callable_method_entry_t * +refined_method_callable_without_refinement(const rb_callable_method_entry_t *me) +{ + const rb_method_entry_t *orig_me = me->def->body.refined.orig_me; + const rb_callable_method_entry_t *cme; + + if (orig_me->defined_class == 0) { + cme = NULL; + rb_notimplement(); + } + else { + cme = (const rb_callable_method_entry_t *)orig_me; + } + + VM_ASSERT(callable_method_entry_p(cme)); + return cme; +} + static #ifdef _MSC_VER __forceinline @@ -1904,12 +1963,16 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) int enable_fastpath = 1; rb_call_info_t ci_temp; + VM_ASSERT(callable_method_entry_p(ci->me)); + start_method_dispatch: + VM_ASSERT(callable_method_entry_p(ci->me)); if (ci->me != 0) { if (LIKELY(METHOD_ENTRY_VISI(ci->me) == METHOD_VISI_PUBLIC && METHOD_ENTRY_SAFE(ci->me) == 0)) { VALUE klass; normal_method_dispatch: + VM_ASSERT(callable_method_entry_p(ci->me)); switch (ci->me->def->type) { case VM_METHOD_TYPE_ISEQ:{ CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath); @@ -1943,7 +2006,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) return vm_call_bmethod(th, cfp, ci); } case VM_METHOD_TYPE_ZSUPER:{ - klass = ci->me->klass; + klass = ci->me->owner; klass = RCLASS_ORIGIN(klass); zsuper_method_dispatch: klass = RCLASS_SUPER(klass); @@ -1954,7 +2017,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) ci_temp = *ci; ci = &ci_temp; - ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class); + ci->me = rb_callable_method_entry(klass, ci->mid); if (ci->me != 0) { goto normal_method_dispatch; @@ -1963,11 +2026,9 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) goto start_method_dispatch; } } - case VM_METHOD_TYPE_ALIAS: { - ci->me = ci->me->def->body.alias.original_me; - ci->defined_class = find_defined_class_by_owner(ci->defined_class, ci->me->klass /* owner */); + case VM_METHOD_TYPE_ALIAS: + ci->me = aliased_callable_method_entry(ci->me); goto normal_method_dispatch; - } case VM_METHOD_TYPE_OPTIMIZED:{ switch (ci->me->def->body.optimize_type) { case OPTIMIZED_METHOD_TYPE_SEND: @@ -1987,26 +2048,24 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) case VM_METHOD_TYPE_REFINED:{ const rb_cref_t *cref = rb_vm_get_cref(cfp->ep); VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil; - VALUE refinement, defined_class; - rb_method_entry_t *me; + VALUE refinement; + const rb_callable_method_entry_t *me; - refinement = find_refinement(refinements, - ci->defined_class); + refinement = find_refinement(refinements, ci->me->owner); if (NIL_P(refinement)) { goto no_refinement_dispatch; } - me = rb_method_entry(refinement, ci->mid, &defined_class); + me = rb_callable_method_entry(refinement, ci->mid); if (me) { if (ci->call == vm_call_super_method) { const rb_control_frame_t *top_cfp = current_method_entry(th, cfp); - const rb_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp); + const rb_callable_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp); if (top_me && rb_method_definition_eq(me->def, top_me->def)) { goto no_refinement_dispatch; } } ci->me = me; - ci->defined_class = defined_class; if (me->def->type != VM_METHOD_TYPE_REFINED) { goto start_method_dispatch; } @@ -2018,14 +2077,15 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) no_refinement_dispatch: if (ci->me->def->body.refined.orig_me) { - ci->me = ci->me->def->body.refined.orig_me; + ci->me = refined_method_callable_without_refinement(ci->me); + if (UNDEFINED_METHOD_ENTRY_P(ci->me)) { ci->me = 0; } goto start_method_dispatch; } else { - klass = ci->me->klass; + klass = ci->me->owner; goto zsuper_method_dispatch; } } @@ -2045,7 +2105,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) } else if (!(ci->flag & VM_CALL_OPT_SEND) && (METHOD_ENTRY_VISI(ci->me) == METHOD_VISI_PROTECTED)) { enable_fastpath = 0; - if (!rb_obj_is_kind_of(cfp->self, ci->defined_class)) { + if (!rb_obj_is_kind_of(cfp->self, ci->me->defined_class)) { ci->aux.method_missing_reason = MISSING_PROTECTED; return vm_call_method_missing(th, cfp, ci); } @@ -2113,7 +2173,7 @@ vm_super_outside(void) static int vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci) { - const rb_method_entry_t *me; + const rb_callable_method_entry_t *me; while (iseq && !iseq->klass) { iseq = iseq->parent_iseq; @@ -2157,10 +2217,11 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, } ci->mid = me->def->original_id; - ci->klass = vm_search_normal_superclass(lcfp->klass); + ci->klass = vm_search_normal_superclass(me->defined_class); } else { - ci->klass = vm_search_normal_superclass(reg_cfp->klass); + me = rb_vm_frame_method_entry(reg_cfp); + ci->klass = vm_search_normal_superclass(me->defined_class); } return 0; @@ -2172,12 +2233,14 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf VALUE current_defined_class; rb_iseq_t *iseq = GET_ISEQ(); VALUE sigval = TOPN(ci->argc); + const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(reg_cfp); - current_defined_class = GET_CFP()->klass; - if (NIL_P(current_defined_class)) { + if (!me) { vm_super_outside(); } + current_defined_class = me->defined_class; + if (!NIL_P(RCLASS_REFINED_CLASS(current_defined_class))) { current_defined_class = RCLASS_REFINED_CLASS(current_defined_class); } @@ -2212,7 +2275,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf } /* TODO: use inline cache */ - ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class); + ci->me = rb_callable_method_entry(ci->klass, ci->mid); ci->call = vm_call_super_method; while (iseq && !iseq->klass) { @@ -2220,8 +2283,8 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf } if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && def_iseq_ptr(ci->me->def) == iseq) { - ci->klass = RCLASS_SUPER(ci->defined_class); - ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class); + ci->klass = RCLASS_SUPER(ci->me->defined_class); + ci->me = rb_callable_method_entry(ci->klass, ci->mid); } } @@ -2242,15 +2305,14 @@ block_proc_is_lambda(const VALUE procval) } static inline VALUE -vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, - VALUE self, VALUE defined_class, +vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockargptr) { const struct vm_ifunc *ifunc = (struct vm_ifunc *)block->iseq; VALUE val, arg, blockarg; int lambda = block_proc_is_lambda(block->proc); - const rb_method_entry_t *me = th->passed_bmethod_me; + const rb_callable_method_entry_t *me = th->passed_bmethod_me; th->passed_bmethod_me = NULL; if (lambda) { @@ -2276,8 +2338,7 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, } vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, - self, defined_class, - VM_ENVVAL_PREV_EP_PTR(block->ep), (VALUE)me, + self, VM_ENVVAL_PREV_EP_PTR(block->ep), (VALUE)me, 0, th->cfp->sp, 1, 0); val = (*ifunc->func) (arg, ifunc->data, argc, argv, blockarg); @@ -2332,7 +2393,6 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci vm_push_frame(th, iseq, is_lambda ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK, block->self, - block->klass, VM_ENVVAL_PREV_EP_PTR(block->ep), 0, iseq->iseq_encoded + opt_pc, rsp + arg_size, @@ -2343,7 +2403,7 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci else { VALUE val; CALLER_SETUP_ARG(th->cfp, ci); - val = vm_yield_with_cfunc(th, block, block->self, block->klass, + val = vm_yield_with_cfunc(th, block, block->self, ci->argc, STACK_ADDR_FROM_TOP(ci->argc), 0); POPN(ci->argc); /* TODO: should put before C/yield? */ return val; @@ -2461,7 +2521,7 @@ vm_defined(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE break; case DEFINED_METHOD:{ VALUE klass = CLASS_OF(v); - const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj), 0); + const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj)); if (me) { switch (METHOD_ENTRY_VISI(me)) { -- cgit v1.2.3