Feature #4085 » control_frame_change-r29944-20101127.diff
class.c | ||
---|---|---|
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"));
|
||
const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"), 0);
|
||
if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC &&
|
||
me->def->body.cfunc.func == rb_any_to_s)
|
||
return 1;
|
insns.def | ||
---|---|---|
break;
|
||
case DEFINED_METHOD:{
|
||
VALUE klass = CLASS_OF(v);
|
||
const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj));
|
||
const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj), 0);
|
||
if (me) {
|
||
if (!(me->flag & NOEX_PRIVATE)) {
|
||
... | ... | |
/* enter scope */
|
||
vm_push_frame(th, class_iseq,
|
||
VM_FRAME_MAGIC_CLASS, klass, (VALUE) GET_BLOCK_PTR(),
|
||
VM_FRAME_MAGIC_CLASS, klass, 0, (VALUE) GET_BLOCK_PTR(),
|
||
class_iseq->iseq_encoded, GET_SP(), 0,
|
||
class_iseq->local_size);
|
||
RESTORE_REGS();
|
||
... | ... | |
(VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
|
||
{
|
||
const rb_method_entry_t *me;
|
||
VALUE recv, klass;
|
||
VALUE recv, klass, defined_class;
|
||
rb_block_t *blockptr = 0;
|
||
VALUE flag = op_flag;
|
||
int num = caller_setup_args(th, GET_CFP(), flag, (int)op_argc,
|
||
... | ... | |
/* get receiver */
|
||
recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num);
|
||
klass = CLASS_OF(recv);
|
||
me = vm_method_search(id, klass, ic);
|
||
CALL_METHOD(num, blockptr, flag, id, me, recv);
|
||
me = vm_method_search(id, klass, ic, &defined_class);
|
||
CALL_METHOD(num, blockptr, flag, id, me, recv, defined_class);
|
||
}
|
||
/**
|
||
... | ... | |
VALUE recv, klass;
|
||
ID id;
|
||
const rb_method_entry_t *me;
|
||
rb_iseq_t *ip;
|
||
flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
||
recv = GET_SELF();
|
||
vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
|
||
/* temporary measure for [Bug #2402] [Bug #2502] [Bug #3136] */
|
||
if (!rb_obj_is_kind_of(recv, klass)) {
|
||
rb_raise(rb_eNotImpError, "super from singleton method that is defined to multiple classes is not supported; this will be fixed in 1.9.3 or later");
|
||
ip = GET_ISEQ();
|
||
while (ip && !ip->klass) {
|
||
ip = ip->parent_iseq;
|
||
}
|
||
again:
|
||
me = rb_method_entry(klass, id, &klass);
|
||
if (me && me->def->type == VM_METHOD_TYPE_ISEQ &&
|
||
me->def->body.iseq == ip) {
|
||
klass = RCLASS_SUPER(klass);
|
||
goto again;
|
||
}
|
||
me = rb_method_entry(klass, id);
|
||
CALL_METHOD(num, blockptr, flag, id, me, recv);
|
||
CALL_METHOD(num, blockptr, flag, id, me, recv, klass);
|
||
}
|
||
/**
|
||
... | ... | |
(VALUE val)
|
||
{
|
||
extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
|
||
const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic);
|
||
const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic, 0);
|
||
val = Qundef;
|
||
if (check_cfunc(me, rb_obj_not_equal)) {
|
||
... | ... | |
(VALUE val)
|
||
{
|
||
extern VALUE rb_obj_not(VALUE obj);
|
||
const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic);
|
||
const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic, 0);
|
||
if (check_cfunc(me, rb_obj_not)) {
|
||
val = RTEST(recv) ? Qfalse : Qtrue;
|
method.h | ||
---|---|---|
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
|
||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
|
||
rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
|
||
rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
|
||
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id);
|
||
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
|
||
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
|
||
int rb_method_entry_arity(const rb_method_entry_t *me);
|
proc.c | ||
---|---|---|
struct METHOD {
|
||
VALUE recv;
|
||
VALUE rclass;
|
||
VALUE defined_class;
|
||
ID id;
|
||
rb_method_entry_t me;
|
||
};
|
||
... | ... | |
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_mark_method_entry(&data->me);
|
||
... | ... | |
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||
{
|
||
VALUE method;
|
||
VALUE rclass = klass;
|
||
VALUE rclass = klass, defined_class;
|
||
ID rid = id;
|
||
struct METHOD *data;
|
||
rb_method_entry_t *me, meb;
|
||
... | ... | |
rb_method_flag_t flag = NOEX_UNDEF;
|
||
again:
|
||
me = rb_method_entry(klass, id);
|
||
me = rb_method_entry(klass, id, &defined_class);
|
||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||
ID rmiss = rb_intern("respond_to_missing?");
|
||
VALUE sym = ID2SYM(id);
|
||
... | ... | |
}
|
||
}
|
||
if (def && def->type == VM_METHOD_TYPE_ZSUPER) {
|
||
klass = RCLASS_SUPER(me->klass);
|
||
klass = RCLASS_SUPER(defined_class);
|
||
id = def->original_id;
|
||
goto again;
|
||
}
|
||
klass = me->klass;
|
||
klass = defined_class;
|
||
while (rclass != klass &&
|
||
(FL_TEST(rclass, FL_SINGLETON) || TYPE(rclass) == T_ICLASS)) {
|
||
... | ... | |
data->recv = obj;
|
||
data->rclass = rclass;
|
||
data->defined_class = defined_class;
|
||
data->id = rid;
|
||
data->me = *me;
|
||
if (def) def->alias_count++;
|
||
... | ... | |
data->me = orig->me;
|
||
if (orig->me.def) orig->me.def->alias_count++;
|
||
data->rclass = orig->rclass;
|
||
data->defined_class = orig->defined_class;
|
||
OBJ_INFECT(method, obj);
|
||
return method;
|
||
... | ... | |
if ((state = EXEC_TAG()) == 0) {
|
||
rb_thread_t *th = GET_THREAD();
|
||
VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||
const rb_method_entry_t *me);
|
||
const rb_method_entry_t *me, VALUE defined_class);
|
||
PASS_PASSED_BLOCK_TH(th);
|
||
result = rb_vm_call(th, data->recv, data->id, argc, argv, &data->me);
|
||
result = rb_vm_call(th, data->recv, data->id, argc, argv, &data->me, data->defined_class);
|
||
}
|
||
POP_TAG();
|
||
if (safe >= 0)
|
||
... | ... | |
int
|
||
rb_mod_method_arity(VALUE mod, ID id)
|
||
{
|
||
rb_method_entry_t *me = rb_method_entry(mod, id);
|
||
rb_method_entry_t *me = rb_method_entry(mod, id, 0);
|
||
return rb_method_entry_arity(me);
|
||
}
|
||
vm.c | ||
---|---|---|
rb_vm_set_finish_env(rb_thread_t * th)
|
||
{
|
||
vm_push_frame(th, 0, VM_FRAME_MAGIC_FINISH,
|
||
Qnil, th->cfp->lfp[0], 0,
|
||
Qnil, Qnil, th->cfp->lfp[0], 0,
|
||
th->cfp->sp, 0, 1);
|
||
th->cfp->pc = (VALUE *)&finish_insn_seq[0];
|
||
return Qtrue;
|
||
... | ... | |
rb_vm_set_finish_env(th);
|
||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP,
|
||
th->top_self, 0, iseq->iseq_encoded,
|
||
th->top_self, rb_cObject, 0, iseq->iseq_encoded,
|
||
th->cfp->sp, 0, iseq->local_size);
|
||
CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
|
||
... | ... | |
/* for return */
|
||
rb_vm_set_finish_env(th);
|
||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self,
|
||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self, block->klass,
|
||
GC_GUARDED_PTR(block->dfp), iseq->iseq_encoded,
|
||
th->cfp->sp, block->lfp, iseq->local_size);
|
||
... | ... | |
GetProcPtr(procval, proc);
|
||
proc->blockprocval = blockprocval;
|
||
proc->block.self = block->self;
|
||
proc->block.klass = block->klass;
|
||
proc->block.lfp = block->lfp;
|
||
proc->block.dfp = block->dfp;
|
||
proc->block.iseq = block->iseq;
|
||
... | ... | |
type == VM_FRAME_MAGIC_LAMBDA);
|
||
ncfp = vm_push_frame(th, iseq, type,
|
||
self, GC_GUARDED_PTR(block->dfp),
|
||
self, th->passed_defined_class,
|
||
GC_GUARDED_PTR(block->dfp),
|
||
iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, block->lfp,
|
||
iseq->local_size - arg_size);
|
||
th->passed_defined_class = 0;
|
||
ncfp->me = th->passed_me;
|
||
th->passed_me = 0;
|
||
th->passed_block = blockptr;
|
||
... | ... | |
/* push block frame */
|
||
cfp->sp[0] = err;
|
||
vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK,
|
||
cfp->self, (VALUE)cfp->dfp, catch_iseq->iseq_encoded,
|
||
cfp->self, cfp->klass,
|
||
(VALUE)cfp->dfp, catch_iseq->iseq_encoded,
|
||
cfp->sp + 1 /* push value */, cfp->lfp, catch_iseq->local_size - 1);
|
||
state = 0;
|
||
... | ... | |
VALUE val;
|
||
vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP,
|
||
recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||
recv, CLASS_OF(recv), (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||
val = (*func)(arg);
|
||
... | ... | |
RUBY_MARK_UNLESS_NULL(th->root_fiber);
|
||
RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
|
||
RUBY_MARK_UNLESS_NULL(th->last_status);
|
||
RUBY_MARK_UNLESS_NULL(th->passed_defined_class);
|
||
RUBY_MARK_UNLESS_NULL(th->locking_mutex);
|
||
... | ... | |
th->cfp = (void *)(th->stack + th->stack_size);
|
||
vm_push_frame(th, 0, VM_FRAME_MAGIC_TOP, Qnil, 0, 0,
|
||
vm_push_frame(th, 0, VM_FRAME_MAGIC_TOP, Qnil, Qnil, 0, 0,
|
||
th->stack, 0, 1);
|
||
th->status = THREAD_RUNNABLE;
|
vm_core.h | ||
---|---|---|
rb_method_entry_t *method;
|
||
long index;
|
||
} ic_value;
|
||
union {
|
||
VALUE defined_class;
|
||
} ic_value2;
|
||
};
|
||
#if 1
|
||
... | ... | |
VALUE *bp; /* cfp[2] */
|
||
rb_iseq_t *iseq; /* cfp[3] */
|
||
VALUE flag; /* cfp[4] */
|
||
VALUE self; /* cfp[5] / block[0] */
|
||
VALUE *lfp; /* cfp[6] / block[1] */
|
||
VALUE *dfp; /* cfp[7] / block[2] */
|
||
rb_iseq_t *block_iseq; /* cfp[8] / block[3] */
|
||
VALUE proc; /* cfp[9] / block[4] */
|
||
const rb_method_entry_t *me;/* cfp[10] */
|
||
VALUE self; /* cfp[5] / block[0] */
|
||
VALUE klass; /* cfp[6] / block[1] */
|
||
VALUE *lfp; /* cfp[7] / block[2] */
|
||
VALUE *dfp; /* cfp[8] / block[3] */
|
||
rb_iseq_t *block_iseq; /* cfp[9] / block[4] */
|
||
VALUE proc; /* cfp[10] / block[5] */
|
||
const rb_method_entry_t *me;/* cfp[11] */
|
||
} rb_control_frame_t;
|
||
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 *lfp; /* share with method frame if it's only block */
|
||
VALUE *dfp; /* share with method frame if it's only block */
|
||
rb_iseq_t *iseq;
|
||
... | ... | |
/* for bmethod */
|
||
const rb_method_entry_t *passed_me;
|
||
VALUE passed_defined_class;
|
||
/* for load(true) */
|
||
VALUE top_self;
|
vm_eval.c | ||
---|---|---|
static inline VALUE
|
||
vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||
const rb_method_entry_t *me)
|
||
const rb_method_entry_t *me, VALUE defined_class)
|
||
{
|
||
const rb_method_definition_t *def = me->def;
|
||
VALUE val;
|
||
VALUE klass = me->klass;
|
||
VALUE klass = defined_class;
|
||
const rb_block_t *blockptr = 0;
|
||
if (!def) return Qnil;
|
||
... | ... | |
*reg_cfp->sp++ = argv[i];
|
||
}
|
||
vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me);
|
||
vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me, klass);
|
||
val = vm_exec(th);
|
||
break;
|
||
}
|
||
... | ... | |
rb_control_frame_t *reg_cfp = th->cfp;
|
||
rb_control_frame_t *cfp =
|
||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
||
recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||
recv, klass, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||
cfp->me = me;
|
||
val = call_cfunc(def->body.cfunc.func, recv, def->body.cfunc.argc, argc, argv);
|
||
... | ... | |
break;
|
||
}
|
||
case VM_METHOD_TYPE_BMETHOD: {
|
||
val = vm_call_bmethod(th, recv, argc, argv, blockptr, me);
|
||
val = vm_call_bmethod(th, recv, argc, argv, blockptr, me, klass);
|
||
break;
|
||
}
|
||
case VM_METHOD_TYPE_ZSUPER: {
|
||
klass = RCLASS_SUPER(klass);
|
||
if (!klass || !(me = rb_method_entry(klass, id))) {
|
||
if (!klass || !(me = rb_method_entry(klass, id, &klass))) {
|
||
return method_missing(recv, id, argc, argv, NOEX_SUPER);
|
||
}
|
||
RUBY_VM_CHECK_INTS();
|
||
... | ... | |
VALUE
|
||
rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||
const rb_method_entry_t *me)
|
||
const rb_method_entry_t *me, VALUE defined_class)
|
||
{
|
||
return vm_call0(th, recv, id, argc, argv, me);
|
||
return vm_call0(th, recv, id, argc, argv, me, defined_class);
|
||
}
|
||
static inline VALUE
|
||
... | ... | |
rb_method_entry_t *me;
|
||
rb_control_frame_t *cfp = th->cfp;
|
||
if (!cfp->iseq) {
|
||
klass = cfp->me->klass;
|
||
klass = RCLASS_SUPER(klass);
|
||
if (!cfp->iseq && !NIL_P(cfp->klass)) {
|
||
klass = RCLASS_SUPER(cfp->klass);
|
||
if (klass == 0) {
|
||
klass = vm_search_normal_superclass(cfp->me->klass, recv);
|
||
... | ... | |
rb_bug("vm_call_super: should not be reached");
|
||
}
|
||
me = rb_method_entry(klass, id);
|
||
me = rb_method_entry(klass, id, &klass);
|
||
if (!me) {
|
||
return method_missing(recv, id, argc, argv, NOEX_SUPER);
|
||
}
|
||
return vm_call0(th, recv, id, argc, argv, me);
|
||
return vm_call0(th, recv, id, argc, argv, me, klass);
|
||
}
|
||
VALUE
|
||
... | ... | |
}
|
||
}
|
||
static inline rb_method_entry_t *rb_search_method_entry(VALUE recv, ID mid);
|
||
static inline rb_method_entry_t *rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr);
|
||
static inline int rb_method_call_status(rb_thread_t *th, rb_method_entry_t *me, call_type scope, VALUE self);
|
||
#define NOEX_OK NOEX_NOSUPER
|
||
... | ... | |
rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
|
||
call_type scope, VALUE self)
|
||
{
|
||
rb_method_entry_t *me = rb_search_method_entry(recv, mid);
|
||
VALUE defined_class;
|
||
rb_method_entry_t *me = rb_search_method_entry(recv, mid, &defined_class);
|
||
rb_thread_t *th = GET_THREAD();
|
||
int call_status = rb_method_call_status(th, me, scope, self);
|
||
... | ... | |
return method_missing(recv, mid, argc, argv, call_status);
|
||
}
|
||
stack_check();
|
||
return vm_call0(th, recv, mid, argc, argv, me);
|
||
return vm_call0(th, recv, mid, argc, argv, me, defined_class);
|
||
}
|
||
struct rescue_funcall_args {
|
||
... | ... | |
static VALUE
|
||
check_funcall(VALUE recv, ID mid, int argc, VALUE *argv)
|
||
{
|
||
rb_method_entry_t *me = rb_search_method_entry(recv, mid);
|
||
VALUE defined_class;
|
||
rb_method_entry_t *me = rb_search_method_entry(recv, mid, &defined_class);
|
||
rb_thread_t *th = GET_THREAD();
|
||
int call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef);
|
||
... | ... | |
}
|
||
}
|
||
stack_check();
|
||
return vm_call0(th, recv, mid, argc, argv, me);
|
||
return vm_call0(th, recv, mid, argc, argv, me, defined_class);
|
||
}
|
||
VALUE
|
||
... | ... | |
}
|
||
static inline rb_method_entry_t *
|
||
rb_search_method_entry(VALUE recv, ID mid)
|
||
rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
|
||
{
|
||
VALUE klass = CLASS_OF(recv);
|
||
... | ... | |
rb_id2name(mid), type, (void *)recv, flags, klass);
|
||
}
|
||
}
|
||
return rb_method_entry(klass, mid);
|
||
return rb_method_entry(klass, mid, defined_class_ptr);
|
||
}
|
||
static inline int
|
vm_insnhelper.c | ||
---|---|---|
static inline rb_control_frame_t *
|
||
vm_push_frame(rb_thread_t * th, const rb_iseq_t * iseq,
|
||
VALUE type, VALUE self, VALUE specval,
|
||
VALUE type, VALUE self, VALUE klass, VALUE specval,
|
||
const VALUE *pc, VALUE *sp, VALUE *lfp,
|
||
int local_size)
|
||
{
|
||
... | ... | |
cfp->block_iseq = 0;
|
||
cfp->proc = 0;
|
||
cfp->me = 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;
|
||
}
|
||
}
|
||
#define COLLECT_PROFILE 0
|
||
#if COLLECT_PROFILE
|
||
... | ... | |
static inline VALUE
|
||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
||
int num, VALUE recv, const rb_block_t *blockptr,
|
||
const rb_method_entry_t *me)
|
||
const rb_method_entry_t *me, VALUE defined_class)
|
||
{
|
||
VALUE val = 0;
|
||
const rb_method_definition_t *def = me->def;
|
||
... | ... | |
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
|
||
cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
||
recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
|
||
recv, defined_class, (VALUE) blockptr,
|
||
0, reg_cfp->sp, 0, 1);
|
||
cfp->me = me;
|
||
reg_cfp->sp -= num + 1;
|
||
... | ... | |
static inline VALUE
|
||
vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv,
|
||
const rb_block_t *blockptr, const rb_method_entry_t *me)
|
||
const rb_block_t *blockptr, const rb_method_entry_t *me,
|
||
VALUE defined_class)
|
||
{
|
||
rb_proc_t *proc;
|
||
VALUE val;
|
||
/* control block frame */
|
||
th->passed_me = me;
|
||
th->passed_defined_class = defined_class;
|
||
GetProcPtr(me->def->body.proc, proc);
|
||
val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
|
||
... | ... | |
static inline void
|
||
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||
VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag,
|
||
const rb_method_entry_t *me)
|
||
const rb_method_entry_t *me, VALUE defined_class)
|
||
{
|
||
int opt_pc, i;
|
||
VALUE *sp, *rsp = cfp->sp - argc;
|
||
... | ... | |
}
|
||
vm_push_frame(th, iseq,
|
||
VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
|
||
VM_FRAME_MAGIC_METHOD, recv, defined_class,
|
||
(VALUE) blockptr,
|
||
iseq->iseq_encoded + opt_pc, sp, 0, 0);
|
||
cfp->sp = rsp - 1 /* recv */;
|
||
... | ... | |
}
|
||
vm_push_frame(th, iseq,
|
||
VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
|
||
VM_FRAME_MAGIC_METHOD, recv, defined_class,
|
||
(VALUE) blockptr,
|
||
iseq->iseq_encoded + opt_pc, sp, 0, 0);
|
||
}
|
||
}
|
||
... | ... | |
static inline VALUE
|
||
vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||
int num, const rb_block_t *blockptr, VALUE flag,
|
||
ID id, const rb_method_entry_t *me, VALUE recv)
|
||
ID id, const rb_method_entry_t *me,
|
||
VALUE recv, VALUE defined_class)
|
||
{
|
||
VALUE val;
|
||
... | ... | |
normal_method_dispatch:
|
||
switch (me->def->type) {
|
||
case VM_METHOD_TYPE_ISEQ:{
|
||
vm_setup_method(th, cfp, recv, num, blockptr, flag, me);
|
||
vm_setup_method(th, cfp, recv, num, blockptr, flag, me,
|
||
defined_class);
|
||
return Qundef;
|
||
}
|
||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||
case VM_METHOD_TYPE_CFUNC:{
|
||
val = vm_call_cfunc(th, cfp, num, recv, blockptr, me);
|
||
val = vm_call_cfunc(th, cfp, num, recv, blockptr, me,
|
||
defined_class);
|
||
break;
|
||
}
|
||
case VM_METHOD_TYPE_ATTRSET:{
|
||
... | ... | |
VALUE *argv = ALLOCA_N(VALUE, num);
|
||
MEMCPY(argv, cfp->sp - num, VALUE, num);
|
||
cfp->sp += - num - 1;
|
||
val = vm_call_bmethod(th, recv, num, argv, blockptr, me);
|
||
val = vm_call_bmethod(th, recv, num, argv, blockptr, me,
|
||
defined_class);
|
||
break;
|
||
}
|
||
case VM_METHOD_TYPE_ZSUPER:{
|
||
VALUE klass = RCLASS_SUPER(me->klass);
|
||
me = rb_method_entry(klass, id);
|
||
me = rb_method_entry(klass, id, &defined_class);
|
||
if (me != 0) {
|
||
goto normal_method_dispatch;
|
||
... | ... | |
if (i > 0) {
|
||
MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
|
||
}
|
||
me = rb_method_entry(CLASS_OF(recv), id);
|
||
me = rb_method_entry(CLASS_OF(recv), id, &defined_class);
|
||
num -= 1;
|
||
DEC_SP(1);
|
||
flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT;
|
||
... | ... | |
val = vm_method_missing(th, id, recv, num, blockptr, stat);
|
||
}
|
||
else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) {
|
||
VALUE defined_class = me->klass;
|
||
if (TYPE(defined_class) == T_ICLASS) {
|
||
defined_class = RBASIC(defined_class)->klass;
|
||
}
|
||
... | ... | |
}
|
||
vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC,
|
||
self, (VALUE)block->dfp,
|
||
self, 0, (VALUE)block->dfp,
|
||
0, th->cfp->sp, block->lfp, 1);
|
||
if (blockargptr) {
|
||
... | ... | |
block_proc_is_lambda(block->proc));
|
||
vm_push_frame(th, iseq,
|
||
VM_FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp,
|
||
VM_FRAME_MAGIC_BLOCK, block->self, block->klass,
|
||
(VALUE) block->dfp,
|
||
iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp,
|
||
iseq->local_size - arg_size);
|
||
... | ... | |
}
|
||
static inline const rb_method_entry_t *
|
||
vm_method_search(VALUE id, VALUE klass, IC ic)
|
||
vm_method_search(VALUE id, VALUE klass, IC ic, VALUE *defined_class_ptr)
|
||
{
|
||
rb_method_entry_t *me;
|
||
#if OPT_INLINE_METHOD_CACHE
|
||
if (LIKELY(klass == ic->ic_class) &&
|
||
LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
|
||
me = ic->ic_value.method;
|
||
if (defined_class_ptr)
|
||
*defined_class_ptr = ic->ic_value2.defined_class;
|
||
}
|
||
else {
|
||
me = rb_method_entry(klass, id);
|
||
VALUE defined_class;
|
||
me = rb_method_entry(klass, id, &defined_class);
|
||
if (defined_class_ptr)
|
||
*defined_class_ptr = defined_class;
|
||
ic->ic_class = klass;
|
||
ic->ic_value.method = me;
|
||
ic->ic_value2.defined_class = defined_class;
|
||
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
||
}
|
||
#else
|
||
me = rb_method_entry(klass, id);
|
||
me = rb_method_entry(klass, id, defined_class_ptr);
|
||
#endif
|
||
return me;
|
||
}
|
||
... | ... | |
static inline VALUE
|
||
vm_search_normal_superclass(VALUE klass, VALUE recv)
|
||
{
|
||
if (BUILTIN_TYPE(klass) == T_CLASS) {
|
||
if (BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_ICLASS) {
|
||
return RCLASS_SUPER(klass);
|
||
}
|
||
else if (BUILTIN_TYPE(klass) == T_MODULE) {
|
||
... | ... | |
}
|
||
id = lcfp->me->def->original_id;
|
||
klass = vm_search_normal_superclass(lcfp->me->klass, recv);
|
||
klass = vm_search_normal_superclass(lcfp->klass, recv);
|
||
}
|
||
else {
|
||
klass = vm_search_normal_superclass(iseq->klass, recv);
|
||
klass = vm_search_normal_superclass(reg_cfp->klass, recv);
|
||
}
|
||
*idp = id;
|
||
... | ... | |
}
|
||
{
|
||
const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic);
|
||
const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic, 0);
|
||
extern VALUE rb_obj_equal(VALUE obj1, VALUE obj2);
|
||
if (check_cfunc(me, rb_obj_equal)) {
|
vm_insnhelper.h | ||
---|---|---|
c1->nd_next = __tmp_c2->nd_next; \
|
||
} while (0)
|
||
#define CALL_METHOD(num, blockptr, flag, id, me, recv) do { \
|
||
VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, me, recv); \
|
||
#define CALL_METHOD(num, blockptr, flag, id, me, recv, defined_class) do { \
|
||
VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, me, recv, defined_class); \
|
||
if (v == Qundef) { \
|
||
RESTORE_REGS(); \
|
||
NEXT_INSN(); \
|
||
... | ... | |
#if USE_IC_FOR_SPECIALIZED_METHOD
|
||
#define CALL_SIMPLE_METHOD(num, id, recv) do { \
|
||
VALUE klass = CLASS_OF(recv); \
|
||
CALL_METHOD(num, 0, 0, id, vm_method_search(id, klass, ic), recv); \
|
||
VALUE klass = CLASS_OF(recv), defined_class; \
|
||
const rb_method_entry_t *me = vm_method_search(id, klass, ic, &defined_class); \
|
||
CALL_METHOD(num, 0, 0, id, me, recv, defined_class); \
|
||
} while (0)
|
||
#else
|
vm_method.c | ||
---|---|---|
ID mid; /* method's id */
|
||
VALUE klass; /* receiver's class */
|
||
rb_method_entry_t *me;
|
||
VALUE defined_class;
|
||
};
|
||
static struct cache_entry cache[CACHE_SIZE];
|
||
... | ... | |
{
|
||
rb_method_entry_t *me;
|
||
Check_Type(klass, T_CLASS);
|
||
me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR);
|
||
me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR, 0);
|
||
if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC) {
|
||
return (rb_alloc_func_t)me->def->body.cfunc.func;
|
||
... | ... | |
}
|
||
static rb_method_entry_t*
|
||
search_method(VALUE klass, ID id)
|
||
search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
|
||
{
|
||
st_data_t body;
|
||
if (!klass) {
|
||
... | ... | |
}
|
||
}
|
||
if (defined_class_ptr)
|
||
*defined_class_ptr = klass;
|
||
return (rb_method_entry_t *)body;
|
||
}
|
||
... | ... | |
* rb_method_entry() simply.
|
||
*/
|
||
rb_method_entry_t *
|
||
rb_method_entry_get_without_cache(VALUE klass, ID id)
|
||
rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *defined_class_ptr)
|
||
{
|
||
rb_method_entry_t *me = search_method(klass, id);
|
||
VALUE defined_class;
|
||
rb_method_entry_t *me;
|
||
me = search_method(klass, id, &defined_class);
|
||
if (ruby_running) {
|
||
struct cache_entry *ent;
|
||
ent = cache + EXPR1(klass, id);
|
||
ent->klass = klass;
|
||
ent->defined_class = defined_class;
|
||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||
ent->mid = id;
|
||
... | ... | |
}
|
||
}
|
||
if (defined_class_ptr)
|
||
*defined_class_ptr = defined_class;
|
||
return me;
|
||
}
|
||
rb_method_entry_t *
|
||
rb_method_entry(VALUE klass, ID id)
|
||
rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
|
||
{
|
||
struct cache_entry *ent;
|
||
ent = cache + EXPR1(klass, id);
|
||
if (ent->mid == id && ent->klass == klass) {
|
||
if (defined_class_ptr)
|
||
*defined_class_ptr = ent->defined_class;
|
||
return ent->me;
|
||
}
|
||
return rb_method_entry_get_without_cache(klass, id);
|
||
return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
|
||
}
|
||
static void
|
||
... | ... | |
rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
|
||
{
|
||
rb_method_entry_t *me;
|
||
VALUE defined_class;
|
||
if (klass == rb_cObject) {
|
||
rb_secure(4);
|
||
}
|
||
me = search_method(klass, name);
|
||
me = search_method(klass, name, &defined_class);
|
||
if (!me && TYPE(klass) == T_MODULE) {
|
||
me = search_method(rb_cObject, name);
|
||
me = search_method(rb_cObject, name, &defined_class);
|
||
}
|
||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||
... | ... | |
if (me->flag != noex) {
|
||
rb_vm_check_redefinition_opt_method(me);
|
||
if (klass == me->klass) {
|
||
if (klass == defined_class) {
|
||
me->flag = noex;
|
||
}
|
||
else {
|
||
... | ... | |
int
|
||
rb_method_boundp(VALUE klass, ID id, int ex)
|
||
{
|
||
rb_method_entry_t *me = rb_method_entry(klass, id);
|
||
rb_method_entry_t *me = rb_method_entry(klass, id, 0);
|
||
if (me != 0) {
|
||
if ((ex & ~NOEX_RESPONDS) && (me->flag & NOEX_PRIVATE)) {
|
||
... | ... | |
rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
|
||
}
|
||
me = search_method(klass, id);
|
||
me = search_method(klass, id, 0);
|
||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||
const char *s0 = " class";
|
||
... | ... | |
check_definition(VALUE mod, ID mid, rb_method_flag_t noex)
|
||
{
|
||
const rb_method_entry_t *me;
|
||
me = rb_method_entry(mod, mid);
|
||
me = rb_method_entry(mod, mid, 0);
|
||
if (me) {
|
||
if (VISI_CHECK(me->flag, noex))
|
||
return Qtrue;
|
||
... | ... | |
}
|
||
again:
|
||
orig_me = search_method(klass, def);
|
||
orig_me = search_method(klass, def, 0);
|
||
if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
|
||
if ((TYPE(klass) != T_MODULE) ||
|
||
(orig_me = search_method(rb_cObject, def), UNDEFINED_METHOD_ENTRY_P(orig_me))) {
|
||
(orig_me = search_method(rb_cObject, def, 0),
|
||
UNDEFINED_METHOD_ENTRY_P(orig_me))) {
|
||
rb_print_undef(klass, def, 0);
|
||
}
|
||
}
|
||
... | ... | |
id = rb_to_id(argv[i]);
|
||
for (;;) {
|
||
me = search_method(m, id);
|
||
me = search_method(m, id, 0);
|
||
if (me == 0) {
|
||
me = search_method(rb_cObject, id);
|
||
me = search_method(rb_cObject, id, 0);
|
||
}
|
||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||
rb_print_undef(module, id, 0);
|
||
... | ... | |
int
|
||
rb_method_basic_definition_p(VALUE klass, ID id)
|
||
{
|
||
const rb_method_entry_t *me = rb_method_entry(klass, id);
|
||
const rb_method_entry_t *me = rb_method_entry(klass, id, 0);
|
||
if (me && (me->flag & NOEX_BASIC))
|
||
return 1;
|
||
return 0;
|