From a1ee11d0bd0d5908d57a88fdcb1687ba0eec9350 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_eval.c | 111 +++++++++++++++++++++++++++++--------------------------------- 1 file changed, 51 insertions(+), 60 deletions(-) (limited to 'vm_eval.c') diff --git a/vm_eval.c b/vm_eval.c index bbc766617c..c63cffb15e 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -42,15 +42,13 @@ static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type sc static VALUE vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv); static VALUE -vm_call0(rb_thread_t* th, VALUE recv, ID id, int argc, const VALUE *argv, - const rb_method_entry_t *me, VALUE defined_class) +vm_call0(rb_thread_t* th, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me) { rb_call_info_t ci_entry, *ci = &ci_entry; ci->flag = 0; ci->mid = id; ci->recv = recv; - ci->defined_class = defined_class; ci->argc = argc; ci->me = me; ci->kw_arg = NULL; @@ -64,11 +62,11 @@ vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv) { VALUE val; - RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, ci->defined_class, ci->mid); - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->defined_class, Qnil); + RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, ci->me->owner, ci->mid); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->me->owner, Qnil); { rb_control_frame_t *reg_cfp = th->cfp; - const rb_method_entry_t *me = ci->me; + const rb_callable_method_entry_t *me = ci->me; const rb_method_cfunc_t *cfunc = &me->def->body.cfunc; int len = cfunc->argc; VALUE recv = ci->recv; @@ -95,8 +93,8 @@ vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv) vm_pop_frame(th); } } - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->defined_class, val); - RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, ci->defined_class, ci->mid); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->me->owner, val); + RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, ci->me->owner, ci->mid); return val; } @@ -105,21 +103,20 @@ static VALUE vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv) { 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 = &me->def->body.cfunc; int len = cfunc->argc; VALUE recv = ci->recv; - VALUE defined_class = ci->defined_class; int argc = ci->argc; ID mid = ci->mid; rb_block_t *blockptr = ci->blockptr; - RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, defined_class, mid); - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, mid, defined_class, Qnil); + RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, mid); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, mid, me->owner, Qnil); { rb_control_frame_t *reg_cfp = th->cfp; - vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class, + vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)me, 0, reg_cfp->sp, 1, 0); @@ -134,8 +131,8 @@ vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv VM_PROFILE_UP(3); vm_pop_frame(th); } - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, mid, defined_class, val); - RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, defined_class, mid); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, mid, me->owner, val); + RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, mid); return val; } @@ -198,14 +195,16 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv) case VM_METHOD_TYPE_REFINED: { const rb_method_type_t type = ci->me->def->type; + VALUE super_class; + if (type == VM_METHOD_TYPE_REFINED && 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); goto again; } - ci->defined_class = RCLASS_SUPER(ci->defined_class); + super_class = RCLASS_SUPER(ci->me->defined_class); - if (!ci->defined_class || !(ci->me = rb_method_entry(ci->defined_class, ci->mid, &ci->defined_class))) { + if (!super_class || !(ci->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(ci->recv, ci->mid, ci->argc, argv, ex); goto success; @@ -214,11 +213,8 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv) goto again; } 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); - goto again; - } + ci->me = aliased_callable_method_entry(ci->me); + goto again; case VM_METHOD_TYPE_MISSING: { VALUE new_args = rb_ary_new4(ci->argc, argv); @@ -258,10 +254,9 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv) } VALUE -rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv, - const rb_method_entry_t *me, VALUE defined_class) +rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me) { - return vm_call0(th, recv, id, argc, argv, me, defined_class); + return vm_call0(th, recv, id, argc, argv, me); } static inline VALUE @@ -270,22 +265,24 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv) VALUE recv = th->cfp->self; VALUE klass; ID id; - rb_method_entry_t *me; rb_control_frame_t *cfp = th->cfp; + const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp); - if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) || NIL_P(cfp->klass)) { + if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { rb_bug("vm_call_super: should not be reached"); } - klass = RCLASS_ORIGIN(cfp->klass); + klass = RCLASS_ORIGIN(me->defined_class); klass = RCLASS_SUPER(klass); - id = rb_vm_frame_method_entry(cfp)->def->original_id; - me = rb_method_entry(klass, id, &klass); + id = me->def->original_id; + me = rb_callable_method_entry(klass, id); + if (!me) { return method_missing(recv, id, argc, argv, MISSING_SUPER); } - - return vm_call0(th, recv, id, argc, argv, me, klass); + else { + return vm_call0(th, recv, id, argc, argv, me); + } } VALUE @@ -316,9 +313,8 @@ stack_check(void) } } -static inline rb_method_entry_t * - rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr); -static inline enum method_missing_reason rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self); +static inline const rb_callable_method_entry_t *rb_search_method_entry(VALUE recv, ID mid); +static inline enum method_missing_reason rb_method_call_status(rb_thread_t *th, const rb_callable_method_entry_t *me, call_type scope, VALUE self); /*! * \internal @@ -339,9 +335,7 @@ static inline VALUE rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope, VALUE self) { - VALUE defined_class; - rb_method_entry_t *me = - rb_search_method_entry(recv, mid, &defined_class); + const rb_callable_method_entry_t *me = rb_search_method_entry(recv, mid); rb_thread_t *th = GET_THREAD(); enum method_missing_reason call_status = rb_method_call_status(th, me, scope, self); @@ -349,7 +343,7 @@ rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, return method_missing(recv, mid, argc, argv, call_status); } stack_check(); - return vm_call0(th, recv, mid, argc, argv, me, defined_class); + return vm_call0(th, recv, mid, argc, argv, me); } struct rescue_funcall_args { @@ -384,13 +378,12 @@ check_funcall_failed(struct rescue_funcall_args *args, VALUE e) static int check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid) { - VALUE defined_class; - const rb_method_entry_t *me = rb_method_entry(klass, idRespond_to, &defined_class); + const rb_callable_method_entry_t *me = rb_callable_method_entry(klass, idRespond_to); if (me && !METHOD_ENTRY_BASIC(me)) { const rb_block_t *passed_block = th->passed_block; VALUE args[2], result; - int arity = rb_method_entry_arity(me); + int arity = rb_method_entry_arity((const rb_method_entry_t *)me); if (arity > 2) rb_raise(rb_eArgError, "respond_to? must accept 1 or 2 arguments (requires %d)", arity); @@ -399,7 +392,7 @@ check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid) args[0] = ID2SYM(mid); args[1] = Qtrue; - result = vm_call0(th, recv, idRespond_to, arity, args, me, defined_class); + result = vm_call0(th, recv, idRespond_to, arity, args, me); th->passed_block = passed_block; if (!RTEST(result)) { return FALSE; @@ -409,7 +402,7 @@ check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid) } static int -check_funcall_callable(rb_thread_t *th, const rb_method_entry_t *me) +check_funcall_callable(rb_thread_t *th, const rb_callable_method_entry_t *me) { return rb_method_call_status(th, me, CALL_FCALL, th->cfp->self) == MISSING_NONE; } @@ -438,19 +431,18 @@ VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv) { VALUE klass = CLASS_OF(recv); - const rb_method_entry_t *me; + const rb_callable_method_entry_t *me; rb_thread_t *th = GET_THREAD(); - VALUE defined_class; if (!check_funcall_respond_to(th, klass, recv, mid)) return Qundef; - me = rb_search_method_entry(recv, mid, &defined_class); + me = rb_search_method_entry(recv, mid); if (!check_funcall_callable(th, me)) { return check_funcall_missing(th, klass, recv, mid, argc, argv); } stack_check(); - return vm_call0(th, recv, mid, argc, argv, me, defined_class); + return vm_call0(th, recv, mid, argc, argv, me); } VALUE @@ -458,21 +450,20 @@ rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv, rb_check_funcall_hook *hook, VALUE arg) { VALUE klass = CLASS_OF(recv); - const rb_method_entry_t *me; + const rb_callable_method_entry_t *me; rb_thread_t *th = GET_THREAD(); - VALUE defined_class; if (!check_funcall_respond_to(th, klass, recv, mid)) return Qundef; - me = rb_search_method_entry(recv, mid, &defined_class); + me = rb_search_method_entry(recv, mid); if (!check_funcall_callable(th, me)) { (*hook)(FALSE, recv, mid, argc, argv, arg); return check_funcall_missing(th, klass, recv, mid, argc, argv); } stack_check(); (*hook)(TRUE, recv, mid, argc, argv, arg); - return vm_call0(th, recv, mid, argc, argv, me, defined_class); + return vm_call0(th, recv, mid, argc, argv, me); } static const char * @@ -511,8 +502,8 @@ rb_type_str(enum ruby_value_type type) #undef type_case } -static inline rb_method_entry_t * -rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr) +static inline const rb_callable_method_entry_t * +rb_search_method_entry(VALUE recv, ID mid) { VALUE klass = CLASS_OF(recv); @@ -550,11 +541,11 @@ rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr) rb_id2str(mid), type, (void *)recv, flags); } } - return rb_method_entry(klass, mid, defined_class_ptr); + return rb_callable_method_entry(klass, mid); } static inline enum method_missing_reason -rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self) +rb_method_call_status(rb_thread_t *th, const rb_callable_method_entry_t *me, call_type scope, VALUE self) { VALUE klass; ID oid; @@ -565,10 +556,11 @@ rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type sc return scope == CALL_VCALL ? MISSING_VCALL : MISSING_NOENTRY; } if (me->def->type == VM_METHOD_TYPE_REFINED) { - me = rb_resolve_refined_method(Qnil, me, NULL); + me = rb_resolve_refined_method_callable(Qnil, me); if (UNDEFINED_METHOD_ENTRY_P(me)) goto undefined; } - klass = me->klass; + + klass = me->owner; oid = me->def->original_id; visi = METHOD_ENTRY_VISI(me); @@ -1306,7 +1298,6 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_ } } vm_set_eval_stack(th, iseqval, cref, base_block); - th->cfp->klass = CLASS_OF(base_block->self); RB_GC_GUARD(crefval); if (0) { /* for debug */ -- cgit v1.2.3