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 /proc.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 'proc.c')
-rw-r--r-- | proc.c | 203 |
1 files changed, 103 insertions, 100 deletions
@@ -21,11 +21,10 @@ const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase); struct METHOD { - VALUE recv; - VALUE rclass; - VALUE defined_class; - ID id; - rb_method_entry_t * const me; + const VALUE recv; + const VALUE klass; + const rb_method_entry_t * const me; + /* for bound methods, `me' should be rb_callable_method_entry_t * */ }; VALUE rb_cUnboundMethod; @@ -1105,9 +1104,8 @@ static void bm_mark(void *ptr) { struct METHOD *data = ptr; - rb_gc_mark(data->defined_class); - rb_gc_mark(data->rclass); rb_gc_mark(data->recv); + rb_gc_mark(data->klass); rb_gc_mark((VALUE)data->me); } @@ -1157,17 +1155,15 @@ respond_to_missing_p(VALUE klass, VALUE obj, VALUE sym, int scope) static VALUE -mnew_missing(VALUE rclass, VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass) +mnew_missing(VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass) { struct METHOD *data; VALUE method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data); rb_method_entry_t *me; rb_method_definition_t *def; - data->recv = obj; - data->rclass = rclass; - data->defined_class = klass; - data->id = rid; + RB_OBJ_WRITE(method, &data->recv, obj); + RB_OBJ_WRITE(method, &data->klass, klass); def = ZALLOC(rb_method_definition_t); def->type = VM_METHOD_TYPE_MISSING; @@ -1183,11 +1179,10 @@ mnew_missing(VALUE rclass, VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass) } static VALUE -mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass, +mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE obj, ID id, VALUE mclass, int scope, int error) { struct METHOD *data; - VALUE rclass = klass; VALUE method; ID rid = id; rb_method_visibility_t visi = METHOD_VISI_UNDEF; @@ -1195,7 +1190,7 @@ mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass, again: if (UNDEFINED_METHOD_ENTRY_P(me)) { if (respond_to_missing_p(klass, obj, ID2SYM(id), scope)) { - return mnew_missing(rclass, klass, obj, id, rid, mclass); + return mnew_missing(klass, obj, id, rid, mclass); } if (!error) return Qnil; rb_print_undef(klass, id, 0); @@ -1208,44 +1203,52 @@ mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass, } } if (me->def->type == VM_METHOD_TYPE_ZSUPER) { - klass = RCLASS_SUPER(defined_class); - id = me->def->original_id; - me = rb_method_entry_without_refinements(klass, id, &defined_class); + if (me->defined_class) { + VALUE klass = RCLASS_SUPER(me->defined_class); + id = me->def->original_id; + me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id); + } + else { + VALUE klass = RCLASS_SUPER(me->owner); + id = me->def->original_id; + me = rb_method_entry_without_refinements(klass, id); + } goto again; } - klass = defined_class; - - while (rclass != klass && - (FL_TEST(rclass, FL_SINGLETON) || RB_TYPE_P(rclass, T_ICLASS))) { - rclass = RCLASS_SUPER(rclass); + while (klass != me->owner && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) { + klass = RCLASS_SUPER(klass); } method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data); - data->recv = obj; - data->rclass = rclass; - data->defined_class = defined_class; - data->id = rid; - RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(me)); + RB_OBJ_WRITE(method, &data->recv, obj); + RB_OBJ_WRITE(method, &data->klass, klass); + RB_OBJ_WRITE(method, &data->me, me); + OBJ_INFECT(method, klass); return method; } static VALUE -mnew_from_me(const rb_method_entry_t *me, VALUE defined_class, VALUE klass, +mnew_from_me(const rb_method_entry_t *me, VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) { - return mnew_internal(me, defined_class, klass, obj, id, mclass, scope, TRUE); + return mnew_internal(me, klass, obj, id, mclass, scope, TRUE); } static VALUE mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) { - VALUE defined_class; - const rb_method_entry_t *me = - rb_method_entry_without_refinements(klass, id, &defined_class); - return mnew_from_me(me, defined_class, klass, obj, id, mclass, scope); + const rb_method_entry_t *me; + + if (obj == Qundef) { /* UnboundMethod */ + me = rb_method_entry_without_refinements(klass, id); + } + else { + me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id); + } + return mnew_from_me(me, klass, obj, id, mclass, scope); } @@ -1287,6 +1290,7 @@ static VALUE method_eq(VALUE method, VALUE other) { struct METHOD *m1, *m2; + VALUE klass1, klass2; if (!rb_obj_is_method(other)) return Qfalse; @@ -1297,8 +1301,12 @@ method_eq(VALUE method, VALUE other) m1 = (struct METHOD *)DATA_PTR(method); m2 = (struct METHOD *)DATA_PTR(other); + klass1 = m1->me->defined_class ? m1->me->defined_class : m1->me->owner; + klass2 = m2->me->defined_class ? m2->me->defined_class : m2->me->owner; + if (!rb_method_entry_eq(m1->me, m2->me) || - m1->rclass != m2->rclass || + klass1 != klass2 || + m1->klass != m2->klass || m1->recv != m2->recv) { return Qfalse; } @@ -1322,8 +1330,7 @@ method_hash(VALUE method) st_index_t hash; TypedData_Get_Struct(method, struct METHOD, &method_data_type, m); - hash = rb_hash_start((st_index_t)m->rclass); - hash = rb_hash_uint(hash, (st_index_t)m->recv); + hash = rb_hash_start((st_index_t)m->recv); hash = rb_hash_method_entry(hash, m->me); hash = rb_hash_end(hash); @@ -1348,11 +1355,9 @@ method_unbind(VALUE obj) TypedData_Get_Struct(obj, struct METHOD, &method_data_type, orig); method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD, &method_data_type, data); - data->recv = Qundef; - data->id = orig->id; + RB_OBJ_WRITE(method, &data->recv, Qundef); + RB_OBJ_WRITE(method, &data->klass, orig->klass); RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me)); - data->rclass = orig->rclass; - data->defined_class = orig->defined_class; OBJ_INFECT(method, obj); return method; @@ -1387,7 +1392,7 @@ method_name(VALUE obj) struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); - return ID2SYM(data->id); + return ID2SYM(data->me->called_id); } /* @@ -1417,16 +1422,8 @@ static VALUE method_owner(VALUE obj) { struct METHOD *data; - VALUE defined_class; - TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); - defined_class = data->defined_class; - - if (RB_TYPE_P(defined_class, T_ICLASS)) { - defined_class = RBASIC_CLASS(defined_class); - } - - return defined_class; + return data->me->owner; } void @@ -1462,7 +1459,7 @@ obj_method(VALUE obj, VALUE vid, int scope) if (!id) { if (respond_to_missing_p(klass, obj, vid, scope)) { id = rb_intern_str(vid); - return mnew_missing(klass, klass, obj, id, id, mclass); + return mnew_missing(klass, obj, id, id, mclass); } rb_method_name_error(klass, vid); } @@ -1551,7 +1548,7 @@ rb_obj_singleton_method(VALUE obj, VALUE vid) if (!NIL_P(klass = rb_singleton_class_get(obj)) && respond_to_missing_p(klass, obj, vid, FALSE)) { id = rb_intern_str(vid); - return mnew_missing(klass, klass, obj, id, id, rb_cMethod); + return mnew_missing(klass, obj, id, id, rb_cMethod); } rb_name_error_str(vid, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'", QUOTE(vid), obj); @@ -1562,7 +1559,7 @@ rb_obj_singleton_method(VALUE obj, VALUE vid) rb_name_error(id, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'", QUOTE_ID(id), obj); } - return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE); + return mnew_from_me(me, klass, obj, id, rb_cMethod, FALSE); } /* @@ -1704,17 +1701,16 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod) if (is_method) { struct METHOD *method = (struct METHOD *)DATA_PTR(body); - VALUE rclass = method->rclass; - if (rclass != mod && !RB_TYPE_P(rclass, T_MODULE) && - !RTEST(rb_class_inherited_p(mod, rclass))) { - if (FL_TEST(rclass, FL_SINGLETON)) { + if (method->me->owner != mod && !RB_TYPE_P(method->me->owner, T_MODULE) && + !RTEST(rb_class_inherited_p(mod, method->me->owner))) { + if (FL_TEST(method->me->owner, FL_SINGLETON)) { rb_raise(rb_eTypeError, "can't bind singleton method to a different class"); } else { rb_raise(rb_eTypeError, "bind argument must be a subclass of % "PRIsVALUE, - rb_class_name(rclass)); + rb_class_name(method->me->owner)); } } rb_method_entry_set(mod, id, method->me, scope_visi->method_visi); @@ -1732,7 +1728,6 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod) RB_OBJ_WRITE(proc->block.iseq->self, &proc->block.iseq->klass, mod); proc->is_lambda = TRUE; proc->is_from_method = TRUE; - proc->block.klass = mod; } rb_add_method(mod, id, VM_METHOD_TYPE_BMETHOD, (void *)body, scope_visi->method_visi); if (scope_visi->module_func) { @@ -1826,10 +1821,8 @@ method_clone(VALUE self) TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig); clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data); CLONESETUP(clone, self); - data->recv = orig->recv; - data->rclass = orig->rclass; - data->defined_class = orig->defined_class; - data->id = orig->id; + RB_OBJ_WRITE(clone, &data->recv, orig->recv); + RB_OBJ_WRITE(clone, &data->klass, orig->klass); RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me)); return clone; } @@ -1854,6 +1847,13 @@ rb_method_call(int argc, const VALUE *argv, VALUE method) return rb_method_call_with_block(argc, argv, method, proc); } +static const rb_callable_method_entry_t * +method_callable_method_entry(struct METHOD *data) +{ + if (data->me && data->me->defined_class == 0) rb_bug("method_callable_method_entry: not callable."); + return (const rb_callable_method_entry_t *)data->me; +} + VALUE rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_procval) { @@ -1877,7 +1877,6 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_ if ((state = EXEC_TAG()) == 0) { rb_thread_t *th = GET_THREAD(); rb_block_t *block = 0; - VALUE defined_class; if (!NIL_P(pass_procval)) { rb_proc_t *pass_proc; @@ -1887,9 +1886,7 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_ th->passed_block = block; VAR_INITIALIZED(data); - defined_class = data->defined_class; - if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass; - result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me, defined_class); + result = rb_vm_call(th, data->recv, data->me->called_id, argc, argv, method_callable_method_entry(data)); } POP_TAG(); if (safe >= 0) @@ -1994,12 +1991,12 @@ static VALUE umethod_bind(VALUE method, VALUE recv) { struct METHOD *data, *bound; - VALUE methclass; - VALUE rclass; + VALUE methclass, klass; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); - methclass = data->rclass; + methclass = data->me->owner; + if (!RB_TYPE_P(methclass, T_MODULE) && methclass != CLASS_OF(recv) && !rb_obj_is_kind_of(recv, methclass)) { if (FL_TEST(methclass, FL_SINGLETON)) { @@ -2012,24 +2009,23 @@ umethod_bind(VALUE method, VALUE recv) } } + klass = CLASS_OF(recv); + method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound); - bound->recv = data->recv; - bound->rclass = data->rclass; - bound->defined_class = data->defined_class; - bound->id = data->id; + RB_OBJ_WRITE(method, &bound->recv, recv); + RB_OBJ_WRITE(method, &bound->klass, data->klass); RB_OBJ_WRITE(method, &bound->me, rb_method_entry_clone(data->me)); - rclass = CLASS_OF(recv); - if (BUILTIN_TYPE(bound->defined_class) == T_MODULE) { - VALUE ic = rb_class_search_ancestor(rclass, bound->defined_class); + + if (RB_TYPE_P(bound->me->owner, T_MODULE)) { + VALUE ic = rb_class_search_ancestor(klass, bound->me->owner); if (ic) { - rclass = ic; + klass = ic; } else { - rclass = rb_include_class_new(methclass, rclass); + klass = rb_include_class_new(methclass, klass); } + RB_OBJ_WRITE(method, &bound->me, rb_method_entry_complement_defined_class(bound->me, klass)); } - bound->recv = recv; - bound->rclass = rclass; return method; } @@ -2150,14 +2146,12 @@ method_arity(VALUE method) static const rb_method_entry_t * original_method_entry(VALUE mod, ID id) { - VALUE rclass; const rb_method_entry_t *me; - while ((me = rb_method_entry(mod, id, &rclass)) != 0) { + while ((me = rb_method_entry(mod, id)) != 0) { const rb_method_definition_t *def = me->def; - if (!def) break; if (def->type != VM_METHOD_TYPE_ZSUPER) break; - mod = RCLASS_SUPER(rclass); + mod = RCLASS_SUPER(me->owner); id = def->original_id; } return me; @@ -2322,6 +2316,7 @@ method_inspect(VALUE method) const char *s; const char *sharp = "#"; VALUE mklass; + VALUE defined_class; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); str = rb_str_buf_new2("#<"); @@ -2329,7 +2324,19 @@ method_inspect(VALUE method) rb_str_buf_cat2(str, s); rb_str_buf_cat2(str, ": "); - mklass = data->me->klass; + mklass = data->klass; + + if (data->me && data->me->def->type == VM_METHOD_TYPE_ALIAS) { + defined_class = data->me->def->body.alias.original_me->owner; + } + else { + defined_class = data->me->defined_class ? data->me->defined_class : data->me->owner; + } + + if (RB_TYPE_P(defined_class, T_ICLASS)) { + defined_class = RBASIC_CLASS(defined_class); + } + if (FL_TEST(mklass, FL_SINGLETON)) { VALUE v = rb_ivar_get(mklass, attached); @@ -2349,16 +2356,16 @@ method_inspect(VALUE method) } } else { - rb_str_buf_append(str, rb_class_name(data->rclass)); - if (data->rclass != mklass) { + rb_str_buf_append(str, rb_class_name(mklass)); + if (defined_class != mklass) { rb_str_buf_cat2(str, "("); - rb_str_buf_append(str, rb_class_name(mklass)); + rb_str_buf_append(str, rb_class_name(defined_class)); rb_str_buf_cat2(str, ")"); } } rb_str_buf_cat2(str, sharp); - rb_str_append(str, rb_id2str(data->id)); - if (data->id != data->me->def->original_id) { + rb_str_append(str, rb_id2str(data->me->called_id)); + if (data->me->called_id != data->me->def->original_id) { rb_str_catf(str, "(%"PRIsVALUE")", rb_id2str(data->me->def->original_id)); } @@ -2444,19 +2451,15 @@ static VALUE method_super_method(VALUE method) { const struct METHOD *data; - VALUE defined_class, super_class; + VALUE super_class; const rb_method_entry_t *me; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); - defined_class = data->defined_class; - if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass; - super_class = RCLASS_SUPER(defined_class); + super_class = RCLASS_SUPER(data->me->defined_class); if (!super_class) return Qnil; - me = rb_method_entry_without_refinements(super_class, data->id, &defined_class); + me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(super_class, data->me->called_id); if (!me) return Qnil; - return mnew_internal(me, defined_class, - super_class, data->recv, data->id, - rb_obj_class(method), FALSE, FALSE); + return mnew_internal(me, super_class, data->recv, data->me->called_id, rb_obj_class(method), FALSE, FALSE); } /* |