summaryrefslogtreecommitdiff
path: root/proc.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-07-03 11:24:50 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-07-03 11:24:50 +0000
commit5e8a147480f87f19a8b96ad3fb33a25fb4bb19b9 (patch)
tree99be8701511a733ec86e5149d6662396e254f9f3 /proc.c
parent6ddfcd93fcad8d12ebd8365707b526946ae6e73e (diff)
* 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.c203
1 files changed, 103 insertions, 100 deletions
diff --git a/proc.c b/proc.c
index adb9f67..15a5cef 100644
--- a/proc.c
+++ b/proc.c
@@ -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);
}
/*