diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-07-03 11:24:50 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-07-03 11:24:50 +0000 |
commit | 5e8a147480f87f19a8b96ad3fb33a25fb4bb19b9 (patch) | |
tree | 99be8701511a733ec86e5149d6662396e254f9f3 /vm.c | |
parent | 6ddfcd93fcad8d12ebd8365707b526946ae6e73e (diff) | |
download | ruby-5e8a147480f87f19a8b96ad3fb33a25fb4bb19b9.tar.gz |
* 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
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 99 |
1 files changed, 44 insertions, 55 deletions
@@ -8,6 +8,8 @@ **********************************************************************/ +#define VM_CHECK_MODE 0 + #include "internal.h" #include "ruby/vm.h" #include "ruby/st.h" @@ -128,10 +130,10 @@ static void vm_collect_usage_register(int reg, int isset); #endif static VALUE -vm_invoke_bmethod(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class, +vm_invoke_bmethod(rb_thread_t *th, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockptr); static VALUE -vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class, +vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockptr); static rb_serial_t ruby_vm_global_method_state = 1; @@ -253,8 +255,7 @@ vm_set_top_stack(rb_thread_t *th, VALUE iseqval) } /* for return */ - vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, - th->top_self, rb_cObject, + vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, th->top_self, VM_ENVVAL_BLOCK_PTR(0), (VALUE)vm_cref_new_toplevel(th), /* cref or me */ iseq->iseq_encoded, th->cfp->sp, iseq->local_size, iseq->stack_max); @@ -267,8 +268,7 @@ vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const rb_cref_t *cref, rb_blo GetISeqPtr(iseqval, iseq); vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH, - base_block->self, base_block->klass, - VM_ENVVAL_PREV_EP_PTR(base_block->ep), + base_block->self, VM_ENVVAL_PREV_EP_PTR(base_block->ep), (VALUE)cref, /* cref or me */ iseq->iseq_encoded, th->cfp->sp, iseq->local_size, iseq->stack_max); @@ -343,10 +343,10 @@ void rb_vm_pop_cfunc_frame(void) { rb_thread_t *th = GET_THREAD(); - const rb_method_entry_t *me = rb_vm_frame_method_entry(th->cfp); + const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(th->cfp); - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil); - RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->owner, Qnil); + RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->called_id); vm_pop_frame(th); } @@ -557,7 +557,6 @@ vm_make_env_each(const rb_thread_t *const th, rb_control_frame_t *const cfp, /* as Binding */ env->block.self = cfp->self; - env->block.klass = 0; env->block.ep = cfp->ep; env->block.iseq = cfp->iseq; env->block.proc = 0; @@ -809,7 +808,7 @@ static inline VALUE invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockptr, const rb_cref_t *cref, - VALUE defined_class, int splattable) + int splattable) { if (SPECIAL_CONST_P(block->iseq)) { return Qnil; @@ -820,7 +819,7 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, const rb_control_frame_t *cfp; int i, opt_pc, arg_size = iseq->param.size; int type = block_proc_is_lambda(block->proc) ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK; - 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; cfp = th->cfp; @@ -833,20 +832,18 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, if (me != 0) { /* bmethod */ - vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_BMETHOD, - self, defined_class, + vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_BMETHOD, self, VM_ENVVAL_PREV_EP_PTR(block->ep), (VALUE)me, /* cref or method (TODO: can we ignore cref?) */ iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, iseq->local_size - arg_size, iseq->stack_max); - RUBY_DTRACE_METHOD_ENTRY_HOOK(th, me->klass, me->called_id); - EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->called_id, me->klass, Qnil); + RUBY_DTRACE_METHOD_ENTRY_HOOK(th, me->owner, me->called_id); + EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->called_id, me->owner, Qnil); } else { - vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH, - self, defined_class, + vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH, self, VM_ENVVAL_PREV_EP_PTR(block->ep), (VALUE)cref, /* cref or method */ iseq->iseq_encoded + opt_pc, @@ -858,15 +855,14 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, if (me) { /* bmethod */ - EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->called_id, me->klass, ret); - RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id); + EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->called_id, me->owner, ret); + RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->owner, me->called_id); } return ret; } else { - return vm_yield_with_cfunc(th, block, self, defined_class, - argc, argv, blockptr); + return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr); } } @@ -886,28 +882,25 @@ static inline VALUE vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const rb_cref_t *cref) { const rb_block_t *blockptr = check_block(th); - return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref, - blockptr->klass, 1); + return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref, 1); } static inline VALUE vm_yield(rb_thread_t *th, int argc, const VALUE *argv) { const rb_block_t *blockptr = check_block(th); - return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0, - blockptr->klass, 1); + return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0, 1); } static inline VALUE vm_yield_with_block(rb_thread_t *th, int argc, const VALUE *argv, const rb_block_t *blockargptr) { const rb_block_t *blockptr = check_block(th); - return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, blockargptr, 0, - blockptr->klass, 1); + return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, blockargptr, 0, 1); } static VALUE -vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class, +vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockptr) { VALUE val = Qundef; @@ -917,8 +910,7 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { th->safe_level = proc->safe_level; - val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0, - defined_class, 0); + val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0, 0); } TH_POP_TAG(); @@ -931,11 +923,10 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class } static VALUE -vm_invoke_bmethod(rb_thread_t *th, rb_proc_t *proc, VALUE self, VALUE defined_class, +vm_invoke_bmethod(rb_thread_t *th, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockptr) { - return invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0, - defined_class, 0); + return invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0, 0); } VALUE @@ -943,12 +934,11 @@ rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, int argc, const VALUE *argv, const rb_block_t *blockptr) { VALUE self = proc->block.self; - VALUE defined_class = proc->block.klass; if (proc->is_from_method) { - return vm_invoke_bmethod(th, proc, self, defined_class, argc, argv, blockptr); + return vm_invoke_bmethod(th, proc, self, argc, argv, blockptr); } else { - return vm_invoke_proc(th, proc, self, defined_class, argc, argv, blockptr); + return vm_invoke_proc(th, proc, self, argc, argv, blockptr); } } @@ -1260,12 +1250,12 @@ static int check_redefined_method(st_data_t key, st_data_t value, st_data_t data) { ID mid = (ID)key; - rb_method_entry_t *me = (rb_method_entry_t *)value; VALUE klass = (VALUE)data; - rb_method_entry_t *newme = rb_method_entry(klass, mid, NULL); + const rb_method_entry_t *me = (rb_method_entry_t *)value; + const rb_method_entry_t *newme = rb_method_entry(klass, mid); + + if (newme != me) rb_vm_check_redefinition_opt_method(me, me->owner); - if (newme != me) - rb_vm_check_redefinition_opt_method(me, me->klass); return ST_CONTINUE; } @@ -1280,7 +1270,7 @@ rb_vm_check_redefinition_by_prepend(VALUE klass) static void add_opt_method(VALUE klass, ID mid, VALUE bop) { - rb_method_entry_t *me = rb_method_entry_at(klass, mid); + const rb_method_entry_t *me = rb_method_entry_at(klass, mid); if (me && me->def->type == VM_METHOD_TYPE_CFUNC) { st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop); @@ -1361,7 +1351,7 @@ hook_before_rewind(rb_thread_t *th, rb_control_frame_t *cfp) EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil); EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self, rb_vm_frame_method_entry(th->cfp)->called_id, - rb_vm_frame_method_entry(th->cfp)->klass, Qnil); + rb_vm_frame_method_entry(th->cfp)->owner, Qnil); } else { EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil); @@ -1508,8 +1498,10 @@ vm_exec(rb_thread_t *th) while (th->cfp->pc == 0 || th->cfp->iseq == 0) { if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) { EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, - rb_vm_frame_method_entry(th->cfp)->called_id, rb_vm_frame_method_entry(th->cfp)->klass, Qnil); - RUBY_DTRACE_METHOD_RETURN_HOOK(th, rb_vm_frame_method_entry(th->cfp)->klass, + rb_vm_frame_method_entry(th->cfp)->called_id, + rb_vm_frame_method_entry(th->cfp)->owner, Qnil); + RUBY_DTRACE_METHOD_RETURN_HOOK(th, + rb_vm_frame_method_entry(th->cfp)->owner, rb_vm_frame_method_entry(th->cfp)->called_id); } th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); @@ -1673,7 +1665,7 @@ vm_exec(rb_thread_t *th) /* push block frame */ cfp->sp[0] = (VALUE)err; vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE, - cfp->self, cfp->klass, + cfp->self, VM_ENVVAL_PREV_EP_PTR(cfp->ep), 0, /* cref or me */ catch_iseq->iseq_encoded, @@ -1738,11 +1730,11 @@ rb_iseq_eval_main(VALUE iseqval) int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp) { - const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp); + const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp); if (me) { if (idp) *idp = me->def->original_id; - if (klassp) *klassp = me->klass; + if (klassp) *klassp = me->owner; return TRUE; } else { @@ -1766,7 +1758,7 @@ VALUE rb_thread_current_status(const rb_thread_t *th) { const rb_control_frame_t *cfp = th->cfp; - const rb_method_entry_t *me; + const rb_callable_method_entry_t *me; VALUE str = Qnil; if (cfp->iseq != 0) { @@ -1779,7 +1771,7 @@ rb_thread_current_status(const rb_thread_t *th) } else if ((me = rb_vm_frame_method_entry(cfp)) && me->def->original_id) { str = rb_sprintf("`%"PRIsVALUE"#%"PRIsVALUE"' (cfunc)", - rb_class_path(me->klass), + rb_class_path(me->owner), rb_id2str(me->def->original_id)); } @@ -1796,7 +1788,7 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, VALUE val; vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, - recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), + recv, VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)vm_cref_new_toplevel(th), /* cref or me */ 0, reg_cfp->sp, 1, 0); @@ -2073,7 +2065,6 @@ rb_thread_mark(void *ptr) rb_iseq_t *iseq = cfp->iseq; rb_gc_mark(cfp->proc); rb_gc_mark(cfp->self); - rb_gc_mark(cfp->klass); if (iseq) { rb_gc_mark(RUBY_VM_NORMAL_ISEQ_P(iseq) ? iseq->self : (VALUE)iseq); } @@ -2231,7 +2222,7 @@ th_init(rb_thread_t *th, VALUE self) th->cfp = (void *)(th->stack + th->stack_size); vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_DUMMY | VM_FRAME_FLAG_FINISH /* dummy frame */, - Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0) /* dummy block ptr */, + Qnil /* dummy self */, VM_ENVVAL_BLOCK_PTR(0) /* dummy block ptr */, 0 /* dummy cref/me */, 0 /* dummy pc */, th->stack, 1, 0); @@ -2544,7 +2535,6 @@ Init_VM(void) rb_define_method_id(klass, idLambda, rb_block_lambda, 0); rb_obj_freeze(fcore); RBASIC_CLEAR_CLASS(klass); - RCLASS_SET_SUPER(klass, 0); rb_obj_freeze(klass); rb_gc_register_mark_object(fcore); rb_mRubyVMFrozenCore = fcore; @@ -2793,7 +2783,6 @@ Init_VM(void) th->cfp->iseq = iseq; th->cfp->pc = iseq->iseq_encoded; th->cfp->self = th->top_self; - th->cfp->klass = Qnil; th->cfp->ep[-1] = (VALUE)vm_cref_new(rb_cObject, METHOD_VISI_PRIVATE, NULL); |