зеркало из https://github.com/github/ruby.git
* 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:
Родитель
6ddfcd93fc
Коммит
5e8a147480
115
ChangeLog
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
|
||||
|
|
8
class.c
8
class.c
|
@ -1119,10 +1119,10 @@ method_entry_i(st_data_t key, st_data_t value, st_data_t data)
|
|||
rb_method_visibility_t type;
|
||||
|
||||
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
VALUE klass = me->klass;
|
||||
me = rb_resolve_refined_method(Qnil, me, NULL);
|
||||
VALUE owner = me->owner;
|
||||
me = rb_resolve_refined_method(Qnil, me);
|
||||
if (!me) return ST_CONTINUE;
|
||||
if (!arg->recur && me->klass != klass) return ST_CONTINUE;
|
||||
if (!arg->recur && me->owner != owner) return ST_CONTINUE;
|
||||
}
|
||||
if (!st_lookup(arg->list, key, 0)) {
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||
|
@ -1718,7 +1718,7 @@ rb_define_attr(VALUE klass, const char *name, int read, int write)
|
|||
int
|
||||
rb_obj_basic_to_s_p(VALUE obj)
|
||||
{
|
||||
const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"), 0);
|
||||
const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"));
|
||||
if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC &&
|
||||
me->def->body.cfunc.func == rb_any_to_s)
|
||||
return 1;
|
||||
|
|
1
cont.c
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
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
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)
|
||||
|
|
49
method.h
49
method.h
|
@ -47,12 +47,20 @@ typedef struct rb_cref_struct {
|
|||
|
||||
typedef struct rb_method_entry_struct {
|
||||
VALUE flags;
|
||||
VALUE dummy;
|
||||
const VALUE defined_class;
|
||||
struct rb_method_definition_struct * const def;
|
||||
ID called_id;
|
||||
const VALUE klass; /* should be marked */
|
||||
const VALUE owner;
|
||||
} rb_method_entry_t;
|
||||
|
||||
typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_entry_t */
|
||||
VALUE flags;
|
||||
const VALUE defined_class;
|
||||
struct rb_method_definition_struct * const def;
|
||||
ID called_id;
|
||||
const VALUE owner;
|
||||
} rb_callable_method_entry_t;
|
||||
|
||||
#define METHOD_ENTRY_VISI(me) (rb_method_visibility_t)(((me)->flags & (IMEMO_FL_USER0 | IMEMO_FL_USER1)) >> (IMEMO_FL_USHIFT+0))
|
||||
#define METHOD_ENTRY_BASIC(me) (int) (((me)->flags & (IMEMO_FL_USER2 )) >> (IMEMO_FL_USHIFT+2))
|
||||
#define METHOD_ENTRY_SAFE(me) (int) (((me)->flags & (IMEMO_FL_USER3 | IMEMO_FL_USER4)) >> (IMEMO_FL_USHIFT+3))
|
||||
|
@ -85,6 +93,13 @@ METHOD_ENTRY_FLAGS_SET(rb_method_entry_t *me, rb_method_visibility_t visi, unsig
|
|||
(me->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4)) |
|
||||
((visi << IMEMO_FL_USHIFT+0) | (basic << (IMEMO_FL_USHIFT+2)) | (safe << IMEMO_FL_USHIFT+3));
|
||||
}
|
||||
static inline void
|
||||
METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src)
|
||||
{
|
||||
dst->flags =
|
||||
(dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4)) |
|
||||
(src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3|IMEMO_FL_USER4));
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
VM_METHOD_TYPE_ISEQ,
|
||||
|
@ -127,6 +142,7 @@ typedef struct rb_method_alias_struct {
|
|||
|
||||
typedef struct rb_method_refined_struct {
|
||||
const struct rb_method_entry_struct * const orig_me;
|
||||
const VALUE owner;
|
||||
} rb_method_refined_t;
|
||||
|
||||
typedef struct rb_method_definition_struct {
|
||||
|
@ -159,20 +175,23 @@ typedef struct rb_method_definition_struct {
|
|||
|
||||
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi);
|
||||
void rb_add_method_iseq(VALUE klass, ID mid, VALUE iseqval, rb_cref_t *cref, rb_method_visibility_t visi);
|
||||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi);
|
||||
rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
|
||||
rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
|
||||
void rb_add_refined_method_entry(VALUE refined_class, ID mid);
|
||||
const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements,
|
||||
const rb_method_entry_t *me,
|
||||
VALUE *defined_class_ptr);
|
||||
const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id,
|
||||
VALUE *defined_class_ptr);
|
||||
const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id,
|
||||
VALUE *defined_class_ptr);
|
||||
|
||||
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
|
||||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi);
|
||||
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_visibility_t noex);
|
||||
rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def);
|
||||
|
||||
const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
|
||||
|
||||
const rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
|
||||
const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id);
|
||||
const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id);
|
||||
const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
|
||||
|
||||
const rb_callable_method_entry_t *rb_callable_method_entry(VALUE klass, ID id);
|
||||
const rb_callable_method_entry_t *rb_callable_method_entry_with_refinements(VALUE klass, ID id);
|
||||
const rb_callable_method_entry_t *rb_callable_method_entry_without_refinements(VALUE klass, ID id);
|
||||
const rb_callable_method_entry_t *rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
|
||||
|
||||
int rb_method_entry_arity(const rb_method_entry_t *me);
|
||||
int rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2);
|
||||
|
@ -185,8 +204,8 @@ VALUE rb_obj_method_location(VALUE obj, ID id);
|
|||
void rb_free_method_entry(const rb_method_entry_t *me);
|
||||
void rb_sweep_method_entry(void *vm);
|
||||
|
||||
rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def);
|
||||
rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me);
|
||||
const rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me);
|
||||
const rb_callable_method_entry_t *rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, VALUE defined_class);
|
||||
void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src);
|
||||
|
||||
void rb_scope_visibility_set(rb_method_visibility_t);
|
||||
|
|
203
proc.c
203
proc.c
|
@ -21,11 +21,10 @@
|
|||
const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase);
|
||||
|
||||
struct METHOD {
|
||||
VALUE recv;
|
||||
VALUE rclass;
|
||||
VALUE defined_class;
|
||||
ID id;
|
||||
rb_method_entry_t * const me;
|
||||
const VALUE recv;
|
||||
const VALUE klass;
|
||||
const rb_method_entry_t * const me;
|
||||
/* for bound methods, `me' should be rb_callable_method_entry_t * */
|
||||
};
|
||||
|
||||
VALUE rb_cUnboundMethod;
|
||||
|
@ -1105,9 +1104,8 @@ static void
|
|||
bm_mark(void *ptr)
|
||||
{
|
||||
struct METHOD *data = ptr;
|
||||
rb_gc_mark(data->defined_class);
|
||||
rb_gc_mark(data->rclass);
|
||||
rb_gc_mark(data->recv);
|
||||
rb_gc_mark(data->klass);
|
||||
rb_gc_mark((VALUE)data->me);
|
||||
}
|
||||
|
||||
|
@ -1157,17 +1155,15 @@ respond_to_missing_p(VALUE klass, VALUE obj, VALUE sym, int scope)
|
|||
|
||||
|
||||
static VALUE
|
||||
mnew_missing(VALUE rclass, VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass)
|
||||
mnew_missing(VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass)
|
||||
{
|
||||
struct METHOD *data;
|
||||
VALUE method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
|
||||
rb_method_entry_t *me;
|
||||
rb_method_definition_t *def;
|
||||
|
||||
data->recv = obj;
|
||||
data->rclass = rclass;
|
||||
data->defined_class = klass;
|
||||
data->id = rid;
|
||||
RB_OBJ_WRITE(method, &data->recv, obj);
|
||||
RB_OBJ_WRITE(method, &data->klass, klass);
|
||||
|
||||
def = ZALLOC(rb_method_definition_t);
|
||||
def->type = VM_METHOD_TYPE_MISSING;
|
||||
|
@ -1183,11 +1179,10 @@ mnew_missing(VALUE rclass, VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass,
|
||||
mnew_internal(const rb_method_entry_t *me, VALUE klass,
|
||||
VALUE obj, ID id, VALUE mclass, int scope, int error)
|
||||
{
|
||||
struct METHOD *data;
|
||||
VALUE rclass = klass;
|
||||
VALUE method;
|
||||
ID rid = id;
|
||||
rb_method_visibility_t visi = METHOD_VISI_UNDEF;
|
||||
|
@ -1195,7 +1190,7 @@ mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass,
|
|||
again:
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||
if (respond_to_missing_p(klass, obj, ID2SYM(id), scope)) {
|
||||
return mnew_missing(rclass, klass, obj, id, rid, mclass);
|
||||
return mnew_missing(klass, obj, id, rid, mclass);
|
||||
}
|
||||
if (!error) return Qnil;
|
||||
rb_print_undef(klass, id, 0);
|
||||
|
@ -1208,44 +1203,52 @@ mnew_internal(const rb_method_entry_t *me, VALUE defined_class, VALUE klass,
|
|||
}
|
||||
}
|
||||
if (me->def->type == VM_METHOD_TYPE_ZSUPER) {
|
||||
klass = RCLASS_SUPER(defined_class);
|
||||
id = me->def->original_id;
|
||||
me = rb_method_entry_without_refinements(klass, id, &defined_class);
|
||||
if (me->defined_class) {
|
||||
VALUE klass = RCLASS_SUPER(me->defined_class);
|
||||
id = me->def->original_id;
|
||||
me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id);
|
||||
}
|
||||
else {
|
||||
VALUE klass = RCLASS_SUPER(me->owner);
|
||||
id = me->def->original_id;
|
||||
me = rb_method_entry_without_refinements(klass, id);
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
|
||||
klass = defined_class;
|
||||
|
||||
while (rclass != klass &&
|
||||
(FL_TEST(rclass, FL_SINGLETON) || RB_TYPE_P(rclass, T_ICLASS))) {
|
||||
rclass = RCLASS_SUPER(rclass);
|
||||
while (klass != me->owner && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) {
|
||||
klass = RCLASS_SUPER(klass);
|
||||
}
|
||||
|
||||
method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
|
||||
|
||||
data->recv = obj;
|
||||
data->rclass = rclass;
|
||||
data->defined_class = defined_class;
|
||||
data->id = rid;
|
||||
RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(me));
|
||||
RB_OBJ_WRITE(method, &data->recv, obj);
|
||||
RB_OBJ_WRITE(method, &data->klass, klass);
|
||||
RB_OBJ_WRITE(method, &data->me, me);
|
||||
|
||||
OBJ_INFECT(method, klass);
|
||||
return method;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
mnew_from_me(const rb_method_entry_t *me, VALUE defined_class, VALUE klass,
|
||||
mnew_from_me(const rb_method_entry_t *me, VALUE klass,
|
||||
VALUE obj, ID id, VALUE mclass, int scope)
|
||||
{
|
||||
return mnew_internal(me, defined_class, klass, obj, id, mclass, scope, TRUE);
|
||||
return mnew_internal(me, klass, obj, id, mclass, scope, TRUE);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||||
{
|
||||
VALUE defined_class;
|
||||
const rb_method_entry_t *me =
|
||||
rb_method_entry_without_refinements(klass, id, &defined_class);
|
||||
return mnew_from_me(me, defined_class, klass, obj, id, mclass, scope);
|
||||
const rb_method_entry_t *me;
|
||||
|
||||
if (obj == Qundef) { /* UnboundMethod */
|
||||
me = rb_method_entry_without_refinements(klass, id);
|
||||
}
|
||||
else {
|
||||
me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id);
|
||||
}
|
||||
return mnew_from_me(me, klass, obj, id, mclass, scope);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1287,6 +1290,7 @@ static VALUE
|
|||
method_eq(VALUE method, VALUE other)
|
||||
{
|
||||
struct METHOD *m1, *m2;
|
||||
VALUE klass1, klass2;
|
||||
|
||||
if (!rb_obj_is_method(other))
|
||||
return Qfalse;
|
||||
|
@ -1297,8 +1301,12 @@ method_eq(VALUE method, VALUE other)
|
|||
m1 = (struct METHOD *)DATA_PTR(method);
|
||||
m2 = (struct METHOD *)DATA_PTR(other);
|
||||
|
||||
klass1 = m1->me->defined_class ? m1->me->defined_class : m1->me->owner;
|
||||
klass2 = m2->me->defined_class ? m2->me->defined_class : m2->me->owner;
|
||||
|
||||
if (!rb_method_entry_eq(m1->me, m2->me) ||
|
||||
m1->rclass != m2->rclass ||
|
||||
klass1 != klass2 ||
|
||||
m1->klass != m2->klass ||
|
||||
m1->recv != m2->recv) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
@ -1322,8 +1330,7 @@ method_hash(VALUE method)
|
|||
st_index_t hash;
|
||||
|
||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, m);
|
||||
hash = rb_hash_start((st_index_t)m->rclass);
|
||||
hash = rb_hash_uint(hash, (st_index_t)m->recv);
|
||||
hash = rb_hash_start((st_index_t)m->recv);
|
||||
hash = rb_hash_method_entry(hash, m->me);
|
||||
hash = rb_hash_end(hash);
|
||||
|
||||
|
@ -1348,11 +1355,9 @@ method_unbind(VALUE obj)
|
|||
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, orig);
|
||||
method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD,
|
||||
&method_data_type, data);
|
||||
data->recv = Qundef;
|
||||
data->id = orig->id;
|
||||
RB_OBJ_WRITE(method, &data->recv, Qundef);
|
||||
RB_OBJ_WRITE(method, &data->klass, orig->klass);
|
||||
RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
|
||||
data->rclass = orig->rclass;
|
||||
data->defined_class = orig->defined_class;
|
||||
OBJ_INFECT(method, obj);
|
||||
|
||||
return method;
|
||||
|
@ -1387,7 +1392,7 @@ method_name(VALUE obj)
|
|||
struct METHOD *data;
|
||||
|
||||
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
|
||||
return ID2SYM(data->id);
|
||||
return ID2SYM(data->me->called_id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1417,16 +1422,8 @@ static VALUE
|
|||
method_owner(VALUE obj)
|
||||
{
|
||||
struct METHOD *data;
|
||||
VALUE defined_class;
|
||||
|
||||
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
|
||||
defined_class = data->defined_class;
|
||||
|
||||
if (RB_TYPE_P(defined_class, T_ICLASS)) {
|
||||
defined_class = RBASIC_CLASS(defined_class);
|
||||
}
|
||||
|
||||
return defined_class;
|
||||
return data->me->owner;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1462,7 +1459,7 @@ obj_method(VALUE obj, VALUE vid, int scope)
|
|||
if (!id) {
|
||||
if (respond_to_missing_p(klass, obj, vid, scope)) {
|
||||
id = rb_intern_str(vid);
|
||||
return mnew_missing(klass, klass, obj, id, id, mclass);
|
||||
return mnew_missing(klass, obj, id, id, mclass);
|
||||
}
|
||||
rb_method_name_error(klass, vid);
|
||||
}
|
||||
|
@ -1551,7 +1548,7 @@ rb_obj_singleton_method(VALUE obj, VALUE vid)
|
|||
if (!NIL_P(klass = rb_singleton_class_get(obj)) &&
|
||||
respond_to_missing_p(klass, obj, vid, FALSE)) {
|
||||
id = rb_intern_str(vid);
|
||||
return mnew_missing(klass, klass, obj, id, id, rb_cMethod);
|
||||
return mnew_missing(klass, obj, id, id, rb_cMethod);
|
||||
}
|
||||
rb_name_error_str(vid, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'",
|
||||
QUOTE(vid), obj);
|
||||
|
@ -1562,7 +1559,7 @@ rb_obj_singleton_method(VALUE obj, VALUE vid)
|
|||
rb_name_error(id, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'",
|
||||
QUOTE_ID(id), obj);
|
||||
}
|
||||
return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE);
|
||||
return mnew_from_me(me, klass, obj, id, rb_cMethod, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1704,17 +1701,16 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
|
|||
|
||||
if (is_method) {
|
||||
struct METHOD *method = (struct METHOD *)DATA_PTR(body);
|
||||
VALUE rclass = method->rclass;
|
||||
if (rclass != mod && !RB_TYPE_P(rclass, T_MODULE) &&
|
||||
!RTEST(rb_class_inherited_p(mod, rclass))) {
|
||||
if (FL_TEST(rclass, FL_SINGLETON)) {
|
||||
if (method->me->owner != mod && !RB_TYPE_P(method->me->owner, T_MODULE) &&
|
||||
!RTEST(rb_class_inherited_p(mod, method->me->owner))) {
|
||||
if (FL_TEST(method->me->owner, FL_SINGLETON)) {
|
||||
rb_raise(rb_eTypeError,
|
||||
"can't bind singleton method to a different class");
|
||||
}
|
||||
else {
|
||||
rb_raise(rb_eTypeError,
|
||||
"bind argument must be a subclass of % "PRIsVALUE,
|
||||
rb_class_name(rclass));
|
||||
rb_class_name(method->me->owner));
|
||||
}
|
||||
}
|
||||
rb_method_entry_set(mod, id, method->me, scope_visi->method_visi);
|
||||
|
@ -1732,7 +1728,6 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
|
|||
RB_OBJ_WRITE(proc->block.iseq->self, &proc->block.iseq->klass, mod);
|
||||
proc->is_lambda = TRUE;
|
||||
proc->is_from_method = TRUE;
|
||||
proc->block.klass = mod;
|
||||
}
|
||||
rb_add_method(mod, id, VM_METHOD_TYPE_BMETHOD, (void *)body, scope_visi->method_visi);
|
||||
if (scope_visi->module_func) {
|
||||
|
@ -1826,10 +1821,8 @@ method_clone(VALUE self)
|
|||
TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig);
|
||||
clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data);
|
||||
CLONESETUP(clone, self);
|
||||
data->recv = orig->recv;
|
||||
data->rclass = orig->rclass;
|
||||
data->defined_class = orig->defined_class;
|
||||
data->id = orig->id;
|
||||
RB_OBJ_WRITE(clone, &data->recv, orig->recv);
|
||||
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
|
||||
RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
|
||||
return clone;
|
||||
}
|
||||
|
@ -1854,6 +1847,13 @@ rb_method_call(int argc, const VALUE *argv, VALUE method)
|
|||
return rb_method_call_with_block(argc, argv, method, proc);
|
||||
}
|
||||
|
||||
static const rb_callable_method_entry_t *
|
||||
method_callable_method_entry(struct METHOD *data)
|
||||
{
|
||||
if (data->me && data->me->defined_class == 0) rb_bug("method_callable_method_entry: not callable.");
|
||||
return (const rb_callable_method_entry_t *)data->me;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_procval)
|
||||
{
|
||||
|
@ -1877,7 +1877,6 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_
|
|||
if ((state = EXEC_TAG()) == 0) {
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
rb_block_t *block = 0;
|
||||
VALUE defined_class;
|
||||
|
||||
if (!NIL_P(pass_procval)) {
|
||||
rb_proc_t *pass_proc;
|
||||
|
@ -1887,9 +1886,7 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE pass_
|
|||
|
||||
th->passed_block = block;
|
||||
VAR_INITIALIZED(data);
|
||||
defined_class = data->defined_class;
|
||||
if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass;
|
||||
result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me, defined_class);
|
||||
result = rb_vm_call(th, data->recv, data->me->called_id, argc, argv, method_callable_method_entry(data));
|
||||
}
|
||||
POP_TAG();
|
||||
if (safe >= 0)
|
||||
|
@ -1994,12 +1991,12 @@ static VALUE
|
|||
umethod_bind(VALUE method, VALUE recv)
|
||||
{
|
||||
struct METHOD *data, *bound;
|
||||
VALUE methclass;
|
||||
VALUE rclass;
|
||||
VALUE methclass, klass;
|
||||
|
||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
|
||||
|
||||
methclass = data->rclass;
|
||||
methclass = data->me->owner;
|
||||
|
||||
if (!RB_TYPE_P(methclass, T_MODULE) &&
|
||||
methclass != CLASS_OF(recv) && !rb_obj_is_kind_of(recv, methclass)) {
|
||||
if (FL_TEST(methclass, FL_SINGLETON)) {
|
||||
|
@ -2012,24 +2009,23 @@ umethod_bind(VALUE method, VALUE recv)
|
|||
}
|
||||
}
|
||||
|
||||
klass = CLASS_OF(recv);
|
||||
|
||||
method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
|
||||
bound->recv = data->recv;
|
||||
bound->rclass = data->rclass;
|
||||
bound->defined_class = data->defined_class;
|
||||
bound->id = data->id;
|
||||
RB_OBJ_WRITE(method, &bound->recv, recv);
|
||||
RB_OBJ_WRITE(method, &bound->klass, data->klass);
|
||||
RB_OBJ_WRITE(method, &bound->me, rb_method_entry_clone(data->me));
|
||||
rclass = CLASS_OF(recv);
|
||||
if (BUILTIN_TYPE(bound->defined_class) == T_MODULE) {
|
||||
VALUE ic = rb_class_search_ancestor(rclass, bound->defined_class);
|
||||
|
||||
if (RB_TYPE_P(bound->me->owner, T_MODULE)) {
|
||||
VALUE ic = rb_class_search_ancestor(klass, bound->me->owner);
|
||||
if (ic) {
|
||||
rclass = ic;
|
||||
klass = ic;
|
||||
}
|
||||
else {
|
||||
rclass = rb_include_class_new(methclass, rclass);
|
||||
klass = rb_include_class_new(methclass, klass);
|
||||
}
|
||||
RB_OBJ_WRITE(method, &bound->me, rb_method_entry_complement_defined_class(bound->me, klass));
|
||||
}
|
||||
bound->recv = recv;
|
||||
bound->rclass = rclass;
|
||||
|
||||
return method;
|
||||
}
|
||||
|
@ -2150,14 +2146,12 @@ method_arity(VALUE method)
|
|||
static const rb_method_entry_t *
|
||||
original_method_entry(VALUE mod, ID id)
|
||||
{
|
||||
VALUE rclass;
|
||||
const rb_method_entry_t *me;
|
||||
|
||||
while ((me = rb_method_entry(mod, id, &rclass)) != 0) {
|
||||
while ((me = rb_method_entry(mod, id)) != 0) {
|
||||
const rb_method_definition_t *def = me->def;
|
||||
if (!def) break;
|
||||
if (def->type != VM_METHOD_TYPE_ZSUPER) break;
|
||||
mod = RCLASS_SUPER(rclass);
|
||||
mod = RCLASS_SUPER(me->owner);
|
||||
id = def->original_id;
|
||||
}
|
||||
return me;
|
||||
|
@ -2322,6 +2316,7 @@ method_inspect(VALUE method)
|
|||
const char *s;
|
||||
const char *sharp = "#";
|
||||
VALUE mklass;
|
||||
VALUE defined_class;
|
||||
|
||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
|
||||
str = rb_str_buf_new2("#<");
|
||||
|
@ -2329,7 +2324,19 @@ method_inspect(VALUE method)
|
|||
rb_str_buf_cat2(str, s);
|
||||
rb_str_buf_cat2(str, ": ");
|
||||
|
||||
mklass = data->me->klass;
|
||||
mklass = data->klass;
|
||||
|
||||
if (data->me && data->me->def->type == VM_METHOD_TYPE_ALIAS) {
|
||||
defined_class = data->me->def->body.alias.original_me->owner;
|
||||
}
|
||||
else {
|
||||
defined_class = data->me->defined_class ? data->me->defined_class : data->me->owner;
|
||||
}
|
||||
|
||||
if (RB_TYPE_P(defined_class, T_ICLASS)) {
|
||||
defined_class = RBASIC_CLASS(defined_class);
|
||||
}
|
||||
|
||||
if (FL_TEST(mklass, FL_SINGLETON)) {
|
||||
VALUE v = rb_ivar_get(mklass, attached);
|
||||
|
||||
|
@ -2349,16 +2356,16 @@ method_inspect(VALUE method)
|
|||
}
|
||||
}
|
||||
else {
|
||||
rb_str_buf_append(str, rb_class_name(data->rclass));
|
||||
if (data->rclass != mklass) {
|
||||
rb_str_buf_append(str, rb_class_name(mklass));
|
||||
if (defined_class != mklass) {
|
||||
rb_str_buf_cat2(str, "(");
|
||||
rb_str_buf_append(str, rb_class_name(mklass));
|
||||
rb_str_buf_append(str, rb_class_name(defined_class));
|
||||
rb_str_buf_cat2(str, ")");
|
||||
}
|
||||
}
|
||||
rb_str_buf_cat2(str, sharp);
|
||||
rb_str_append(str, rb_id2str(data->id));
|
||||
if (data->id != data->me->def->original_id) {
|
||||
rb_str_append(str, rb_id2str(data->me->called_id));
|
||||
if (data->me->called_id != data->me->def->original_id) {
|
||||
rb_str_catf(str, "(%"PRIsVALUE")",
|
||||
rb_id2str(data->me->def->original_id));
|
||||
}
|
||||
|
@ -2444,19 +2451,15 @@ static VALUE
|
|||
method_super_method(VALUE method)
|
||||
{
|
||||
const struct METHOD *data;
|
||||
VALUE defined_class, super_class;
|
||||
VALUE super_class;
|
||||
const rb_method_entry_t *me;
|
||||
|
||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
|
||||
defined_class = data->defined_class;
|
||||
if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass;
|
||||
super_class = RCLASS_SUPER(defined_class);
|
||||
super_class = RCLASS_SUPER(data->me->defined_class);
|
||||
if (!super_class) return Qnil;
|
||||
me = rb_method_entry_without_refinements(super_class, data->id, &defined_class);
|
||||
me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(super_class, data->me->called_id);
|
||||
if (!me) return Qnil;
|
||||
return mnew_internal(me, defined_class,
|
||||
super_class, data->recv, data->id,
|
||||
rb_obj_class(method), FALSE, FALSE);
|
||||
return mnew_internal(me, super_class, data->recv, data->me->called_id, rb_obj_class(method), FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
99
vm.c
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);
|
||||
|
|
20
vm_core.h
20
vm_core.h
|
@ -183,8 +183,7 @@ typedef struct rb_call_info_struct {
|
|||
VALUE klass;
|
||||
|
||||
/* inline cache: values */
|
||||
const rb_method_entry_t *me;
|
||||
VALUE defined_class;
|
||||
const rb_callable_method_entry_t *me;
|
||||
|
||||
/* temporary values for method calling */
|
||||
struct rb_block_struct *blockptr;
|
||||
|
@ -524,7 +523,7 @@ typedef struct rb_vm_struct {
|
|||
#endif
|
||||
|
||||
#ifndef VM_DEBUG_VERIFY_METHOD_CACHE
|
||||
#define VM_DEBUG_VERIFY_METHOD_CACHE 0
|
||||
#define VM_DEBUG_VERIFY_METHOD_CACHE (VM_DEBUG_MODE != 0)
|
||||
#endif
|
||||
|
||||
typedef struct rb_control_frame_struct {
|
||||
|
@ -533,10 +532,9 @@ typedef struct rb_control_frame_struct {
|
|||
rb_iseq_t *iseq; /* cfp[2] */
|
||||
VALUE flag; /* cfp[3] */
|
||||
VALUE self; /* cfp[4] / block[0] */
|
||||
VALUE klass; /* cfp[5] / block[1] */
|
||||
VALUE *ep; /* cfp[6] / block[2] */
|
||||
rb_iseq_t *block_iseq; /* cfp[7] / block[3] */
|
||||
VALUE proc; /* cfp[8] / block[4] */
|
||||
VALUE *ep; /* cfp[6] / block[1] */
|
||||
rb_iseq_t *block_iseq; /* cfp[7] / block[2] */
|
||||
VALUE proc; /* cfp[8] / block[3] */
|
||||
|
||||
#if VM_DEBUG_BP_CHECK
|
||||
VALUE *bp_check; /* cfp[9] */
|
||||
|
@ -545,7 +543,6 @@ typedef struct rb_control_frame_struct {
|
|||
|
||||
typedef struct rb_block_struct {
|
||||
VALUE self; /* share with method frame if it's only block */
|
||||
VALUE klass; /* share with method frame if it's only block */
|
||||
VALUE *ep; /* share with method frame if it's only block */
|
||||
rb_iseq_t *iseq;
|
||||
VALUE proc;
|
||||
|
@ -631,7 +628,7 @@ typedef struct rb_thread_struct {
|
|||
const rb_block_t *passed_block;
|
||||
|
||||
/* for bmethod */
|
||||
const rb_method_entry_t *passed_bmethod_me;
|
||||
const rb_callable_method_entry_t *passed_bmethod_me;
|
||||
|
||||
/* for cfunc */
|
||||
rb_call_info_t *passed_ci;
|
||||
|
@ -976,8 +973,7 @@ VALUE *rb_binding_add_dynavars(rb_binding_t *bind, int dyncount, const ID *dynva
|
|||
void rb_vm_inc_const_missing_count(void);
|
||||
void rb_vm_gvl_destroy(rb_vm_t *vm);
|
||||
VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc,
|
||||
const VALUE *argv, const rb_method_entry_t *me,
|
||||
VALUE defined_class);
|
||||
const VALUE *argv, const rb_callable_method_entry_t *me);
|
||||
|
||||
void rb_thread_start_timer_thread(void);
|
||||
void rb_thread_stop_timer_thread(int);
|
||||
|
@ -1024,7 +1020,7 @@ int rb_autoloading_value(VALUE mod, ID id, VALUE* value);
|
|||
|
||||
void rb_vm_rewrite_cref(rb_cref_t *node, VALUE old_klass, VALUE new_klass, rb_cref_t **new_cref_ptr);
|
||||
|
||||
const rb_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp);
|
||||
const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp);
|
||||
|
||||
#define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack]
|
||||
|
||||
|
|
|
@ -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; */
|
||||
|
|
111
vm_eval.c
111
vm_eval.c
|
@ -42,15 +42,13 @@ static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type sc
|
|||
static VALUE vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv);
|
||||
|
||||
static VALUE
|
||||
vm_call0(rb_thread_t* th, VALUE recv, ID id, int argc, const VALUE *argv,
|
||||
const rb_method_entry_t *me, VALUE defined_class)
|
||||
vm_call0(rb_thread_t* th, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me)
|
||||
{
|
||||
rb_call_info_t ci_entry, *ci = &ci_entry;
|
||||
|
||||
ci->flag = 0;
|
||||
ci->mid = id;
|
||||
ci->recv = recv;
|
||||
ci->defined_class = defined_class;
|
||||
ci->argc = argc;
|
||||
ci->me = me;
|
||||
ci->kw_arg = NULL;
|
||||
|
@ -64,11 +62,11 @@ vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
|
|||
{
|
||||
VALUE val;
|
||||
|
||||
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, ci->defined_class, ci->mid);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->defined_class, Qnil);
|
||||
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, ci->me->owner, ci->mid);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->me->owner, Qnil);
|
||||
{
|
||||
rb_control_frame_t *reg_cfp = th->cfp;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
const rb_callable_method_entry_t *me = ci->me;
|
||||
const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
|
||||
int len = cfunc->argc;
|
||||
VALUE recv = ci->recv;
|
||||
|
@ -95,8 +93,8 @@ vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
|
|||
vm_pop_frame(th);
|
||||
}
|
||||
}
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->defined_class, val);
|
||||
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, ci->defined_class, ci->mid);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->me->owner, val);
|
||||
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, ci->me->owner, ci->mid);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -105,21 +103,20 @@ static VALUE
|
|||
vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
|
||||
{
|
||||
VALUE val;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
const rb_callable_method_entry_t *me = ci->me;
|
||||
const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
|
||||
int len = cfunc->argc;
|
||||
VALUE recv = ci->recv;
|
||||
VALUE defined_class = ci->defined_class;
|
||||
int argc = ci->argc;
|
||||
ID mid = ci->mid;
|
||||
rb_block_t *blockptr = ci->blockptr;
|
||||
|
||||
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, defined_class, mid);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, mid, defined_class, Qnil);
|
||||
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, mid);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, mid, me->owner, Qnil);
|
||||
{
|
||||
rb_control_frame_t *reg_cfp = th->cfp;
|
||||
|
||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
|
||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv,
|
||||
VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)me,
|
||||
0, reg_cfp->sp, 1, 0);
|
||||
|
||||
|
@ -134,8 +131,8 @@ vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv
|
|||
VM_PROFILE_UP(3);
|
||||
vm_pop_frame(th);
|
||||
}
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, mid, defined_class, val);
|
||||
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, defined_class, mid);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, mid, me->owner, val);
|
||||
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, mid);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -198,14 +195,16 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
|
|||
case VM_METHOD_TYPE_REFINED:
|
||||
{
|
||||
const rb_method_type_t type = ci->me->def->type;
|
||||
VALUE super_class;
|
||||
|
||||
if (type == VM_METHOD_TYPE_REFINED && ci->me->def->body.refined.orig_me) {
|
||||
ci->me = ci->me->def->body.refined.orig_me;
|
||||
ci->me = refined_method_callable_without_refinement(ci->me);
|
||||
goto again;
|
||||
}
|
||||
|
||||
ci->defined_class = RCLASS_SUPER(ci->defined_class);
|
||||
super_class = RCLASS_SUPER(ci->me->defined_class);
|
||||
|
||||
if (!ci->defined_class || !(ci->me = rb_method_entry(ci->defined_class, ci->mid, &ci->defined_class))) {
|
||||
if (!super_class || !(ci->me = rb_callable_method_entry(super_class, ci->mid))) {
|
||||
enum method_missing_reason ex = (type == VM_METHOD_TYPE_ZSUPER) ? MISSING_SUPER : 0;
|
||||
ret = method_missing(ci->recv, ci->mid, ci->argc, argv, ex);
|
||||
goto success;
|
||||
|
@ -214,11 +213,8 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
|
|||
goto again;
|
||||
}
|
||||
case VM_METHOD_TYPE_ALIAS:
|
||||
{
|
||||
ci->me = ci->me->def->body.alias.original_me;
|
||||
ci->defined_class = find_defined_class_by_owner(ci->defined_class, ci->me->klass);
|
||||
goto again;
|
||||
}
|
||||
ci->me = aliased_callable_method_entry(ci->me);
|
||||
goto again;
|
||||
case VM_METHOD_TYPE_MISSING:
|
||||
{
|
||||
VALUE new_args = rb_ary_new4(ci->argc, argv);
|
||||
|
@ -258,10 +254,9 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
|
|||
}
|
||||
|
||||
VALUE
|
||||
rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||||
const rb_method_entry_t *me, VALUE defined_class)
|
||||
rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me)
|
||||
{
|
||||
return vm_call0(th, recv, id, argc, argv, me, defined_class);
|
||||
return vm_call0(th, recv, id, argc, argv, me);
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
|
@ -270,22 +265,24 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
|
|||
VALUE recv = th->cfp->self;
|
||||
VALUE klass;
|
||||
ID id;
|
||||
rb_method_entry_t *me;
|
||||
rb_control_frame_t *cfp = th->cfp;
|
||||
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
|
||||
|
||||
if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) || NIL_P(cfp->klass)) {
|
||||
if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
|
||||
rb_bug("vm_call_super: should not be reached");
|
||||
}
|
||||
|
||||
klass = RCLASS_ORIGIN(cfp->klass);
|
||||
klass = RCLASS_ORIGIN(me->defined_class);
|
||||
klass = RCLASS_SUPER(klass);
|
||||
id = rb_vm_frame_method_entry(cfp)->def->original_id;
|
||||
me = rb_method_entry(klass, id, &klass);
|
||||
id = me->def->original_id;
|
||||
me = rb_callable_method_entry(klass, id);
|
||||
|
||||
if (!me) {
|
||||
return method_missing(recv, id, argc, argv, MISSING_SUPER);
|
||||
}
|
||||
|
||||
return vm_call0(th, recv, id, argc, argv, me, klass);
|
||||
else {
|
||||
return vm_call0(th, recv, id, argc, argv, me);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -316,9 +313,8 @@ stack_check(void)
|
|||
}
|
||||
}
|
||||
|
||||
static inline rb_method_entry_t *
|
||||
rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr);
|
||||
static inline enum method_missing_reason rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self);
|
||||
static inline const rb_callable_method_entry_t *rb_search_method_entry(VALUE recv, ID mid);
|
||||
static inline enum method_missing_reason rb_method_call_status(rb_thread_t *th, const rb_callable_method_entry_t *me, call_type scope, VALUE self);
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
|
@ -339,9 +335,7 @@ static inline VALUE
|
|||
rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
|
||||
call_type scope, VALUE self)
|
||||
{
|
||||
VALUE defined_class;
|
||||
rb_method_entry_t *me =
|
||||
rb_search_method_entry(recv, mid, &defined_class);
|
||||
const rb_callable_method_entry_t *me = rb_search_method_entry(recv, mid);
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
enum method_missing_reason call_status = rb_method_call_status(th, me, scope, self);
|
||||
|
||||
|
@ -349,7 +343,7 @@ rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
|
|||
return method_missing(recv, mid, argc, argv, call_status);
|
||||
}
|
||||
stack_check();
|
||||
return vm_call0(th, recv, mid, argc, argv, me, defined_class);
|
||||
return vm_call0(th, recv, mid, argc, argv, me);
|
||||
}
|
||||
|
||||
struct rescue_funcall_args {
|
||||
|
@ -384,13 +378,12 @@ check_funcall_failed(struct rescue_funcall_args *args, VALUE e)
|
|||
static int
|
||||
check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid)
|
||||
{
|
||||
VALUE defined_class;
|
||||
const rb_method_entry_t *me = rb_method_entry(klass, idRespond_to, &defined_class);
|
||||
const rb_callable_method_entry_t *me = rb_callable_method_entry(klass, idRespond_to);
|
||||
|
||||
if (me && !METHOD_ENTRY_BASIC(me)) {
|
||||
const rb_block_t *passed_block = th->passed_block;
|
||||
VALUE args[2], result;
|
||||
int arity = rb_method_entry_arity(me);
|
||||
int arity = rb_method_entry_arity((const rb_method_entry_t *)me);
|
||||
|
||||
if (arity > 2)
|
||||
rb_raise(rb_eArgError, "respond_to? must accept 1 or 2 arguments (requires %d)", arity);
|
||||
|
@ -399,7 +392,7 @@ check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid)
|
|||
|
||||
args[0] = ID2SYM(mid);
|
||||
args[1] = Qtrue;
|
||||
result = vm_call0(th, recv, idRespond_to, arity, args, me, defined_class);
|
||||
result = vm_call0(th, recv, idRespond_to, arity, args, me);
|
||||
th->passed_block = passed_block;
|
||||
if (!RTEST(result)) {
|
||||
return FALSE;
|
||||
|
@ -409,7 +402,7 @@ check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid)
|
|||
}
|
||||
|
||||
static int
|
||||
check_funcall_callable(rb_thread_t *th, const rb_method_entry_t *me)
|
||||
check_funcall_callable(rb_thread_t *th, const rb_callable_method_entry_t *me)
|
||||
{
|
||||
return rb_method_call_status(th, me, CALL_FCALL, th->cfp->self) == MISSING_NONE;
|
||||
}
|
||||
|
@ -438,19 +431,18 @@ VALUE
|
|||
rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
|
||||
{
|
||||
VALUE klass = CLASS_OF(recv);
|
||||
const rb_method_entry_t *me;
|
||||
const rb_callable_method_entry_t *me;
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
VALUE defined_class;
|
||||
|
||||
if (!check_funcall_respond_to(th, klass, recv, mid))
|
||||
return Qundef;
|
||||
|
||||
me = rb_search_method_entry(recv, mid, &defined_class);
|
||||
me = rb_search_method_entry(recv, mid);
|
||||
if (!check_funcall_callable(th, me)) {
|
||||
return check_funcall_missing(th, klass, recv, mid, argc, argv);
|
||||
}
|
||||
stack_check();
|
||||
return vm_call0(th, recv, mid, argc, argv, me, defined_class);
|
||||
return vm_call0(th, recv, mid, argc, argv, me);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -458,21 +450,20 @@ rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv,
|
|||
rb_check_funcall_hook *hook, VALUE arg)
|
||||
{
|
||||
VALUE klass = CLASS_OF(recv);
|
||||
const rb_method_entry_t *me;
|
||||
const rb_callable_method_entry_t *me;
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
VALUE defined_class;
|
||||
|
||||
if (!check_funcall_respond_to(th, klass, recv, mid))
|
||||
return Qundef;
|
||||
|
||||
me = rb_search_method_entry(recv, mid, &defined_class);
|
||||
me = rb_search_method_entry(recv, mid);
|
||||
if (!check_funcall_callable(th, me)) {
|
||||
(*hook)(FALSE, recv, mid, argc, argv, arg);
|
||||
return check_funcall_missing(th, klass, recv, mid, argc, argv);
|
||||
}
|
||||
stack_check();
|
||||
(*hook)(TRUE, recv, mid, argc, argv, arg);
|
||||
return vm_call0(th, recv, mid, argc, argv, me, defined_class);
|
||||
return vm_call0(th, recv, mid, argc, argv, me);
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
@ -511,8 +502,8 @@ rb_type_str(enum ruby_value_type type)
|
|||
#undef type_case
|
||||
}
|
||||
|
||||
static inline rb_method_entry_t *
|
||||
rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
|
||||
static inline const rb_callable_method_entry_t *
|
||||
rb_search_method_entry(VALUE recv, ID mid)
|
||||
{
|
||||
VALUE klass = CLASS_OF(recv);
|
||||
|
||||
|
@ -550,11 +541,11 @@ rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
|
|||
rb_id2str(mid), type, (void *)recv, flags);
|
||||
}
|
||||
}
|
||||
return rb_method_entry(klass, mid, defined_class_ptr);
|
||||
return rb_callable_method_entry(klass, mid);
|
||||
}
|
||||
|
||||
static inline enum method_missing_reason
|
||||
rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self)
|
||||
rb_method_call_status(rb_thread_t *th, const rb_callable_method_entry_t *me, call_type scope, VALUE self)
|
||||
{
|
||||
VALUE klass;
|
||||
ID oid;
|
||||
|
@ -565,10 +556,11 @@ rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type sc
|
|||
return scope == CALL_VCALL ? MISSING_VCALL : MISSING_NOENTRY;
|
||||
}
|
||||
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
me = rb_resolve_refined_method(Qnil, me, NULL);
|
||||
me = rb_resolve_refined_method_callable(Qnil, me);
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me)) goto undefined;
|
||||
}
|
||||
klass = me->klass;
|
||||
|
||||
klass = me->owner;
|
||||
oid = me->def->original_id;
|
||||
visi = METHOD_ENTRY_VISI(me);
|
||||
|
||||
|
@ -1306,7 +1298,6 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_
|
|||
}
|
||||
}
|
||||
vm_set_eval_stack(th, iseqval, cref, base_block);
|
||||
th->cfp->klass = CLASS_OF(base_block->self);
|
||||
RB_GC_GUARD(crefval);
|
||||
|
||||
if (0) { /* for debug */
|
||||
|
|
250
vm_insnhelper.c
250
vm_insnhelper.c
|
@ -22,8 +22,7 @@
|
|||
#define INLINE inline
|
||||
#endif
|
||||
|
||||
static rb_control_frame_t *
|
||||
vm_get_ruby_level_caller_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp);
|
||||
static rb_control_frame_t *vm_get_ruby_level_caller_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp);
|
||||
|
||||
VALUE
|
||||
ruby_vm_sysstack_error_copy(void)
|
||||
|
@ -40,6 +39,34 @@ vm_stackoverflow(void)
|
|||
}
|
||||
|
||||
#if VM_CHECK_MODE > 0
|
||||
|
||||
static int
|
||||
callable_class_p(VALUE klass)
|
||||
{
|
||||
#if VM_CHECK_MODE >= 2
|
||||
while (klass) {
|
||||
if (klass == rb_cBasicObject) {
|
||||
return TRUE;
|
||||
}
|
||||
klass = RCLASS_SUPER(klass);
|
||||
}
|
||||
return FALSE;
|
||||
#else
|
||||
return klass != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
callable_method_entry_p(const rb_callable_method_entry_t *me)
|
||||
{
|
||||
if (me == NULL || callable_class_p(me->defined_class)) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_frame(int magic, int req_block, int req_me, int req_cref, VALUE specval, VALUE cref_or_me)
|
||||
{
|
||||
|
@ -76,6 +103,14 @@ check_frame(int magic, int req_block, int req_me, int req_cref, VALUE specval, V
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cref_or_me_type == imemo_ment) {
|
||||
const rb_callable_method_entry_t *me = (const rb_callable_method_entry_t *)cref_or_me;
|
||||
|
||||
if (!callable_method_entry_p(me)) {
|
||||
rb_bug("vm_push_frame: ment (%s) should be callable on %x frame.", rb_obj_info(cref_or_me), magic);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -84,7 +119,6 @@ vm_push_frame(rb_thread_t *th,
|
|||
const rb_iseq_t *iseq,
|
||||
VALUE type,
|
||||
VALUE self,
|
||||
VALUE klass,
|
||||
VALUE specval,
|
||||
VALUE cref_or_me,
|
||||
const VALUE *pc,
|
||||
|
@ -147,19 +181,6 @@ vm_push_frame(rb_thread_t *th,
|
|||
cfp->block_iseq = 0;
|
||||
cfp->proc = 0;
|
||||
|
||||
if (klass) {
|
||||
cfp->klass = klass;
|
||||
}
|
||||
else {
|
||||
rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
||||
if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, prev_cfp)) {
|
||||
cfp->klass = Qnil;
|
||||
}
|
||||
else {
|
||||
cfp->klass = prev_cfp->klass;
|
||||
}
|
||||
}
|
||||
|
||||
if (VMDEBUG == 2) {
|
||||
SDR();
|
||||
}
|
||||
|
@ -334,7 +355,7 @@ vm_getspecial(rb_thread_t *th, VALUE *lep, rb_num_t key, rb_num_t type)
|
|||
return val;
|
||||
}
|
||||
|
||||
static rb_method_entry_t *
|
||||
static rb_callable_method_entry_t *
|
||||
check_method_entry(VALUE obj, int can_be_svar)
|
||||
{
|
||||
if (obj == Qfalse) return NULL;
|
||||
|
@ -345,7 +366,7 @@ check_method_entry(VALUE obj, int can_be_svar)
|
|||
|
||||
switch (imemo_type(obj)) {
|
||||
case imemo_ment:
|
||||
return (rb_method_entry_t *)obj;
|
||||
return (rb_callable_method_entry_t *)obj;
|
||||
case imemo_cref:
|
||||
return NULL;
|
||||
case imemo_svar:
|
||||
|
@ -360,11 +381,11 @@ check_method_entry(VALUE obj, int can_be_svar)
|
|||
}
|
||||
}
|
||||
|
||||
const rb_method_entry_t *
|
||||
const rb_callable_method_entry_t *
|
||||
rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
|
||||
{
|
||||
VALUE *ep = cfp->ep;
|
||||
rb_method_entry_t *me;
|
||||
rb_callable_method_entry_t *me;
|
||||
|
||||
while (!VM_EP_LEP_P(ep)) {
|
||||
if ((me = check_method_entry(ep[-1], FALSE)) != NULL) return me;
|
||||
|
@ -375,7 +396,7 @@ rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
|
|||
}
|
||||
|
||||
static rb_cref_t *
|
||||
method_entry_cref(rb_method_entry_t *me)
|
||||
method_entry_cref(rb_callable_method_entry_t *me)
|
||||
{
|
||||
switch (me->def->type) {
|
||||
case VM_METHOD_TYPE_ISEQ:
|
||||
|
@ -396,7 +417,7 @@ check_cref(VALUE obj, int can_be_svar)
|
|||
|
||||
switch (imemo_type(obj)) {
|
||||
case imemo_ment:
|
||||
return method_entry_cref((rb_method_entry_t *)obj);
|
||||
return method_entry_cref((rb_callable_method_entry_t *)obj);
|
||||
case imemo_cref:
|
||||
return (rb_cref_t *)obj;
|
||||
case imemo_svar:
|
||||
|
@ -558,15 +579,7 @@ vm_check_if_namespace(VALUE klass)
|
|||
static inline VALUE
|
||||
vm_get_iclass(rb_control_frame_t *cfp, VALUE klass)
|
||||
{
|
||||
if (RB_TYPE_P(klass, T_MODULE) &&
|
||||
FL_TEST(klass, RMODULE_IS_OVERLAID) &&
|
||||
RB_TYPE_P(cfp->klass, T_ICLASS) &&
|
||||
RBASIC(cfp->klass)->klass == klass) {
|
||||
return cfp->klass;
|
||||
}
|
||||
else {
|
||||
return klass;
|
||||
}
|
||||
return klass;
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
|
@ -1040,7 +1053,8 @@ vm_search_method(rb_call_info_t *ci, VALUE recv)
|
|||
}
|
||||
#endif
|
||||
|
||||
ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
|
||||
ci->me = rb_callable_method_entry(klass, ci->mid);
|
||||
VM_ASSERT(callable_method_entry_p(ci->me));
|
||||
ci->klass = klass;
|
||||
ci->call = vm_call_general;
|
||||
#if OPT_INLINE_METHOD_CACHE
|
||||
|
@ -1050,7 +1064,7 @@ vm_search_method(rb_call_info_t *ci, VALUE recv)
|
|||
}
|
||||
|
||||
static inline int
|
||||
check_cfunc(const rb_method_entry_t *me, VALUE (*func)())
|
||||
check_cfunc(const rb_callable_method_entry_t *me, VALUE (*func)())
|
||||
{
|
||||
if (me && me->def->type == VM_METHOD_TYPE_CFUNC &&
|
||||
me->def->body.cfunc.func == func) {
|
||||
|
@ -1114,12 +1128,11 @@ rb_equal_opt(VALUE obj1, VALUE obj2)
|
|||
ci.klass = 0;
|
||||
ci.method_state = 0;
|
||||
ci.me = NULL;
|
||||
ci.defined_class = 0;
|
||||
ci.class_serial = 0;
|
||||
return opt_eq_func(obj1, obj2, &ci);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
vm_call0(rb_thread_t*, VALUE, ID, int, const VALUE*, const rb_method_entry_t*, VALUE);
|
||||
static VALUE vm_call0(rb_thread_t*, VALUE, ID, int, const VALUE*, const rb_callable_method_entry_t *);
|
||||
|
||||
static VALUE
|
||||
check_match(VALUE pattern, VALUE target, enum vm_check_match_type type)
|
||||
|
@ -1133,10 +1146,9 @@ check_match(VALUE pattern, VALUE target, enum vm_check_match_type type)
|
|||
}
|
||||
/* fall through */
|
||||
case VM_CHECKMATCH_TYPE_CASE: {
|
||||
VALUE defined_class;
|
||||
const rb_method_entry_t *me = rb_method_entry_with_refinements(CLASS_OF(pattern), idEqq, &defined_class);
|
||||
const rb_callable_method_entry_t *me = rb_callable_method_entry_with_refinements(CLASS_OF(pattern), idEqq);
|
||||
if (me) {
|
||||
return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me, defined_class);
|
||||
return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me);
|
||||
}
|
||||
else {
|
||||
/* fallback to funcall (e.g. method_missing) */
|
||||
|
@ -1352,7 +1364,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info
|
|||
{
|
||||
int i, local_size;
|
||||
VALUE *argv = cfp->sp - ci->argc;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
const rb_callable_method_entry_t *me = ci->me;
|
||||
rb_iseq_t *iseq = def_iseq_ptr(me->def);
|
||||
VALUE *sp = argv + iseq->param.size;
|
||||
|
||||
|
@ -1361,7 +1373,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info
|
|||
*sp++ = Qnil;
|
||||
}
|
||||
|
||||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class,
|
||||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv,
|
||||
VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me,
|
||||
iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, iseq->stack_max);
|
||||
|
||||
|
@ -1374,7 +1386,7 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
|
|||
{
|
||||
int i;
|
||||
VALUE *argv = cfp->sp - ci->argc;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
const rb_callable_method_entry_t *me = ci->me;
|
||||
rb_iseq_t *iseq = def_iseq_ptr(me->def);
|
||||
VALUE *src_argv = argv;
|
||||
VALUE *sp_orig, *sp;
|
||||
|
@ -1401,8 +1413,7 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
|
|||
}
|
||||
|
||||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag,
|
||||
ci->recv, ci->defined_class,
|
||||
VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me,
|
||||
ci->recv, VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me,
|
||||
iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, iseq->stack_max);
|
||||
|
||||
cfp->sp = sp_orig;
|
||||
|
@ -1541,7 +1552,7 @@ vm_profile_show_result(void)
|
|||
|
||||
static inline
|
||||
const rb_method_cfunc_t *
|
||||
vm_method_cfunc_entry(const rb_method_entry_t *me)
|
||||
vm_method_cfunc_entry(const rb_callable_method_entry_t *me)
|
||||
{
|
||||
#if VM_DEBUG_VERIFY_METHOD_CACHE
|
||||
switch (me->def->type) {
|
||||
|
@ -1571,20 +1582,19 @@ static VALUE
|
|||
vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
||||
{
|
||||
VALUE val;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
const rb_callable_method_entry_t *me = ci->me;
|
||||
const rb_method_cfunc_t *cfunc = vm_method_cfunc_entry(me);
|
||||
int len = cfunc->argc;
|
||||
|
||||
/* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */
|
||||
VALUE recv = ci->recv;
|
||||
VALUE defined_class = ci->defined_class;
|
||||
rb_block_t *blockptr = ci->blockptr;
|
||||
int argc = ci->argc;
|
||||
|
||||
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef);
|
||||
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, me->called_id);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->owner, Qundef);
|
||||
|
||||
vm_push_frame(th, NULL, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
|
||||
vm_push_frame(th, NULL, VM_FRAME_MAGIC_CFUNC, recv,
|
||||
VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)me,
|
||||
0, th->cfp->sp, 1, 0);
|
||||
|
||||
|
@ -1600,8 +1610,8 @@ vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_i
|
|||
|
||||
vm_pop_frame(th);
|
||||
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
|
||||
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->owner, val);
|
||||
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->called_id);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -1644,15 +1654,15 @@ static VALUE
|
|||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
||||
{
|
||||
VALUE val;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
const rb_callable_method_entry_t *me = ci->me;
|
||||
int len = vm_method_cfunc_entry(me)->argc;
|
||||
VALUE recv = ci->recv;
|
||||
|
||||
CALLER_SETUP_ARG(reg_cfp, ci);
|
||||
if (len >= 0) rb_check_arity(ci->argc, len, len);
|
||||
|
||||
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qnil);
|
||||
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->owner, me->called_id);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->owner, Qnil);
|
||||
|
||||
if (!(ci->me->def->flag & METHOD_VISI_PROTECTED) &&
|
||||
!(ci->flag & VM_CALL_ARGS_SPLAT) &&
|
||||
|
@ -1661,8 +1671,8 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
|||
}
|
||||
val = vm_call_cfunc_latter(th, reg_cfp, ci);
|
||||
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
|
||||
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->owner, val);
|
||||
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->called_id);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -1671,11 +1681,11 @@ void
|
|||
rb_vm_call_cfunc_push_frame(rb_thread_t *th)
|
||||
{
|
||||
rb_call_info_t *ci = th->passed_ci;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
const rb_callable_method_entry_t *me = ci->me;
|
||||
th->passed_ci = 0;
|
||||
|
||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
|
||||
VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me /* cref */,
|
||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
||||
ci->recv, VM_ENVVAL_BLOCK_PTR(ci->blockptr), (VALUE)me /* cref */,
|
||||
0, th->cfp->sp + ci->aux.inc_sp, 1, 0);
|
||||
|
||||
if (ci->call != vm_call_general) {
|
||||
|
@ -1716,7 +1726,7 @@ vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv)
|
|||
/* control block frame */
|
||||
th->passed_bmethod_me = ci->me;
|
||||
GetProcPtr(ci->me->def->body.proc, proc);
|
||||
val = vm_invoke_bmethod(th, proc, ci->recv, ci->defined_class, ci->argc, argv, ci->blockptr);
|
||||
val = vm_invoke_bmethod(th, proc, ci->recv, ci->argc, argv, ci->blockptr);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -1790,7 +1800,7 @@ vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *c
|
|||
ci->argc -= 1;
|
||||
DEC_SP(1);
|
||||
}
|
||||
ci->me = rb_method_entry_without_refinements(CLASS_OF(ci->recv), ci->mid, &ci->defined_class);
|
||||
ci->me = rb_callable_method_entry_without_refinements(CLASS_OF(ci->recv), ci->mid);
|
||||
|
||||
ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND;
|
||||
|
||||
|
@ -1828,7 +1838,7 @@ vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
|
|||
ci_entry.mid = idMethodMissing;
|
||||
ci_entry.blockptr = ci->blockptr;
|
||||
ci_entry.recv = ci->recv;
|
||||
ci_entry.me = rb_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing, &ci_entry.defined_class);
|
||||
ci_entry.me = rb_callable_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing);
|
||||
ci_entry.kw_arg = NULL;
|
||||
|
||||
/* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
|
||||
|
@ -1892,6 +1902,55 @@ find_defined_class_by_owner(VALUE current_class, VALUE target_owner)
|
|||
return current_class; /* maybe module function */
|
||||
}
|
||||
|
||||
static rb_method_definition_t *method_definition_create(rb_method_type_t type, ID mid);
|
||||
static void method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts);
|
||||
|
||||
static const rb_callable_method_entry_t *
|
||||
aliased_callable_method_entry(const rb_callable_method_entry_t *me)
|
||||
{
|
||||
const rb_method_entry_t *orig_me = me->def->body.alias.original_me;
|
||||
const rb_callable_method_entry_t *cme;
|
||||
|
||||
if (orig_me->defined_class == 0) {
|
||||
VALUE defined_class = find_defined_class_by_owner(me->defined_class, orig_me->owner);
|
||||
VM_ASSERT(RB_TYPE_P(orig_me->owner, T_MODULE));
|
||||
cme = rb_method_entry_complement_defined_class(orig_me, defined_class);
|
||||
|
||||
if (me->def->alias_count == 0) {
|
||||
RB_OBJ_WRITE(me, &me->def->body.alias.original_me, cme);
|
||||
}
|
||||
else {
|
||||
method_definition_set((rb_method_entry_t *)me,
|
||||
method_definition_create(VM_METHOD_TYPE_ALIAS, me->def->original_id),
|
||||
(void *)cme);
|
||||
}
|
||||
}
|
||||
else {
|
||||
cme = (const rb_callable_method_entry_t *)orig_me;
|
||||
}
|
||||
|
||||
VM_ASSERT(callable_method_entry_p(cme));
|
||||
return cme;
|
||||
}
|
||||
|
||||
static const rb_callable_method_entry_t *
|
||||
refined_method_callable_without_refinement(const rb_callable_method_entry_t *me)
|
||||
{
|
||||
const rb_method_entry_t *orig_me = me->def->body.refined.orig_me;
|
||||
const rb_callable_method_entry_t *cme;
|
||||
|
||||
if (orig_me->defined_class == 0) {
|
||||
cme = NULL;
|
||||
rb_notimplement();
|
||||
}
|
||||
else {
|
||||
cme = (const rb_callable_method_entry_t *)orig_me;
|
||||
}
|
||||
|
||||
VM_ASSERT(callable_method_entry_p(cme));
|
||||
return cme;
|
||||
}
|
||||
|
||||
static
|
||||
#ifdef _MSC_VER
|
||||
__forceinline
|
||||
|
@ -1904,12 +1963,16 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|||
int enable_fastpath = 1;
|
||||
rb_call_info_t ci_temp;
|
||||
|
||||
VM_ASSERT(callable_method_entry_p(ci->me));
|
||||
|
||||
start_method_dispatch:
|
||||
VM_ASSERT(callable_method_entry_p(ci->me));
|
||||
if (ci->me != 0) {
|
||||
if (LIKELY(METHOD_ENTRY_VISI(ci->me) == METHOD_VISI_PUBLIC && METHOD_ENTRY_SAFE(ci->me) == 0)) {
|
||||
VALUE klass;
|
||||
|
||||
normal_method_dispatch:
|
||||
VM_ASSERT(callable_method_entry_p(ci->me));
|
||||
switch (ci->me->def->type) {
|
||||
case VM_METHOD_TYPE_ISEQ:{
|
||||
CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath);
|
||||
|
@ -1943,7 +2006,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|||
return vm_call_bmethod(th, cfp, ci);
|
||||
}
|
||||
case VM_METHOD_TYPE_ZSUPER:{
|
||||
klass = ci->me->klass;
|
||||
klass = ci->me->owner;
|
||||
klass = RCLASS_ORIGIN(klass);
|
||||
zsuper_method_dispatch:
|
||||
klass = RCLASS_SUPER(klass);
|
||||
|
@ -1954,7 +2017,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|||
ci_temp = *ci;
|
||||
ci = &ci_temp;
|
||||
|
||||
ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
|
||||
ci->me = rb_callable_method_entry(klass, ci->mid);
|
||||
|
||||
if (ci->me != 0) {
|
||||
goto normal_method_dispatch;
|
||||
|
@ -1963,11 +2026,9 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|||
goto start_method_dispatch;
|
||||
}
|
||||
}
|
||||
case VM_METHOD_TYPE_ALIAS: {
|
||||
ci->me = ci->me->def->body.alias.original_me;
|
||||
ci->defined_class = find_defined_class_by_owner(ci->defined_class, ci->me->klass /* owner */);
|
||||
case VM_METHOD_TYPE_ALIAS:
|
||||
ci->me = aliased_callable_method_entry(ci->me);
|
||||
goto normal_method_dispatch;
|
||||
}
|
||||
case VM_METHOD_TYPE_OPTIMIZED:{
|
||||
switch (ci->me->def->body.optimize_type) {
|
||||
case OPTIMIZED_METHOD_TYPE_SEND:
|
||||
|
@ -1987,26 +2048,24 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|||
case VM_METHOD_TYPE_REFINED:{
|
||||
const rb_cref_t *cref = rb_vm_get_cref(cfp->ep);
|
||||
VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
|
||||
VALUE refinement, defined_class;
|
||||
rb_method_entry_t *me;
|
||||
VALUE refinement;
|
||||
const rb_callable_method_entry_t *me;
|
||||
|
||||
refinement = find_refinement(refinements,
|
||||
ci->defined_class);
|
||||
refinement = find_refinement(refinements, ci->me->owner);
|
||||
if (NIL_P(refinement)) {
|
||||
goto no_refinement_dispatch;
|
||||
}
|
||||
me = rb_method_entry(refinement, ci->mid, &defined_class);
|
||||
me = rb_callable_method_entry(refinement, ci->mid);
|
||||
if (me) {
|
||||
if (ci->call == vm_call_super_method) {
|
||||
const rb_control_frame_t *top_cfp = current_method_entry(th, cfp);
|
||||
const rb_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp);
|
||||
const rb_callable_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp);
|
||||
|
||||
if (top_me && rb_method_definition_eq(me->def, top_me->def)) {
|
||||
goto no_refinement_dispatch;
|
||||
}
|
||||
}
|
||||
ci->me = me;
|
||||
ci->defined_class = defined_class;
|
||||
if (me->def->type != VM_METHOD_TYPE_REFINED) {
|
||||
goto start_method_dispatch;
|
||||
}
|
||||
|
@ -2018,14 +2077,15 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|||
|
||||
no_refinement_dispatch:
|
||||
if (ci->me->def->body.refined.orig_me) {
|
||||
ci->me = ci->me->def->body.refined.orig_me;
|
||||
ci->me = refined_method_callable_without_refinement(ci->me);
|
||||
|
||||
if (UNDEFINED_METHOD_ENTRY_P(ci->me)) {
|
||||
ci->me = 0;
|
||||
}
|
||||
goto start_method_dispatch;
|
||||
}
|
||||
else {
|
||||
klass = ci->me->klass;
|
||||
klass = ci->me->owner;
|
||||
goto zsuper_method_dispatch;
|
||||
}
|
||||
}
|
||||
|
@ -2045,7 +2105,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|||
}
|
||||
else if (!(ci->flag & VM_CALL_OPT_SEND) && (METHOD_ENTRY_VISI(ci->me) == METHOD_VISI_PROTECTED)) {
|
||||
enable_fastpath = 0;
|
||||
if (!rb_obj_is_kind_of(cfp->self, ci->defined_class)) {
|
||||
if (!rb_obj_is_kind_of(cfp->self, ci->me->defined_class)) {
|
||||
ci->aux.method_missing_reason = MISSING_PROTECTED;
|
||||
return vm_call_method_missing(th, cfp, ci);
|
||||
}
|
||||
|
@ -2113,7 +2173,7 @@ vm_super_outside(void)
|
|||
static int
|
||||
vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci)
|
||||
{
|
||||
const rb_method_entry_t *me;
|
||||
const rb_callable_method_entry_t *me;
|
||||
|
||||
while (iseq && !iseq->klass) {
|
||||
iseq = iseq->parent_iseq;
|
||||
|
@ -2157,10 +2217,11 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval,
|
|||
}
|
||||
|
||||
ci->mid = me->def->original_id;
|
||||
ci->klass = vm_search_normal_superclass(lcfp->klass);
|
||||
ci->klass = vm_search_normal_superclass(me->defined_class);
|
||||
}
|
||||
else {
|
||||
ci->klass = vm_search_normal_superclass(reg_cfp->klass);
|
||||
me = rb_vm_frame_method_entry(reg_cfp);
|
||||
ci->klass = vm_search_normal_superclass(me->defined_class);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2172,12 +2233,14 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
|
|||
VALUE current_defined_class;
|
||||
rb_iseq_t *iseq = GET_ISEQ();
|
||||
VALUE sigval = TOPN(ci->argc);
|
||||
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(reg_cfp);
|
||||
|
||||
current_defined_class = GET_CFP()->klass;
|
||||
if (NIL_P(current_defined_class)) {
|
||||
if (!me) {
|
||||
vm_super_outside();
|
||||
}
|
||||
|
||||
current_defined_class = me->defined_class;
|
||||
|
||||
if (!NIL_P(RCLASS_REFINED_CLASS(current_defined_class))) {
|
||||
current_defined_class = RCLASS_REFINED_CLASS(current_defined_class);
|
||||
}
|
||||
|
@ -2212,7 +2275,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
|
|||
}
|
||||
|
||||
/* TODO: use inline cache */
|
||||
ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
|
||||
ci->me = rb_callable_method_entry(ci->klass, ci->mid);
|
||||
ci->call = vm_call_super_method;
|
||||
|
||||
while (iseq && !iseq->klass) {
|
||||
|
@ -2220,8 +2283,8 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
|
|||
}
|
||||
|
||||
if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && def_iseq_ptr(ci->me->def) == iseq) {
|
||||
ci->klass = RCLASS_SUPER(ci->defined_class);
|
||||
ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
|
||||
ci->klass = RCLASS_SUPER(ci->me->defined_class);
|
||||
ci->me = rb_callable_method_entry(ci->klass, ci->mid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2242,15 +2305,14 @@ block_proc_is_lambda(const VALUE procval)
|
|||
}
|
||||
|
||||
static inline VALUE
|
||||
vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
|
||||
VALUE self, VALUE defined_class,
|
||||
vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, VALUE self,
|
||||
int argc, const VALUE *argv,
|
||||
const rb_block_t *blockargptr)
|
||||
{
|
||||
const struct vm_ifunc *ifunc = (struct vm_ifunc *)block->iseq;
|
||||
VALUE val, arg, blockarg;
|
||||
int lambda = block_proc_is_lambda(block->proc);
|
||||
const rb_method_entry_t *me = th->passed_bmethod_me;
|
||||
const rb_callable_method_entry_t *me = th->passed_bmethod_me;
|
||||
th->passed_bmethod_me = NULL;
|
||||
|
||||
if (lambda) {
|
||||
|
@ -2276,8 +2338,7 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
|
|||
}
|
||||
|
||||
vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC,
|
||||
self, defined_class,
|
||||
VM_ENVVAL_PREV_EP_PTR(block->ep), (VALUE)me,
|
||||
self, VM_ENVVAL_PREV_EP_PTR(block->ep), (VALUE)me,
|
||||
0, th->cfp->sp, 1, 0);
|
||||
|
||||
val = (*ifunc->func) (arg, ifunc->data, argc, argv, blockarg);
|
||||
|
@ -2332,7 +2393,6 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci
|
|||
vm_push_frame(th, iseq,
|
||||
is_lambda ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK,
|
||||
block->self,
|
||||
block->klass,
|
||||
VM_ENVVAL_PREV_EP_PTR(block->ep), 0,
|
||||
iseq->iseq_encoded + opt_pc,
|
||||
rsp + arg_size,
|
||||
|
@ -2343,7 +2403,7 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci
|
|||
else {
|
||||
VALUE val;
|
||||
CALLER_SETUP_ARG(th->cfp, ci);
|
||||
val = vm_yield_with_cfunc(th, block, block->self, block->klass,
|
||||
val = vm_yield_with_cfunc(th, block, block->self,
|
||||
ci->argc, STACK_ADDR_FROM_TOP(ci->argc), 0);
|
||||
POPN(ci->argc); /* TODO: should put before C/yield? */
|
||||
return val;
|
||||
|
@ -2461,7 +2521,7 @@ vm_defined(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE
|
|||
break;
|
||||
case DEFINED_METHOD:{
|
||||
VALUE klass = CLASS_OF(v);
|
||||
const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj), 0);
|
||||
const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj));
|
||||
|
||||
if (me) {
|
||||
switch (METHOD_ENTRY_VISI(me)) {
|
||||
|
|
322
vm_method.c
322
vm_method.c
|
@ -93,6 +93,15 @@ rb_clear_method_cache_by_class(VALUE klass)
|
|||
else {
|
||||
rb_class_clear_method_cache(klass, Qnil);
|
||||
}
|
||||
|
||||
if (RB_TYPE_P(klass, T_MODULE)) {
|
||||
rb_subclass_entry_t *entry = RCLASS_EXT(klass)->subclasses;
|
||||
|
||||
for (; entry != NULL; entry = entry->next) {
|
||||
struct st_table *table = RCLASS_CALLABLE_M_TBL(entry->klass);
|
||||
if (table) st_clear(table);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +210,7 @@ setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
|
|||
}
|
||||
|
||||
static void
|
||||
method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
|
||||
method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
|
||||
{
|
||||
*(rb_method_definition_t **)&me->def = def;
|
||||
|
||||
|
@ -263,8 +272,12 @@ method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *
|
|||
def->body.optimize_type = (enum method_optimized_type)opts;
|
||||
return;
|
||||
case VM_METHOD_TYPE_REFINED:
|
||||
RB_OBJ_WRITE(me, &def->body.refined.orig_me, (rb_method_entry_t *)opts);
|
||||
return;
|
||||
{
|
||||
const rb_method_refined_t *refined = (rb_method_refined_t *)opts;
|
||||
RB_OBJ_WRITE(me, &def->body.refined.orig_me, refined->orig_me);
|
||||
RB_OBJ_WRITE(me, &def->body.refined.owner, refined->owner);
|
||||
return;
|
||||
}
|
||||
case VM_METHOD_TYPE_ALIAS:
|
||||
RB_OBJ_WRITE(me, &def->body.alias.original_me, (rb_method_entry_t *)opts);
|
||||
return;
|
||||
|
@ -273,7 +286,6 @@ method_definition_set(rb_method_entry_t *me, rb_method_definition_t *def, void *
|
|||
case VM_METHOD_TYPE_MISSING:
|
||||
return;
|
||||
}
|
||||
rb_bug("rb_add_method: unsupported method type (%d)\n", def->type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,6 +308,7 @@ method_definition_reset(const rb_method_entry_t *me)
|
|||
break;
|
||||
case VM_METHOD_TYPE_REFINED:
|
||||
RB_OBJ_WRITTEN(me, Qundef, def->body.refined.orig_me);
|
||||
RB_OBJ_WRITTEN(me, Qundef, def->body.refined.owner);
|
||||
break;
|
||||
case VM_METHOD_TYPE_ALIAS:
|
||||
RB_OBJ_WRITTEN(me, Qundef, def->body.alias.original_me);
|
||||
|
@ -328,46 +341,83 @@ method_definition_addref(rb_method_definition_t *def)
|
|||
return def;
|
||||
}
|
||||
|
||||
static rb_method_entry_t *
|
||||
rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, const rb_method_definition_t *def)
|
||||
{
|
||||
rb_method_entry_t *me = (rb_method_entry_t *)rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, owner, defined_class);
|
||||
return me;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
filter_defined_class(VALUE klass)
|
||||
{
|
||||
switch (BUILTIN_TYPE(klass)) {
|
||||
case T_CLASS:
|
||||
return klass;
|
||||
case T_MODULE:
|
||||
return 0;
|
||||
case T_ICLASS:
|
||||
break;
|
||||
}
|
||||
rb_bug("filter_defined_class: %s", rb_obj_info(klass));
|
||||
}
|
||||
|
||||
rb_method_entry_t *
|
||||
rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def)
|
||||
{
|
||||
rb_method_entry_t *me = (rb_method_entry_t *)rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, (VALUE)klass, 0);
|
||||
rb_method_entry_t *me = rb_method_entry_alloc(called_id, klass, filter_defined_class(klass), def);
|
||||
METHOD_ENTRY_FLAGS_SET(me, visi, ruby_running ? FALSE : TRUE, rb_safe_level());
|
||||
if (def != NULL) method_definition_reset(me);
|
||||
return me;
|
||||
}
|
||||
|
||||
rb_method_entry_t *
|
||||
const rb_method_entry_t *
|
||||
rb_method_entry_clone(const rb_method_entry_t *src_me)
|
||||
{
|
||||
rb_method_entry_t *me = rb_method_entry_create(src_me->called_id, src_me->klass,
|
||||
METHOD_ENTRY_VISI(src_me),
|
||||
method_definition_addref(src_me->def));
|
||||
rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, src_me->defined_class,
|
||||
method_definition_addref(src_me->def));
|
||||
METHOD_ENTRY_FLAGS_COPY(me, src_me);
|
||||
return me;
|
||||
}
|
||||
|
||||
const rb_callable_method_entry_t *
|
||||
rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, VALUE defined_class)
|
||||
{
|
||||
rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, defined_class,
|
||||
method_definition_addref(src_me->def));
|
||||
METHOD_ENTRY_FLAGS_COPY(me, src_me);
|
||||
return (rb_callable_method_entry_t *)me;
|
||||
}
|
||||
|
||||
void
|
||||
rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src)
|
||||
{
|
||||
*(rb_method_definition_t **)&dst->def = method_definition_addref(src->def);
|
||||
method_definition_reset(dst);
|
||||
dst->called_id = src->called_id;
|
||||
RB_OBJ_WRITE((VALUE)dst, &dst->klass, src->klass);
|
||||
RB_OBJ_WRITE((VALUE)dst, &dst->owner, src->owner);
|
||||
RB_OBJ_WRITE((VALUE)dst, &dst->defined_class, src->defined_class);
|
||||
METHOD_ENTRY_FLAGS_COPY(dst, src);
|
||||
}
|
||||
|
||||
static void
|
||||
make_method_entry_refined(rb_method_entry_t *me)
|
||||
make_method_entry_refined(VALUE owner, rb_method_entry_t *me)
|
||||
{
|
||||
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
rb_method_entry_t *cloned_me;
|
||||
struct {
|
||||
const struct rb_method_entry_struct *orig_me;
|
||||
VALUE owner;
|
||||
} refined;
|
||||
|
||||
rb_vm_check_redefinition_opt_method(me, me->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,9 +669,9 @@ rb_method_entry_at(VALUE klass, ID id)
|
|||
* if you need method entry with method cache (normal case), use
|
||||
* rb_method_entry() simply.
|
||||
*/
|
||||
rb_method_entry_t *
|
||||
rb_method_entry_get_without_cache(VALUE klass, ID id,
|
||||
VALUE *defined_class_ptr)
|
||||
static rb_method_entry_t *
|
||||
method_entry_get_without_cache(VALUE klass, ID id,
|
||||
VALUE *defined_class_ptr)
|
||||
{
|
||||
VALUE defined_class;
|
||||
rb_method_entry_t *me = search_method(klass, id, &defined_class);
|
||||
|
@ -659,7 +709,7 @@ verify_method_cache(VALUE klass, ID id, VALUE defined_class, rb_method_entry_t *
|
|||
{
|
||||
VALUE actual_defined_class;
|
||||
rb_method_entry_t *actual_me =
|
||||
rb_method_entry_get_without_cache(klass, id, &actual_defined_class);
|
||||
method_entry_get_without_cache(klass, id, &actual_defined_class);
|
||||
|
||||
if (me != actual_me || defined_class != actual_defined_class) {
|
||||
rb_bug("method cache verification failed");
|
||||
|
@ -667,8 +717,8 @@ verify_method_cache(VALUE klass, ID id, VALUE defined_class, rb_method_entry_t *
|
|||
}
|
||||
#endif
|
||||
|
||||
rb_method_entry_t *
|
||||
rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
|
||||
static rb_method_entry_t *
|
||||
method_entry_get(VALUE klass, ID id, VALUE *defined_class_ptr)
|
||||
{
|
||||
#if OPT_GLOBAL_METHOD_CACHE
|
||||
struct cache_entry *ent;
|
||||
|
@ -676,107 +726,182 @@ 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);
|
||||
}
|
||||
|
||||
static const rb_method_entry_t *
|
||||
get_original_method_entry(VALUE refinements,
|
||||
const rb_method_entry_t *me,
|
||||
VALUE *defined_class_ptr)
|
||||
{
|
||||
VALUE super;
|
||||
|
||||
if (me->def->body.refined.orig_me) {
|
||||
return me->def->body.refined.orig_me;
|
||||
}
|
||||
else if (!(super = RCLASS_SUPER(me->klass))) {
|
||||
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);
|
||||
}
|
||||
return method_entry_get_without_cache(klass, id, defined_class_ptr);
|
||||
}
|
||||
|
||||
const rb_method_entry_t *
|
||||
rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me,
|
||||
VALUE *defined_class_ptr)
|
||||
rb_method_entry(VALUE klass, ID id)
|
||||
{
|
||||
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
VALUE refinement;
|
||||
rb_method_entry_t *tmp_me;
|
||||
return method_entry_get(klass, id, NULL);
|
||||
}
|
||||
|
||||
refinement = find_refinement(refinements, me->klass);
|
||||
if (NIL_P(refinement)) {
|
||||
return get_original_method_entry(refinements, me,
|
||||
defined_class_ptr);
|
||||
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();
|
||||
}
|
||||
tmp_me = rb_method_entry(refinement, me->called_id,
|
||||
defined_class_ptr);
|
||||
if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
|
||||
return tmp_me;
|
||||
|
||||
if (st_lookup(mtbl, id, (st_data_t *)&me)) {
|
||||
cme = (rb_callable_method_entry_t *)me;
|
||||
VM_ASSERT(callable_method_entry_p(cme));
|
||||
}
|
||||
else {
|
||||
return get_original_method_entry(refinements, me,
|
||||
defined_class_ptr);
|
||||
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 {
|
||||
return (rb_method_entry_t *)me;
|
||||
cme = (const rb_callable_method_entry_t *)me;
|
||||
}
|
||||
|
||||
VM_ASSERT(callable_method_entry_p(cme));
|
||||
return cme;
|
||||
}
|
||||
|
||||
const rb_method_entry_t *
|
||||
rb_method_entry_with_refinements(VALUE klass, ID id,
|
||||
VALUE *defined_class_ptr)
|
||||
const rb_callable_method_entry_t *
|
||||
rb_callable_method_entry(VALUE klass, ID id)
|
||||
{
|
||||
VALUE defined_class;
|
||||
const rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
|
||||
rb_method_entry_t *me = method_entry_get(klass, id, &defined_class);
|
||||
return prepare_callable_method_entry(defined_class, id, me);
|
||||
}
|
||||
|
||||
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
const rb_cref_t *cref = rb_vm_cref();
|
||||
VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
|
||||
static const rb_method_entry_t *resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr);
|
||||
|
||||
me = rb_resolve_refined_method(refinements, me, &defined_class);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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 = rb_method_entry(klass, id, &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);
|
||||
}
|
||||
|
||||
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
me = rb_resolve_refined_method(Qnil, me, &defined_class);
|
||||
const rb_method_entry_t *
|
||||
rb_method_entry_without_refinements(VALUE klass, ID id)
|
||||
{
|
||||
return method_entry_resolve_refienment(klass, id, FALSE, NULL);
|
||||
}
|
||||
|
||||
const rb_callable_method_entry_t *
|
||||
rb_callable_method_entry_without_refinements(VALUE klass, ID id)
|
||||
{
|
||||
VALUE defined_class;
|
||||
const rb_method_entry_t *me = method_entry_resolve_refienment(klass, id, FALSE, &defined_class);
|
||||
return prepare_callable_method_entry(defined_class, id, me);
|
||||
}
|
||||
|
||||
static const rb_method_entry_t *
|
||||
refiend_method_original_method_entry(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr)
|
||||
{
|
||||
VALUE super;
|
||||
|
||||
if (me->def->body.refined.orig_me) {
|
||||
if (defined_class_ptr) *defined_class_ptr = me->def->body.refined.orig_me->defined_class;
|
||||
return me->def->body.refined.orig_me;
|
||||
}
|
||||
if (defined_class_ptr)
|
||||
*defined_class_ptr = defined_class;
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||
else if (!(super = RCLASS_SUPER(me->owner))) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
rb_method_entry_t *tmp_me;
|
||||
tmp_me = method_entry_get(super, me->called_id, defined_class_ptr);
|
||||
return resolve_refined_method(refinements, tmp_me, 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->owner);
|
||||
if (NIL_P(refinement)) {
|
||||
return refiend_method_original_method_entry(refinements, me, 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 refiend_method_original_method_entry(refinements, me, defined_class_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return me;
|
||||
}
|
||||
}
|
||||
|
||||
const rb_method_entry_t *
|
||||
rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me)
|
||||
{
|
||||
return resolve_refined_method(refinements, me, NULL);
|
||||
}
|
||||
|
||||
const rb_callable_method_entry_t *
|
||||
rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me)
|
||||
{
|
||||
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 (resolved_me && resolved_me->defined_class == 0) {
|
||||
return rb_method_entry_complement_defined_class(resolved_me, defined_class);
|
||||
}
|
||||
else {
|
||||
return (const rb_callable_method_entry_t *)resolved_me;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
remove_method(VALUE klass, ID mid)
|
||||
{
|
||||
|
@ -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)
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче