* 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
This commit is contained in:
ko1 2015-07-03 11:24:50 +00:00
Родитель 6ddfcd93fc
Коммит 5e8a147480
17 изменённых файлов: 753 добавлений и 458 удалений

115
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

Просмотреть файл

@ -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;

1
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;

14
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;

8
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:

Просмотреть файл

@ -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(),

Просмотреть файл

@ -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)

Просмотреть файл

@ -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);

201
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);
if (me->defined_class) {
VALUE klass = RCLASS_SUPER(me->defined_class);
id = me->def->original_id;
me = rb_method_entry_without_refinements(klass, id, &defined_class);
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_cat2(str, "(");
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(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);
}
/*

99
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);

Просмотреть файл

@ -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();

Просмотреть файл

@ -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);

Просмотреть файл

@ -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]

Просмотреть файл

@ -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; */

109
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);
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 */

Просмотреть файл

@ -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,16 +579,8 @@ 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;
}
}
static inline VALUE
vm_get_ev_const(rb_thread_t *th, VALUE orig_klass, ID id, int is_defined)
@ -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)) {

Просмотреть файл

@ -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);
{
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),
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->klass);
cloned_me = rb_method_entry_clone(me);
rb_vm_check_redefinition_opt_method(me, me->owner);
method_definition_set(me, method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id), (void *)cloned_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 *)&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,8 +669,8 @@ 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,
static rb_method_entry_t *
method_entry_get_without_cache(VALUE klass, ID id,
VALUE *defined_class_ptr)
{
VALUE 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 *
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 *
get_original_method_entry(VALUE refinements,
const rb_method_entry_t *me,
VALUE *defined_class_ptr)
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);
return refiend_method_original_method_entry(refinements, me, defined_class_ptr);
}
tmp_me = rb_method_entry(refinement, me->called_id,
defined_class_ptr);
else {
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 get_original_method_entry(refinements, me,
defined_class_ptr);
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);
return resolve_refined_method(refinements, me, NULL);
}
if (defined_class_ptr) *defined_class_ptr = defined_class;
return me;
}
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)