aboutsummaryrefslogtreecommitdiffstats
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
commita1ee11d0bd0d5908d57a88fdcb1687ba0eec9350 (patch)
tree99be8701511a733ec86e5149d6662396e254f9f3
parentf6e0ac0044338d522da85d296ce6f5a2c699689f (diff)
downloadruby-a1ee11d0bd0d5908d57a88fdcb1687ba0eec9350.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
-rw-r--r--ChangeLog115
-rw-r--r--class.c8
-rw-r--r--cont.c1
-rw-r--r--eval.c14
-rw-r--r--gc.c8
-rw-r--r--insns.def3
-rw-r--r--internal.h2
-rw-r--r--method.h51
-rw-r--r--proc.c203
-rw-r--r--vm.c99
-rw-r--r--vm_args.c2
-rw-r--r--vm_backtrace.c2
-rw-r--r--vm_core.h20
-rw-r--r--vm_dump.c2
-rw-r--r--vm_eval.c111
-rw-r--r--vm_insnhelper.c250
-rw-r--r--vm_method.c310
17 files changed, 748 insertions, 453 deletions
diff --git a/ChangeLog b/ChangeLog
index 5e304ff045..82374795fc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,118 @@
+Fri Jul 03 20:05:10 2015 Koichi Sasada <ko1@atdot.net>
+
+ * 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.
+
Fri Jul 3 14:30:18 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* win32/file.c: some mingw compilers need a tweek for the
diff --git a/class.c b/class.c
index 6207fb7c5a..0521cf96c3 100644
--- a/class.c
+++ b/class.c
@@ -1119,10 +1119,10 @@ method_entry_i(st_data_t key, st_data_t value, st_data_t data)
rb_method_visibility_t type;
if (me->def->type == VM_METHOD_TYPE_REFINED) {
- VALUE klass = me->klass;
- me = rb_resolve_refined_method(Qnil, me, NULL);
+ VALUE owner = me->owner;
+ me = rb_resolve_refined_method(Qnil, me);
if (!me) return ST_CONTINUE;
- if (!arg->recur && me->klass != klass) return ST_CONTINUE;
+ if (!arg->recur && me->owner != owner) return ST_CONTINUE;
}
if (!st_lookup(arg->list, key, 0)) {
if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -1718,7 +1718,7 @@ rb_define_attr(VALUE klass, const char *name, int read, int write)
int
rb_obj_basic_to_s_p(VALUE obj)
{
- const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"), 0);
+ const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"));
if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC &&
me->def->body.cfunc.func == rb_any_to_s)
return 1;
diff --git a/cont.c b/cont.c
index 19e8122c83..0ad91619bc 100644
--- a/cont.c
+++ b/cont.c
@@ -1203,7 +1203,6 @@ fiber_init(VALUE fibval, VALUE proc)
th->cfp->ep = th->stack;
*th->cfp->ep = VM_ENVVAL_BLOCK_PTR(0);
th->cfp->self = Qnil;
- th->cfp->klass = Qnil;
th->cfp->flag = 0;
th->cfp->iseq = 0;
th->cfp->proc = 0;
diff --git a/eval.c b/eval.c
index 3cc9a2efe9..3462a802d4 100644
--- a/eval.c
+++ b/eval.c
@@ -748,8 +748,8 @@ rb_raise_jump(VALUE mesg, VALUE cause)
{
rb_thread_t *th = GET_THREAD();
const rb_control_frame_t *cfp = th->cfp;
- const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp);
- VALUE klass = me->klass;
+ const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
+ VALUE klass = me->owner;
VALUE self = cfp->self;
ID mid = me->called_id;
@@ -922,7 +922,7 @@ rb_ensure(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*e_proc)(ANYARGS), VALUE
return result;
}
-static const rb_method_entry_t *
+static const rb_callable_method_entry_t *
method_entry_of_iseq(const rb_control_frame_t *cfp, const rb_iseq_t *iseq)
{
rb_thread_t *th = GET_THREAD();
@@ -939,9 +939,9 @@ method_entry_of_iseq(const rb_control_frame_t *cfp, const rb_iseq_t *iseq)
static ID
frame_func_id(rb_control_frame_t *cfp)
{
- const rb_method_entry_t *me_local;
const rb_iseq_t *iseq = cfp->iseq;
- const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp);
+ const rb_callable_method_entry_t *me_local;
+ const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
if (me) {
return me->def->original_id;
@@ -970,9 +970,9 @@ frame_func_id(rb_control_frame_t *cfp)
static ID
frame_called_id(rb_control_frame_t *cfp)
{
- const rb_method_entry_t *me_local;
const rb_iseq_t *iseq = cfp->iseq;
- const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp);
+ const rb_callable_method_entry_t *me_local;
+ const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
if (me) {
return me->called_id;
diff --git a/gc.c b/gc.c
index 550c11767f..31a5d1378d 100644
--- a/gc.c
+++ b/gc.c
@@ -2105,6 +2105,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
rb_free_m_tbl(RCLASS_M_TBL(obj));
}
+ rb_free_m_tbl(RCLASS_CALLABLE_M_TBL(obj));
if (RCLASS_EXT(obj)->subclasses) {
rb_class_detach_subclasses(obj);
RCLASS_EXT(obj)->subclasses = NULL;
@@ -3926,7 +3927,8 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
{
const rb_method_definition_t *def = me->def;
- gc_mark(objspace, me->klass);
+ gc_mark(objspace, me->owner);
+ gc_mark(objspace, me->defined_class);
if (def) {
switch (def->type) {
@@ -3946,6 +3948,7 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
return;
case VM_METHOD_TYPE_REFINED:
gc_mark(objspace, (VALUE)def->body.refined.orig_me);
+ gc_mark(objspace, (VALUE)def->body.refined.owner);
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_ZSUPER:
@@ -4324,6 +4327,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
mark_m_tbl(objspace, RCLASS_M_TBL(obj));
}
+ mark_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
if (!RCLASS_EXT(obj)) break;
gc_mark(objspace, RCLASS_SUPER((VALUE)obj));
break;
@@ -8953,7 +8957,7 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
if (imemo_type(obj) == imemo_ment) {
const rb_method_entry_t *me = &RANY(obj)->as.imemo.ment;
snprintf(buff, buff_size, "%s (called_id: %s, type: %s, alias: %d, class: %s)", buff,
- rb_id2name(me->called_id), method_type_name(me->def->type), me->def->alias_count, obj_info(me->klass));
+ rb_id2name(me->called_id), method_type_name(me->def->type), me->def->alias_count, obj_info(me->defined_class));
}
}
default:
diff --git a/insns.def b/insns.def
index 70b4cfb69e..c2697c60d5 100644
--- a/insns.def
+++ b/insns.def
@@ -914,8 +914,7 @@ defineclass
}
/* enter scope */
- vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS,
- klass, 0,
+ vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS, klass,
VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
(VALUE)vm_cref_push(th, klass, NULL),
class_iseq->iseq_encoded, GET_SP(),
diff --git a/internal.h b/internal.h
index 32ad346e07..86bf5fd9cc 100644
--- a/internal.h
+++ b/internal.h
@@ -456,6 +456,7 @@ struct rb_classext_struct {
struct st_table *iv_index_tbl;
struct st_table *iv_tbl;
struct st_table *const_tbl;
+ struct st_table *callable_m_tbl;
rb_subclass_entry_t *subclasses;
rb_subclass_entry_t **parent_subclasses;
/**
@@ -477,6 +478,7 @@ void rb_class_remove_from_super_subclasses(VALUE);
#define RCLASS_IV_TBL(c) (RCLASS_EXT(c)->iv_tbl)
#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
+#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl)
#define RCLASS_IV_INDEX_TBL(c) (RCLASS_EXT(c)->iv_index_tbl)
#define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin_)
#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class)
diff --git a/method.h b/method.h
index f66a384d7d..2a75c810c0 100644
--- a/method.h
+++ b/method.h
@@ -47,12 +47,20 @@ typedef struct rb_cref_struct {
typedef struct rb_method_entry_struct {
VALUE flags;
- VALUE dummy;
+ const VALUE defined_class;
struct rb_method_definition_struct * const def;
ID called_id;
- const VALUE klass; /* should be marked */
+ const VALUE owner;
} rb_method_entry_t;
+typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_entry_t */
+ VALUE flags;
+ const VALUE defined_class;
+ struct rb_method_definition_struct * const def;
+ ID called_id;
+ const VALUE owner;
+} rb_callable_method_entry_t;
+
#define METHOD_ENTRY_VISI(me) (rb_method_visibility_t)(((me)->flags & (IMEMO_FL_USER0 | IMEMO_FL_USER1)) >> (IMEMO_FL_USHIFT+0))
#define METHOD_ENTRY_BASIC(me) (int) (((me)->flags & (IMEMO_FL_USER2 )) >> (IMEMO_FL_USHIFT+2))
#define METHOD_ENTRY_SAFE(me) (int) (((me)->flags & (IMEMO_FL_USER3 | IMEMO_FL_USER4)) >> (IMEMO_FL_USHIFT+3))
@@ -85,6 +93,13 @@ METHOD_ENTRY_FLAGS_SET(rb_method_entry_t *me, rb_method_visibility_t visi, unsig
(me->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4)) |
((visi << IMEMO_FL_USHIFT+0) | (basic << (IMEMO_FL_USHIFT+2)) | (safe << IMEMO_FL_USHIFT+3));
}
+static inline void
+METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src)
+{
+ dst->flags =
+ (dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4)) |
+ (src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4));
+}
typedef enum {
VM_METHOD_TYPE_ISEQ,
@@ -127,6 +142,7 @@ typedef struct rb_method_alias_struct {
typedef struct rb_method_refined_struct {
const struct rb_method_entry_struct * const orig_me;
+ const VALUE owner;
} rb_method_refined_t;
typedef struct rb_method_definition_struct {
@@ -159,20 +175,23 @@ typedef struct rb_method_definition_struct {
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi);
void rb_add_method_iseq(VALUE klass, ID mid, VALUE iseqval, rb_cref_t *cref, rb_method_visibility_t visi);
-rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi);
-rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
-rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
void rb_add_refined_method_entry(VALUE refined_class, ID mid);
-const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements,
- const rb_method_entry_t *me,
- VALUE *defined_class_ptr);
-const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id,
- VALUE *defined_class_ptr);
-const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id,
- VALUE *defined_class_ptr);
-
-rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
+
+rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi);
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_visibility_t noex);
+rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def);
+
+const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
+
+const rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
+const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id);
+const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id);
+const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
+
+const rb_callable_method_entry_t *rb_callable_method_entry(VALUE klass, ID id);
+const rb_callable_method_entry_t *rb_callable_method_entry_with_refinements(VALUE klass, ID id);
+const rb_callable_method_entry_t *rb_callable_method_entry_without_refinements(VALUE klass, ID id);
+const rb_callable_method_entry_t *rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
int rb_method_entry_arity(const rb_method_entry_t *me);
int rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2);
@@ -185,8 +204,8 @@ VALUE rb_obj_method_location(VALUE obj, ID id);
void rb_free_method_entry(const rb_method_entry_t *me);
void rb_sweep_method_entry(void *vm);
-rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def);
-rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me);
+const rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me);
+const rb_callable_method_entry_t *rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, VALUE defined_class);
void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src);
void rb_scope_visibility_set(rb_method_visibility_t);
diff --git a/proc.c b/proc.c
index adb9f674a2..15a5cef433 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);
}
/*
diff --git a/vm.c b/vm.c
index ad0d8505f7..ba4cf3e9f8 100644
--- a/vm.c
+++ b/vm.c
@@ -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);
diff --git a/vm_args.c b/vm_args.c
index e466b10bce..bea9d59b7a 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -689,7 +689,7 @@ raise_argument_error(rb_thread_t *th, const rb_iseq_t *iseq, const VALUE exc)
VALUE at;
if (iseq) {
- vm_push_frame(th, iseq, VM_FRAME_MAGIC_DUMMY, Qnil /* self */, Qnil /* klass */,
+ vm_push_frame(th, iseq, VM_FRAME_MAGIC_DUMMY, Qnil /* self */,
VM_ENVVAL_BLOCK_PTR(0) /* specval*/, Qfalse /* me or cref */,
iseq->iseq_encoded, th->cfp->sp, 1 /* local_size (cref/me) */, 0 /* stack_max */);
at = rb_vm_backtrace_object();
diff --git a/vm_backtrace.c b/vm_backtrace.c
index 801bf1100c..99d3e7f3d3 100644
--- a/vm_backtrace.c
+++ b/vm_backtrace.c
@@ -465,7 +465,7 @@ backtrace_each(rb_thread_t *th,
}
}
else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
- 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);
ID mid = me->def->original_id;
iter_cfunc(arg, cfp, mid);
diff --git a/vm_core.h b/vm_core.h
index 72a1b2d908..58179ffbef 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -183,8 +183,7 @@ typedef struct rb_call_info_struct {
VALUE klass;
/* inline cache: values */
- const rb_method_entry_t *me;
- VALUE defined_class;
+ const rb_callable_method_entry_t *me;
/* temporary values for method calling */
struct rb_block_struct *blockptr;
@@ -524,7 +523,7 @@ typedef struct rb_vm_struct {
#endif
#ifndef VM_DEBUG_VERIFY_METHOD_CACHE
-#define VM_DEBUG_VERIFY_METHOD_CACHE 0
+#define VM_DEBUG_VERIFY_METHOD_CACHE (VM_DEBUG_MODE != 0)
#endif
typedef struct rb_control_frame_struct {
@@ -533,10 +532,9 @@ typedef struct rb_control_frame_struct {
rb_iseq_t *iseq; /* cfp[2] */
VALUE flag; /* cfp[3] */
VALUE self; /* cfp[4] / block[0] */
- VALUE klass; /* cfp[5] / block[1] */
- VALUE *ep; /* cfp[6] / block[2] */
- rb_iseq_t *block_iseq; /* cfp[7] / block[3] */
- VALUE proc; /* cfp[8] / block[4] */
+ VALUE *ep; /* cfp[6] / block[1] */
+ rb_iseq_t *block_iseq; /* cfp[7] / block[2] */
+ VALUE proc; /* cfp[8] / block[3] */
#if VM_DEBUG_BP_CHECK
VALUE *bp_check; /* cfp[9] */
@@ -545,7 +543,6 @@ typedef struct rb_control_frame_struct {
typedef struct rb_block_struct {
VALUE self; /* share with method frame if it's only block */
- VALUE klass; /* share with method frame if it's only block */
VALUE *ep; /* share with method frame if it's only block */
rb_iseq_t *iseq;
VALUE proc;
@@ -631,7 +628,7 @@ typedef struct rb_thread_struct {
const rb_block_t *passed_block;
/* for bmethod */
- const rb_method_entry_t *passed_bmethod_me;
+ const rb_callable_method_entry_t *passed_bmethod_me;
/* for cfunc */
rb_call_info_t *passed_ci;
@@ -976,8 +973,7 @@ VALUE *rb_binding_add_dynavars(rb_binding_t *bind, int dyncount, const ID *dynva
void rb_vm_inc_const_missing_count(void);
void rb_vm_gvl_destroy(rb_vm_t *vm);
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);
+ const VALUE *argv, const rb_callable_method_entry_t *me);
void rb_thread_start_timer_thread(void);
void rb_thread_stop_timer_thread(int);
@@ -1024,7 +1020,7 @@ int rb_autoloading_value(VALUE mod, ID id, VALUE* value);
void rb_vm_rewrite_cref(rb_cref_t *node, VALUE old_klass, VALUE new_klass, rb_cref_t **new_cref_ptr);
-const rb_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp);
+const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp);
#define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack]
diff --git a/vm_dump.c b/vm_dump.c
index be8feb1794..edd8176f96 100644
--- a/vm_dump.c
+++ b/vm_dump.c
@@ -36,7 +36,7 @@ control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp)
const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-";
VALUE tmp;
- const rb_method_entry_t *me;
+ const rb_callable_method_entry_t *me;
if (cfp->block_iseq != 0 && !RUBY_VM_IFUNC_P(cfp->block_iseq)) {
biseq_name = ""; /* RSTRING(cfp->block_iseq->location.label)->ptr; */
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 */
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)) {
diff --git a/vm_method.c b/vm_method.c
index d9c0b4fc97..0ae14c833a 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -93,6 +93,15 @@ rb_clear_method_cache_by_class(VALUE klass)
else {
rb_class_clear_method_cache(klass, Qnil);
}
+
+ if (RB_TYPE_P(klass, T_MODULE)) {
+ rb_subclass_entry_t *entry = RCLASS_EXT(klass)->subclasses;
+
+ for (; entry != NULL; entry = entry->next) {
+ struct st_table *table = RCLASS_CALLABLE_M_TBL(entry->klass);
+ if (table) st_clear(table);
+ }
+ }
}
}
@@ -201,7 +210,7 @@ setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
}
static void
-method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
+method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
{
*(rb_method_definition_t **)&me->def = def;
@@ -263,8 +272,12 @@ method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *
def->body.optimize_type = (enum method_optimized_type)opts;
return;
case VM_METHOD_TYPE_REFINED:
- RB_OBJ_WRITE(me, &def->body.refined.orig_me, (rb_method_entry_t *)opts);
- return;
+ {
+ const rb_method_refined_t *refined = (rb_method_refined_t *)opts;
+ RB_OBJ_WRITE(me, &def->body.refined.orig_me, refined->orig_me);
+ RB_OBJ_WRITE(me, &def->body.refined.owner, refined->owner);
+ return;
+ }
case VM_METHOD_TYPE_ALIAS:
RB_OBJ_WRITE(me, &def->body.alias.original_me, (rb_method_entry_t *)opts);
return;
@@ -273,7 +286,6 @@ method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *
case VM_METHOD_TYPE_MISSING:
return;
}
- rb_bug("rb_add_method: unsupported method type (%d)\n", def->type);
}
}
@@ -296,6 +308,7 @@ method_definition_reset(const rb_method_entry_t *me)
break;
case VM_METHOD_TYPE_REFINED:
RB_OBJ_WRITTEN(me, Qundef, def->body.refined.orig_me);
+ RB_OBJ_WRITTEN(me, Qundef, def->body.refined.owner);
break;
case VM_METHOD_TYPE_ALIAS:
RB_OBJ_WRITTEN(me, Qundef, def->body.alias.original_me);
@@ -328,46 +341,83 @@ method_definition_addref(rb_method_definition_t *def)
return def;
}
+static rb_method_entry_t *
+rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, const rb_method_definition_t *def)
+{
+ rb_method_entry_t *me = (rb_method_entry_t *)rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, owner, defined_class);
+ return me;
+}
+
+static VALUE
+filter_defined_class(VALUE klass)
+{
+ switch (BUILTIN_TYPE(klass)) {
+ case T_CLASS:
+ return klass;
+ case T_MODULE:
+ return 0;
+ case T_ICLASS:
+ break;
+ }
+ rb_bug("filter_defined_class: %s", rb_obj_info(klass));
+}
+
rb_method_entry_t *
rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def)
{
- rb_method_entry_t *me = (rb_method_entry_t *)rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, (VALUE)klass, 0);
+ rb_method_entry_t *me = rb_method_entry_alloc(called_id, klass, filter_defined_class(klass), def);
METHOD_ENTRY_FLAGS_SET(me, visi, ruby_running ? FALSE : TRUE, rb_safe_level());
if (def != NULL) method_definition_reset(me);
return me;
}
-rb_method_entry_t *
+const rb_method_entry_t *
rb_method_entry_clone(const rb_method_entry_t *src_me)
{
- rb_method_entry_t *me = rb_method_entry_create(src_me->called_id, src_me->klass,
- METHOD_ENTRY_VISI(src_me),
- method_definition_addref(src_me->def));
+ rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, src_me->defined_class,
+ method_definition_addref(src_me->def));
+ METHOD_ENTRY_FLAGS_COPY(me, src_me);
return me;
}
+const rb_callable_method_entry_t *
+rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, VALUE defined_class)
+{
+ rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, defined_class,
+ method_definition_addref(src_me->def));
+ METHOD_ENTRY_FLAGS_COPY(me, src_me);
+ return (rb_callable_method_entry_t *)me;
+}
+
void
rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src)
{
*(rb_method_definition_t **)&dst->def = method_definition_addref(src->def);
method_definition_reset(dst);
dst->called_id = src->called_id;
- RB_OBJ_WRITE((VALUE)dst, &dst->klass, src->klass);
+ RB_OBJ_WRITE((VALUE)dst, &dst->owner, src->owner);
+ RB_OBJ_WRITE((VALUE)dst, &dst->defined_class, src->defined_class);
+ METHOD_ENTRY_FLAGS_COPY(dst, src);
}
static void
-make_method_entry_refined(rb_method_entry_t *me)
+make_method_entry_refined(VALUE owner, rb_method_entry_t *me)
{
if (me->def->type == VM_METHOD_TYPE_REFINED) {
return;
}
else {
- rb_method_entry_t *cloned_me;
+ struct {
+ const struct rb_method_entry_struct *orig_me;
+ VALUE owner;
+ } refined;
+
+ rb_vm_check_redefinition_opt_method(me, me->owner);
- rb_vm_check_redefinition_opt_method(me, me->klass);
- cloned_me = rb_method_entry_clone(me);
+ refined.orig_me = rb_method_entry_clone(me);
+ refined.owner = owner;
- method_definition_set(me, method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id), (void *)cloned_me);
+ method_definition_set(me, method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id), (void *)&refined);
METHOD_ENTRY_VISI_SET(me, METHOD_VISI_PUBLIC);
}
}
@@ -378,7 +428,7 @@ rb_add_refined_method_entry(VALUE refined_class, ID mid)
rb_method_entry_t *me = lookup_method_table(refined_class, mid);
if (me) {
- make_method_entry_refined(me);
+ make_method_entry_refined(refined_class, me);
rb_clear_method_cache_by_class(refined_class);
}
else {
@@ -490,7 +540,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
}
if (make_refined) {
- make_method_entry_refined(me);
+ make_method_entry_refined(klass, me);
}
st_insert(mtbl, mid, (st_data_t) me);
@@ -607,7 +657,7 @@ search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
return me;
}
-rb_method_entry_t *
+const rb_method_entry_t *
rb_method_entry_at(VALUE klass, ID id)
{
return lookup_method_table(klass, id);
@@ -619,9 +669,9 @@ rb_method_entry_at(VALUE klass, ID id)
* if you need method entry with method cache (normal case), use
* rb_method_entry() simply.
*/
-rb_method_entry_t *
-rb_method_entry_get_without_cache(VALUE klass, ID id,
- VALUE *defined_class_ptr)
+static rb_method_entry_t *
+method_entry_get_without_cache(VALUE klass, ID id,
+ VALUE *defined_class_ptr)
{
VALUE defined_class;
rb_method_entry_t *me = search_method(klass, id, &defined_class);
@@ -659,7 +709,7 @@ verify_method_cache(VALUE klass, ID id, VALUE defined_class, rb_method_entry_t *
{
VALUE actual_defined_class;
rb_method_entry_t *actual_me =
- rb_method_entry_get_without_cache(klass, id, &actual_defined_class);
+ method_entry_get_without_cache(klass, id, &actual_defined_class);
if (me != actual_me || defined_class != actual_defined_class) {
rb_bug("method cache verification failed");
@@ -667,8 +717,8 @@ verify_method_cache(VALUE klass, ID id, VALUE defined_class, rb_method_entry_t *
}
#endif
-rb_method_entry_t *
-rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
+static rb_method_entry_t *
+method_entry_get(VALUE klass, ID id, VALUE *defined_class_ptr)
{
#if OPT_GLOBAL_METHOD_CACHE
struct cache_entry *ent;
@@ -676,104 +726,179 @@ rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
if (ent->method_state == GET_GLOBAL_METHOD_STATE() &&
ent->class_serial == RCLASS_SERIAL(klass) &&
ent->mid == id) {
- if (defined_class_ptr)
- *defined_class_ptr = ent->defined_class;
#if VM_DEBUG_VERIFY_METHOD_CACHE
verify_method_cache(klass, id, ent->defined_class, ent->me);
#endif
+ if (defined_class_ptr) *defined_class_ptr = ent->defined_class;
return ent->me;
}
#endif
- return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
+ return method_entry_get_without_cache(klass, id, defined_class_ptr);
+}
+
+const rb_method_entry_t *
+rb_method_entry(VALUE klass, ID id)
+{
+ return method_entry_get(klass, id, NULL);
}
+static const rb_callable_method_entry_t *
+prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_t *me)
+{
+ struct st_table *mtbl;
+ const rb_callable_method_entry_t *cme;
+
+ if (me && me->defined_class == 0) {
+ VM_ASSERT(RB_TYPE_P(defined_class, T_ICLASS));
+ VM_ASSERT(me->defined_class == 0);
+
+ if ((mtbl = RCLASS_EXT(defined_class)->callable_m_tbl) == NULL) {
+ mtbl = RCLASS_EXT(defined_class)->callable_m_tbl = st_init_numtable();
+ }
+
+ if (st_lookup(mtbl, id, (st_data_t *)&me)) {
+ cme = (rb_callable_method_entry_t *)me;
+ VM_ASSERT(callable_method_entry_p(cme));
+ }
+ else {
+ cme = rb_method_entry_complement_defined_class(me, defined_class);
+ st_insert(mtbl, id, (st_data_t)cme);
+ VM_ASSERT(callable_method_entry_p(cme));
+ }
+ }
+ else {
+ cme = (const rb_callable_method_entry_t *)me;
+ }
+
+ VM_ASSERT(callable_method_entry_p(cme));
+ return cme;
+}
+
+const rb_callable_method_entry_t *
+rb_callable_method_entry(VALUE klass, ID id)
+{
+ VALUE defined_class;
+ rb_method_entry_t *me = method_entry_get(klass, id, &defined_class);
+ return prepare_callable_method_entry(defined_class, id, me);
+}
+
+static const rb_method_entry_t *resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr);
+
static const rb_method_entry_t *
-get_original_method_entry(VALUE refinements,
- const rb_method_entry_t *me,
- VALUE *defined_class_ptr)
+method_entry_resolve_refienment(VALUE klass, ID id, int with_refinement, VALUE *defined_class_ptr)
+{
+ const rb_method_entry_t *me = method_entry_get(klass, id, defined_class_ptr);
+
+ if (me) {
+ if (me->def->type == VM_METHOD_TYPE_REFINED) {
+ if (with_refinement) {
+ const rb_cref_t *cref = rb_vm_cref();
+ VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
+ me = resolve_refined_method(refinements, me, defined_class_ptr);
+ }
+ else {
+ me = resolve_refined_method(Qnil, me, defined_class_ptr);
+ }
+
+ if (UNDEFINED_METHOD_ENTRY_P(me)) me = NULL;
+ }
+ }
+
+ return me;
+}
+
+const rb_method_entry_t *
+rb_method_entry_with_refinements(VALUE klass, ID id)
+{
+ return method_entry_resolve_refienment(klass, id, TRUE, NULL);
+}
+
+const rb_callable_method_entry_t *
+rb_callable_method_entry_with_refinements(VALUE klass, ID id)
+{
+ VALUE defined_class;
+ const rb_method_entry_t *me = method_entry_resolve_refienment(klass, id, TRUE, &defined_class);
+ return prepare_callable_method_entry(defined_class, id, me);
+}
+
+const rb_method_entry_t *
+rb_method_entry_without_refinements(VALUE klass, ID id)
+{
+ return method_entry_resolve_refienment(klass, id, FALSE, NULL);
+}
+
+const rb_callable_method_entry_t *
+rb_callable_method_entry_without_refinements(VALUE klass, ID id)
+{
+ VALUE defined_class;
+ const rb_method_entry_t *me = method_entry_resolve_refienment(klass, id, FALSE, &defined_class);
+ return prepare_callable_method_entry(defined_class, id, me);
+}
+
+static const rb_method_entry_t *
+refiend_method_original_method_entry(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr)
{
VALUE super;
if (me->def->body.refined.orig_me) {
+ if (defined_class_ptr) *defined_class_ptr = me->def->body.refined.orig_me->defined_class;
return me->def->body.refined.orig_me;
}
- else if (!(super = RCLASS_SUPER(me->klass))) {
+ else if (!(super = RCLASS_SUPER(me->owner))) {
return 0;
}
else {
rb_method_entry_t *tmp_me;
- tmp_me = rb_method_entry(super, me->called_id,
- defined_class_ptr);
- return rb_resolve_refined_method(refinements, tmp_me,
- defined_class_ptr);
+ tmp_me = method_entry_get(super, me->called_id, defined_class_ptr);
+ return resolve_refined_method(refinements, tmp_me, defined_class_ptr);
}
}
-const rb_method_entry_t *
-rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me,
- VALUE *defined_class_ptr)
+static const rb_method_entry_t *
+resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr)
{
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
VALUE refinement;
rb_method_entry_t *tmp_me;
- refinement = find_refinement(refinements, me->klass);
+ refinement = find_refinement(refinements, me->owner);
if (NIL_P(refinement)) {
- return get_original_method_entry(refinements, me,
- defined_class_ptr);
- }
- tmp_me = rb_method_entry(refinement, me->called_id,
- defined_class_ptr);
- if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
- return tmp_me;
+ return refiend_method_original_method_entry(refinements, me, defined_class_ptr);
}
else {
- return get_original_method_entry(refinements, me,
- defined_class_ptr);
+ tmp_me = method_entry_get(refinement, me->called_id, defined_class_ptr);
+
+ if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
+ return tmp_me;
+ }
+ else {
+ return refiend_method_original_method_entry(refinements, me, defined_class_ptr);
+ }
}
}
else {
- return (rb_method_entry_t *)me;
+ return me;
}
}
const rb_method_entry_t *
-rb_method_entry_with_refinements(VALUE klass, ID id,
- VALUE *defined_class_ptr)
+rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me)
{
- VALUE defined_class;
- const rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
-
- if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
- const rb_cref_t *cref = rb_vm_cref();
- VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
-
- me = rb_resolve_refined_method(refinements, me, &defined_class);
- }
-
- if (defined_class_ptr) *defined_class_ptr = defined_class;
-
- return me;
+ return resolve_refined_method(refinements, me, NULL);
}
-const rb_method_entry_t *
-rb_method_entry_without_refinements(VALUE klass, ID id,
- VALUE *defined_class_ptr)
+const rb_callable_method_entry_t *
+rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me)
{
- VALUE defined_class;
- const rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
+ VALUE defined_class = me->defined_class;
+ const rb_method_entry_t *resolved_me = resolve_refined_method(refinements, (const rb_method_entry_t *)me, &defined_class);
- if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
- me = rb_resolve_refined_method(Qnil, me, &defined_class);
- }
- if (defined_class_ptr)
- *defined_class_ptr = defined_class;
- if (UNDEFINED_METHOD_ENTRY_P(me)) {
- return 0;
+ if (resolved_me && resolved_me->defined_class == 0) {
+ return rb_method_entry_complement_defined_class(resolved_me, defined_class);
}
else {
- return me;
+ return (const rb_callable_method_entry_t *)resolved_me;
}
}
@@ -889,7 +1014,7 @@ rb_export_method(VALUE klass, ID name, rb_method_visibility_t visi)
int
rb_method_boundp(VALUE klass, ID id, int ex)
{
- const rb_method_entry_t *me = rb_method_entry_without_refinements(klass, id, 0);
+ const rb_method_entry_t *me = rb_method_entry_without_refinements(klass, id);
if (me != 0) {
if ((ex & ~BOUND_RESPONDS) &&
@@ -1123,7 +1248,7 @@ check_definition(VALUE mod, VALUE mid, rb_method_visibility_t visi)
const rb_method_entry_t *me;
ID id = rb_check_id(&mid);
if (!id) return Qfalse;
- me = rb_method_entry_without_refinements(mod, id, 0);
+ me = rb_method_entry_without_refinements(mod, id);
if (me) {
if (METHOD_ENTRY_VISI(me) == visi) return Qtrue;
}
@@ -1354,7 +1479,7 @@ rb_alias(VALUE klass, ID alias_name, ID original_name)
again:
orig_me = search_method(klass, original_name, &defined_class);
if (orig_me && orig_me->def->type == VM_METHOD_TYPE_REFINED) {
- orig_me = rb_resolve_refined_method(Qnil, orig_me, &defined_class);
+ orig_me = rb_resolve_refined_method(Qnil, orig_me);
}
if (UNDEFINED_METHOD_ENTRY_P(orig_me) ||
@@ -1375,26 +1500,19 @@ rb_alias(VALUE klass, ID alias_name, ID original_name)
if (visi == METHOD_VISI_UNDEF) visi = METHOD_ENTRY_VISI(orig_me);
- if (defined_class != target_klass) { /* inter class/module alias */
- VALUE real_owner;
+ if (orig_me->defined_class == 0) {
rb_method_entry_t *alias_me;
- if (RB_TYPE_P(defined_class, T_ICLASS)) {
- defined_class = real_owner = RBASIC_CLASS(defined_class);
- }
- else {
- real_owner = defined_class;
- }
-
- /* make mthod entry */
- alias_me = rb_add_method(target_klass, alias_name, VM_METHOD_TYPE_ALIAS, rb_method_entry_clone(orig_me), visi);
- RB_OBJ_WRITE(alias_me, &alias_me->klass, defined_class);
+ alias_me = rb_add_method(target_klass, alias_name, VM_METHOD_TYPE_ALIAS, (void *)rb_method_entry_clone(orig_me), visi);
alias_me->def->original_id = orig_me->called_id;
- *(ID *)&alias_me->def->body.alias.original_me->called_id = alias_name;
METHOD_ENTRY_SAFE_SET(alias_me, METHOD_ENTRY_SAFE(orig_me));
}
else {
- method_entry_set(target_klass, alias_name, orig_me, visi, defined_class);
+ rb_method_entry_t *alias_me;
+
+ alias_me = method_entry_set(target_klass, alias_name, orig_me, visi, orig_me->owner);
+ RB_OBJ_WRITE(alias_me, &alias_me->owner, target_klass);
+ RB_OBJ_WRITE(alias_me, &alias_me->defined_class, defined_class);
}
}
@@ -1690,7 +1808,7 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
int
rb_method_basic_definition_p(VALUE klass, ID id)
{
- const rb_method_entry_t *me = rb_method_entry(klass, id, 0);
+ const rb_method_entry_t *me = rb_method_entry(klass, id);
return (me && METHOD_ENTRY_BASIC(me)) ? TRUE : FALSE;
}
@@ -1876,7 +1994,7 @@ Init_eval_method(void)
{
#define REPLICATE_METHOD(klass, id) do { \
- const rb_method_entry_t *me = rb_method_entry((klass), (id), 0); \
+ const rb_method_entry_t *me = rb_method_entry((klass), (id)); \
rb_method_entry_set((klass), (id), me, METHOD_ENTRY_VISI(me)); \
} while (0)