mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* class.c, insns.def, method.h, proc.c, vm.c, vm_core.h, vm_eval.c,
vm_insnhelper.c, vm_insnhelper.h, vm_method.c: add klass to rb_control_frame_t to implement super correctly. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36595 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
14bf66f252
commit
319088e9c7
11 changed files with 175 additions and 102 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
Thu Aug 2 20:08:02 2012 Shugo Maeda <shugo@ruby-lang.org>
|
||||||
|
|
||||||
|
* class.c, insns.def, method.h, proc.c, vm.c, vm_core.h, vm_eval.c,
|
||||||
|
vm_insnhelper.c, vm_insnhelper.h, vm_method.c: add klass to
|
||||||
|
rb_control_frame_t to implement super correctly.
|
||||||
|
|
||||||
Thu Aug 2 13:23:08 2012 NARUSE, Yui <naruse@ruby-lang.org>
|
Thu Aug 2 13:23:08 2012 NARUSE, Yui <naruse@ruby-lang.org>
|
||||||
|
|
||||||
* configure.in (AC_PROG_CC): AC_PROG_CC tries clang at first on
|
* configure.in (AC_PROG_CC): AC_PROG_CC tries clang at first on
|
||||||
|
|
2
class.c
2
class.c
|
@ -1444,7 +1444,7 @@ rb_define_attr(VALUE klass, const char *name, int read, int write)
|
||||||
int
|
int
|
||||||
rb_obj_basic_to_s_p(VALUE obj)
|
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 &&
|
if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC &&
|
||||||
me->def->body.cfunc.func == rb_any_to_s)
|
me->def->body.cfunc.func == rb_any_to_s)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
32
insns.def
32
insns.def
|
@ -798,7 +798,7 @@ defined
|
||||||
break;
|
break;
|
||||||
case DEFINED_METHOD:{
|
case DEFINED_METHOD:{
|
||||||
VALUE klass = CLASS_OF(v);
|
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) {
|
||||||
if (!(me->flag & NOEX_PRIVATE)) {
|
if (!(me->flag & NOEX_PRIVATE)) {
|
||||||
|
@ -967,7 +967,7 @@ defineclass
|
||||||
|
|
||||||
/* enter scope */
|
/* enter scope */
|
||||||
vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS,
|
vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS,
|
||||||
klass, VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
|
klass, 0, VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
|
||||||
class_iseq->iseq_encoded, GET_SP(),
|
class_iseq->iseq_encoded, GET_SP(),
|
||||||
class_iseq->local_size, 0);
|
class_iseq->local_size, 0);
|
||||||
RESTORE_REGS();
|
RESTORE_REGS();
|
||||||
|
@ -999,7 +999,7 @@ send
|
||||||
(VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
|
(VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
|
||||||
{
|
{
|
||||||
const rb_method_entry_t *me;
|
const rb_method_entry_t *me;
|
||||||
VALUE recv, klass;
|
VALUE recv, klass, defined_class;
|
||||||
rb_block_t *blockptr = 0;
|
rb_block_t *blockptr = 0;
|
||||||
VALUE flag = op_flag;
|
VALUE flag = op_flag;
|
||||||
int num = caller_setup_args(th, GET_CFP(), flag, (int)op_argc,
|
int num = caller_setup_args(th, GET_CFP(), flag, (int)op_argc,
|
||||||
|
@ -1009,8 +1009,8 @@ send
|
||||||
/* get receiver */
|
/* get receiver */
|
||||||
recv = TOPN(num);
|
recv = TOPN(num);
|
||||||
klass = CLASS_OF(recv);
|
klass = CLASS_OF(recv);
|
||||||
me = vm_method_search(id, klass, ic);
|
me = vm_method_search(id, klass, ic, &defined_class);
|
||||||
CALL_METHOD(num, blockptr, flag, id, me, recv);
|
CALL_METHOD(num, blockptr, flag, id, me, recv, defined_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1033,20 +1033,26 @@ invokesuper
|
||||||
VALUE recv, klass;
|
VALUE recv, klass;
|
||||||
ID id;
|
ID id;
|
||||||
const rb_method_entry_t *me;
|
const rb_method_entry_t *me;
|
||||||
|
rb_iseq_t *ip;
|
||||||
|
|
||||||
flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
||||||
|
|
||||||
recv = GET_SELF();
|
recv = GET_SELF();
|
||||||
vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
|
vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
|
||||||
|
|
||||||
/* temporary measure for [Bug #2402] [Bug #2502] [Bug #3136] */
|
ip = GET_ISEQ();
|
||||||
if (!rb_obj_is_kind_of(recv, klass)) {
|
while (ip && !ip->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 = 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, klass);
|
||||||
|
|
||||||
CALL_METHOD(num, blockptr, flag, id, me, recv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1652,7 +1658,7 @@ opt_neq
|
||||||
(VALUE val)
|
(VALUE val)
|
||||||
{
|
{
|
||||||
extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
|
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;
|
val = Qundef;
|
||||||
|
|
||||||
if (check_cfunc(me, rb_obj_not_equal)) {
|
if (check_cfunc(me, rb_obj_not_equal)) {
|
||||||
|
@ -2056,7 +2062,7 @@ opt_not
|
||||||
(VALUE val)
|
(VALUE val)
|
||||||
{
|
{
|
||||||
extern VALUE rb_obj_not(VALUE obj);
|
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)) {
|
if (check_cfunc(me, rb_obj_not)) {
|
||||||
val = RTEST(recv) ? Qfalse : Qtrue;
|
val = RTEST(recv) ? Qfalse : Qtrue;
|
||||||
|
|
4
method.h
4
method.h
|
@ -89,9 +89,9 @@ struct unlinked_method_entry_list_entry {
|
||||||
|
|
||||||
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
|
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_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);
|
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);
|
int rb_method_entry_arity(const rb_method_entry_t *me);
|
||||||
|
|
17
proc.c
17
proc.c
|
@ -17,6 +17,7 @@
|
||||||
struct METHOD {
|
struct METHOD {
|
||||||
VALUE recv;
|
VALUE recv;
|
||||||
VALUE rclass;
|
VALUE rclass;
|
||||||
|
VALUE defined_class;
|
||||||
ID id;
|
ID id;
|
||||||
rb_method_entry_t *me;
|
rb_method_entry_t *me;
|
||||||
struct unlinked_method_entry_list_entry *ume;
|
struct unlinked_method_entry_list_entry *ume;
|
||||||
|
@ -889,6 +890,7 @@ static void
|
||||||
bm_mark(void *ptr)
|
bm_mark(void *ptr)
|
||||||
{
|
{
|
||||||
struct METHOD *data = ptr;
|
struct METHOD *data = ptr;
|
||||||
|
rb_gc_mark(data->defined_class);
|
||||||
rb_gc_mark(data->rclass);
|
rb_gc_mark(data->rclass);
|
||||||
rb_gc_mark(data->recv);
|
rb_gc_mark(data->recv);
|
||||||
if (data->me) rb_mark_method_entry(data->me);
|
if (data->me) rb_mark_method_entry(data->me);
|
||||||
|
@ -935,7 +937,7 @@ static VALUE
|
||||||
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||||||
{
|
{
|
||||||
VALUE method;
|
VALUE method;
|
||||||
VALUE rclass = klass;
|
VALUE rclass = klass, defined_class;
|
||||||
ID rid = id;
|
ID rid = id;
|
||||||
struct METHOD *data;
|
struct METHOD *data;
|
||||||
rb_method_entry_t *me, meb;
|
rb_method_entry_t *me, meb;
|
||||||
|
@ -943,7 +945,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||||||
rb_method_flag_t flag = NOEX_UNDEF;
|
rb_method_flag_t flag = NOEX_UNDEF;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
me = rb_method_entry(klass, id);
|
me = rb_method_entry(klass, id, &defined_class);
|
||||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||||
ID rmiss = rb_intern("respond_to_missing?");
|
ID rmiss = rb_intern("respond_to_missing?");
|
||||||
VALUE sym = ID2SYM(id);
|
VALUE sym = ID2SYM(id);
|
||||||
|
@ -985,12 +987,12 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (def && def->type == VM_METHOD_TYPE_ZSUPER) {
|
if (def && def->type == VM_METHOD_TYPE_ZSUPER) {
|
||||||
klass = RCLASS_SUPER(me->klass);
|
klass = RCLASS_SUPER(defined_class);
|
||||||
id = def->original_id;
|
id = def->original_id;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
klass = me->klass;
|
klass = defined_class;
|
||||||
|
|
||||||
while (rclass != klass &&
|
while (rclass != klass &&
|
||||||
(FL_TEST(rclass, FL_SINGLETON) || RB_TYPE_P(rclass, T_ICLASS))) {
|
(FL_TEST(rclass, FL_SINGLETON) || RB_TYPE_P(rclass, T_ICLASS))) {
|
||||||
|
@ -1006,6 +1008,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||||||
|
|
||||||
data->recv = obj;
|
data->recv = obj;
|
||||||
data->rclass = rclass;
|
data->rclass = rclass;
|
||||||
|
data->defined_class = defined_class;
|
||||||
data->id = rid;
|
data->id = rid;
|
||||||
data->me = ALLOC(rb_method_entry_t);
|
data->me = ALLOC(rb_method_entry_t);
|
||||||
*data->me = *me;
|
*data->me = *me;
|
||||||
|
@ -1119,6 +1122,7 @@ method_unbind(VALUE obj)
|
||||||
*data->me = *orig->me;
|
*data->me = *orig->me;
|
||||||
if (orig->me->def) orig->me->def->alias_count++;
|
if (orig->me->def) orig->me->def->alias_count++;
|
||||||
data->rclass = orig->rclass;
|
data->rclass = orig->rclass;
|
||||||
|
data->defined_class = orig->defined_class;
|
||||||
data->ume = ALLOC(struct unlinked_method_entry_list_entry);
|
data->ume = ALLOC(struct unlinked_method_entry_list_entry);
|
||||||
OBJ_INFECT(method, obj);
|
OBJ_INFECT(method, obj);
|
||||||
|
|
||||||
|
@ -1394,6 +1398,7 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
|
||||||
proc->block.iseq->klass = mod;
|
proc->block.iseq->klass = mod;
|
||||||
proc->is_lambda = TRUE;
|
proc->is_lambda = TRUE;
|
||||||
proc->is_from_method = TRUE;
|
proc->is_from_method = TRUE;
|
||||||
|
proc->block.klass = mod;
|
||||||
}
|
}
|
||||||
rb_add_method(mod, id, VM_METHOD_TYPE_BMETHOD, (void *)body, noex);
|
rb_add_method(mod, id, VM_METHOD_TYPE_BMETHOD, (void *)body, noex);
|
||||||
}
|
}
|
||||||
|
@ -1498,7 +1503,7 @@ rb_method_call(int argc, VALUE *argv, VALUE method)
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
PASS_PASSED_BLOCK_TH(th);
|
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();
|
POP_TAG();
|
||||||
if (safe >= 0)
|
if (safe >= 0)
|
||||||
|
@ -1727,7 +1732,7 @@ method_arity(VALUE method)
|
||||||
int
|
int
|
||||||
rb_mod_method_arity(VALUE mod, ID id)
|
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);
|
return rb_method_entry_arity(me);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
25
vm.c
25
vm.c
|
@ -136,8 +136,8 @@ vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
|
||||||
/* for return */
|
/* for return */
|
||||||
CHECK_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max);
|
CHECK_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max);
|
||||||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
|
vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
|
||||||
th->top_self, VM_ENVVAL_BLOCK_PTR(0), iseq->iseq_encoded,
|
th->top_self, rb_cObject, VM_ENVVAL_BLOCK_PTR(0),
|
||||||
th->cfp->sp, iseq->local_size, 0);
|
iseq->iseq_encoded, th->cfp->sp, iseq->local_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -147,7 +147,8 @@ vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref, rb_block_t
|
||||||
GetISeqPtr(iseqval, iseq);
|
GetISeqPtr(iseqval, iseq);
|
||||||
|
|
||||||
CHECK_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max);
|
CHECK_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max);
|
||||||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH, base_block->self,
|
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), iseq->iseq_encoded,
|
VM_ENVVAL_PREV_EP_PTR(base_block->ep), iseq->iseq_encoded,
|
||||||
th->cfp->sp, iseq->local_size, 0);
|
th->cfp->sp, iseq->local_size, 0);
|
||||||
|
|
||||||
|
@ -554,6 +555,7 @@ rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)
|
||||||
GetProcPtr(procval, proc);
|
GetProcPtr(procval, proc);
|
||||||
proc->blockprocval = blockprocval;
|
proc->blockprocval = blockprocval;
|
||||||
proc->block.self = block->self;
|
proc->block.self = block->self;
|
||||||
|
proc->block.klass = block->klass;
|
||||||
proc->block.ep = block->ep;
|
proc->block.ep = block->ep;
|
||||||
proc->block.iseq = block->iseq;
|
proc->block.iseq = block->iseq;
|
||||||
proc->block.proc = procval;
|
proc->block.proc = procval;
|
||||||
|
@ -596,8 +598,10 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
|
||||||
type == VM_FRAME_MAGIC_LAMBDA);
|
type == VM_FRAME_MAGIC_LAMBDA);
|
||||||
|
|
||||||
vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH,
|
vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH,
|
||||||
self, VM_ENVVAL_PREV_EP_PTR(block->ep),
|
self, block->klass, /* th->passed_defined_class, */
|
||||||
iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, iseq->local_size - arg_size,
|
VM_ENVVAL_PREV_EP_PTR(block->ep),
|
||||||
|
iseq->iseq_encoded + opt_pc,
|
||||||
|
cfp->sp + arg_size, iseq->local_size - arg_size,
|
||||||
th->passed_me);
|
th->passed_me);
|
||||||
th->passed_me = 0;
|
th->passed_me = 0;
|
||||||
th->passed_block = blockptr;
|
th->passed_block = blockptr;
|
||||||
|
@ -1302,8 +1306,11 @@ vm_exec(rb_thread_t *th)
|
||||||
/* push block frame */
|
/* push block frame */
|
||||||
cfp->sp[0] = err;
|
cfp->sp[0] = err;
|
||||||
vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK,
|
vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK,
|
||||||
cfp->self, VM_ENVVAL_PREV_EP_PTR(cfp->ep), catch_iseq->iseq_encoded,
|
cfp->self, cfp->klass,
|
||||||
cfp->sp + 1 /* push value */, catch_iseq->local_size - 1,
|
VM_ENVVAL_PREV_EP_PTR(cfp->ep),
|
||||||
|
catch_iseq->iseq_encoded,
|
||||||
|
cfp->sp + 1 /* push value */,
|
||||||
|
catch_iseq->local_size - 1,
|
||||||
cfp->me);
|
cfp->me);
|
||||||
|
|
||||||
state = 0;
|
state = 0;
|
||||||
|
@ -1438,7 +1445,7 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
|
||||||
VALUE val;
|
VALUE val;
|
||||||
|
|
||||||
vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
|
vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
|
||||||
recv, VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, 0);
|
recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, 0);
|
||||||
|
|
||||||
val = (*func)(arg);
|
val = (*func)(arg);
|
||||||
|
|
||||||
|
@ -1783,7 +1790,7 @@ th_init(rb_thread_t *th, VALUE self)
|
||||||
th->cfp = (void *)(th->stack + th->stack_size);
|
th->cfp = (void *)(th->stack + th->stack_size);
|
||||||
|
|
||||||
vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
|
vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
|
||||||
Qnil /* dummy self */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1, 0);
|
Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1, 0);
|
||||||
|
|
||||||
th->status = THREAD_RUNNABLE;
|
th->status = THREAD_RUNNABLE;
|
||||||
th->errinfo = Qnil;
|
th->errinfo = Qnil;
|
||||||
|
|
16
vm_core.h
16
vm_core.h
|
@ -137,6 +137,9 @@ struct iseq_inline_cache_entry {
|
||||||
rb_method_entry_t *method;
|
rb_method_entry_t *method;
|
||||||
long index;
|
long index;
|
||||||
} ic_value;
|
} ic_value;
|
||||||
|
union {
|
||||||
|
VALUE defined_class;
|
||||||
|
} ic_value2;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
@ -349,14 +352,16 @@ typedef struct {
|
||||||
rb_iseq_t *iseq; /* cfp[3] */
|
rb_iseq_t *iseq; /* cfp[3] */
|
||||||
VALUE flag; /* cfp[4] */
|
VALUE flag; /* cfp[4] */
|
||||||
VALUE self; /* cfp[5] / block[0] */
|
VALUE self; /* cfp[5] / block[0] */
|
||||||
VALUE *ep; /* cfp[6] / block[1] */
|
VALUE klass; /* cfp[6] / block[1] */
|
||||||
rb_iseq_t *block_iseq; /* cfp[7] / block[2] */
|
VALUE *ep; /* cfp[7] / block[2] */
|
||||||
VALUE proc; /* cfp[8] / block[3] */
|
rb_iseq_t *block_iseq; /* cfp[8] / block[3] */
|
||||||
const rb_method_entry_t *me;/* cfp[9] */
|
VALUE proc; /* cfp[9] / block[4] */
|
||||||
|
const rb_method_entry_t *me;/* cfp[10] */
|
||||||
} rb_control_frame_t;
|
} rb_control_frame_t;
|
||||||
|
|
||||||
typedef struct rb_block_struct {
|
typedef struct rb_block_struct {
|
||||||
VALUE self; /* share with method frame if it's only block */
|
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 */
|
VALUE *ep; /* share with method frame if it's only block */
|
||||||
rb_iseq_t *iseq;
|
rb_iseq_t *iseq;
|
||||||
VALUE proc;
|
VALUE proc;
|
||||||
|
@ -714,7 +719,8 @@ void rb_vm_rewrite_ep_in_errinfo(rb_thread_t *th, rb_control_frame_t *cfp);
|
||||||
void rb_vm_inc_const_missing_count(void);
|
void rb_vm_inc_const_missing_count(void);
|
||||||
void rb_vm_gvl_destroy(rb_vm_t *vm);
|
void rb_vm_gvl_destroy(rb_vm_t *vm);
|
||||||
VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc,
|
VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc,
|
||||||
const VALUE *argv, const rb_method_entry_t *me);
|
const VALUE *argv, const rb_method_entry_t *me,
|
||||||
|
VALUE defined_class);
|
||||||
void rb_unlink_method_entry(rb_method_entry_t *me);
|
void rb_unlink_method_entry(rb_method_entry_t *me);
|
||||||
void rb_gc_mark_unlinked_live_method_entries(void *pvm);
|
void rb_gc_mark_unlinked_live_method_entries(void *pvm);
|
||||||
|
|
||||||
|
|
49
vm_eval.c
49
vm_eval.c
|
@ -33,11 +33,11 @@ static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type sc
|
||||||
|
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
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;
|
const rb_method_definition_t *def = me->def;
|
||||||
VALUE val;
|
VALUE val;
|
||||||
VALUE klass = me->klass;
|
VALUE klass = defined_class;
|
||||||
const rb_block_t *blockptr = 0;
|
const rb_block_t *blockptr = 0;
|
||||||
|
|
||||||
if (!def) return Qnil;
|
if (!def) return Qnil;
|
||||||
|
@ -59,7 +59,8 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||||||
*reg_cfp->sp++ = argv[i];
|
*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);
|
||||||
th->cfp->flag |= VM_FRAME_FLAG_FINISH;
|
th->cfp->flag |= VM_FRAME_FLAG_FINISH;
|
||||||
val = vm_exec(th);
|
val = vm_exec(th);
|
||||||
break;
|
break;
|
||||||
|
@ -71,7 +72,8 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||||||
rb_control_frame_t *reg_cfp = th->cfp;
|
rb_control_frame_t *reg_cfp = th->cfp;
|
||||||
rb_control_frame_t *cfp =
|
rb_control_frame_t *cfp =
|
||||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
||||||
recv, VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, me);
|
recv, klass, VM_ENVVAL_BLOCK_PTR(blockptr),
|
||||||
|
0, reg_cfp->sp, 1, me);
|
||||||
|
|
||||||
cfp->me = me;
|
cfp->me = me;
|
||||||
val = call_cfunc(def->body.cfunc.func, recv, def->body.cfunc.argc, argc, argv);
|
val = call_cfunc(def->body.cfunc.func, recv, def->body.cfunc.argc, argc, argv);
|
||||||
|
@ -95,12 +97,12 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VM_METHOD_TYPE_BMETHOD: {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case VM_METHOD_TYPE_ZSUPER: {
|
case VM_METHOD_TYPE_ZSUPER: {
|
||||||
klass = RCLASS_SUPER(klass);
|
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);
|
return method_missing(recv, id, argc, argv, NOEX_SUPER);
|
||||||
}
|
}
|
||||||
RUBY_VM_CHECK_INTS(th);
|
RUBY_VM_CHECK_INTS(th);
|
||||||
|
@ -144,9 +146,9 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
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
|
static inline VALUE
|
||||||
|
@ -158,9 +160,8 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
|
||||||
rb_method_entry_t *me;
|
rb_method_entry_t *me;
|
||||||
rb_control_frame_t *cfp = th->cfp;
|
rb_control_frame_t *cfp = th->cfp;
|
||||||
|
|
||||||
if (!cfp->iseq) {
|
if (!cfp->iseq && !NIL_P(cfp->klass)) {
|
||||||
klass = cfp->me->klass;
|
klass = RCLASS_SUPER(cfp->klass);
|
||||||
klass = RCLASS_SUPER(klass);
|
|
||||||
|
|
||||||
if (klass == 0) {
|
if (klass == 0) {
|
||||||
klass = vm_search_normal_superclass(cfp->me->klass, recv);
|
klass = vm_search_normal_superclass(cfp->me->klass, recv);
|
||||||
|
@ -171,12 +172,12 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
|
||||||
rb_bug("vm_call_super: should not be reached");
|
rb_bug("vm_call_super: should not be reached");
|
||||||
}
|
}
|
||||||
|
|
||||||
me = rb_method_entry(klass, id);
|
me = rb_method_entry(klass, id, &klass);
|
||||||
if (!me) {
|
if (!me) {
|
||||||
return method_missing(recv, id, argc, argv, NOEX_SUPER);
|
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
|
VALUE
|
||||||
|
@ -197,7 +198,8 @@ stack_check(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, const rb_method_entry_t *me, call_type scope, VALUE self);
|
static inline int rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self);
|
||||||
#define NOEX_OK NOEX_NOSUPER
|
#define NOEX_OK NOEX_NOSUPER
|
||||||
|
|
||||||
|
@ -219,7 +221,8 @@ static inline VALUE
|
||||||
rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
|
rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
|
||||||
call_type scope, VALUE self)
|
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();
|
rb_thread_t *th = GET_THREAD();
|
||||||
int call_status = rb_method_call_status(th, me, scope, self);
|
int call_status = rb_method_call_status(th, me, scope, self);
|
||||||
|
|
||||||
|
@ -227,7 +230,7 @@ rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
|
||||||
return method_missing(recv, mid, argc, argv, call_status);
|
return method_missing(recv, mid, argc, argv, call_status);
|
||||||
}
|
}
|
||||||
stack_check();
|
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 {
|
struct rescue_funcall_args {
|
||||||
|
@ -264,8 +267,9 @@ check_funcall(VALUE recv, ID mid, int argc, VALUE *argv)
|
||||||
const rb_method_entry_t *me;
|
const rb_method_entry_t *me;
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
int call_status;
|
int call_status;
|
||||||
|
VALUE defined_class;
|
||||||
|
|
||||||
me = rb_method_entry(klass, idRespond_to);
|
me = rb_method_entry(klass, idRespond_to, &defined_class);
|
||||||
if (me && !(me->flag & NOEX_BASIC)) {
|
if (me && !(me->flag & NOEX_BASIC)) {
|
||||||
VALUE args[2];
|
VALUE args[2];
|
||||||
int arity = rb_method_entry_arity(me);
|
int arity = rb_method_entry_arity(me);
|
||||||
|
@ -277,12 +281,13 @@ check_funcall(VALUE recv, ID mid, int argc, VALUE *argv)
|
||||||
|
|
||||||
args[0] = ID2SYM(mid);
|
args[0] = ID2SYM(mid);
|
||||||
args[1] = Qtrue;
|
args[1] = Qtrue;
|
||||||
if (!RTEST(vm_call0(th, recv, idRespond_to, arity, args, me))) {
|
if (!RTEST(vm_call0(th, recv, idRespond_to, arity, args, me,
|
||||||
|
defined_class))) {
|
||||||
return Qundef;
|
return Qundef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
me = rb_search_method_entry(recv, mid);
|
me = rb_search_method_entry(recv, mid, &defined_class);
|
||||||
call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef);
|
call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef);
|
||||||
if (call_status != NOEX_OK) {
|
if (call_status != NOEX_OK) {
|
||||||
if (rb_method_basic_definition_p(klass, idMethodMissing)) {
|
if (rb_method_basic_definition_p(klass, idMethodMissing)) {
|
||||||
|
@ -302,7 +307,7 @@ check_funcall(VALUE recv, ID mid, int argc, VALUE *argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack_check();
|
stack_check();
|
||||||
return vm_call0(th, recv, mid, argc, argv, me);
|
return vm_call0(th, recv, mid, argc, argv, me, defined_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
|
@ -347,7 +352,7 @@ rb_type_str(enum ruby_value_type type)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline rb_method_entry_t *
|
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);
|
VALUE klass = CLASS_OF(recv);
|
||||||
|
|
||||||
|
@ -386,7 +391,7 @@ rb_search_method_entry(VALUE recv, ID mid)
|
||||||
rb_id2name(mid), type, (void *)recv, flags, klass);
|
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
|
static inline int
|
||||||
|
|
|
@ -27,6 +27,7 @@ vm_push_frame(rb_thread_t *th,
|
||||||
const rb_iseq_t *iseq,
|
const rb_iseq_t *iseq,
|
||||||
VALUE type,
|
VALUE type,
|
||||||
VALUE self,
|
VALUE self,
|
||||||
|
VALUE klass,
|
||||||
VALUE specval,
|
VALUE specval,
|
||||||
const VALUE *pc,
|
const VALUE *pc,
|
||||||
VALUE *sp,
|
VALUE *sp,
|
||||||
|
@ -64,6 +65,18 @@ vm_push_frame(rb_thread_t *th,
|
||||||
cfp->block_iseq = 0;
|
cfp->block_iseq = 0;
|
||||||
cfp->proc = 0;
|
cfp->proc = 0;
|
||||||
cfp->me = me;
|
cfp->me = me;
|
||||||
|
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) {
|
if (VMDEBUG == 2) {
|
||||||
SDR();
|
SDR();
|
||||||
|
@ -415,14 +428,14 @@ call_cfunc(VALUE (*func)(), VALUE recv,
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
||||||
int num, volatile VALUE recv, const rb_block_t *blockptr,
|
int num, volatile VALUE recv, const rb_block_t *blockptr,
|
||||||
const rb_method_entry_t *me)
|
const rb_method_entry_t *me, VALUE defined_class)
|
||||||
{
|
{
|
||||||
volatile VALUE val = 0;
|
volatile VALUE val = 0;
|
||||||
const rb_method_definition_t *def = me->def;
|
const rb_method_definition_t *def = me->def;
|
||||||
|
|
||||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
|
||||||
|
|
||||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv,
|
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
|
||||||
VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me);
|
VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me);
|
||||||
|
|
||||||
reg_cfp->sp -= num + 1;
|
reg_cfp->sp -= num + 1;
|
||||||
|
@ -442,7 +455,8 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
||||||
|
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv,
|
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;
|
rb_proc_t *proc;
|
||||||
VALUE val;
|
VALUE val;
|
||||||
|
@ -483,7 +497,7 @@ vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
|
||||||
static inline void
|
static inline void
|
||||||
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag,
|
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;
|
int opt_pc, i;
|
||||||
VALUE *sp, *rsp = cfp->sp - argc;
|
VALUE *sp, *rsp = cfp->sp - argc;
|
||||||
|
@ -505,7 +519,7 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
*sp++ = Qnil;
|
*sp++ = Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, recv,
|
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, recv, defined_class,
|
||||||
VM_ENVVAL_BLOCK_PTR(blockptr),
|
VM_ENVVAL_BLOCK_PTR(blockptr),
|
||||||
iseq->iseq_encoded + opt_pc, sp, 0, me);
|
iseq->iseq_encoded + opt_pc, sp, 0, me);
|
||||||
|
|
||||||
|
@ -528,7 +542,7 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
*sp++ = Qnil;
|
*sp++ = Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, recv,
|
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, recv, defined_class,
|
||||||
VM_ENVVAL_BLOCK_PTR(blockptr),
|
VM_ENVVAL_BLOCK_PTR(blockptr),
|
||||||
iseq->iseq_encoded + opt_pc, sp, 0, me);
|
iseq->iseq_encoded + opt_pc, sp, 0, me);
|
||||||
}
|
}
|
||||||
|
@ -537,7 +551,8 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
int num, const rb_block_t *blockptr, VALUE flag,
|
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;
|
VALUE val;
|
||||||
|
|
||||||
|
@ -548,12 +563,14 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
normal_method_dispatch:
|
normal_method_dispatch:
|
||||||
switch (me->def->type) {
|
switch (me->def->type) {
|
||||||
case VM_METHOD_TYPE_ISEQ:{
|
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;
|
return Qundef;
|
||||||
}
|
}
|
||||||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||||||
case VM_METHOD_TYPE_CFUNC:{
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case VM_METHOD_TYPE_ATTRSET:{
|
case VM_METHOD_TYPE_ATTRSET:{
|
||||||
|
@ -581,12 +598,13 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
VALUE *argv = ALLOCA_N(VALUE, num);
|
VALUE *argv = ALLOCA_N(VALUE, num);
|
||||||
MEMCPY(argv, cfp->sp - num, VALUE, num);
|
MEMCPY(argv, cfp->sp - num, VALUE, num);
|
||||||
cfp->sp += - num - 1;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case VM_METHOD_TYPE_ZSUPER:{
|
case VM_METHOD_TYPE_ZSUPER:{
|
||||||
VALUE klass = RCLASS_SUPER(me->klass);
|
VALUE klass = RCLASS_SUPER(me->klass);
|
||||||
me = rb_method_entry(klass, id);
|
me = rb_method_entry(klass, id, &defined_class);
|
||||||
|
|
||||||
if (me != 0) {
|
if (me != 0) {
|
||||||
goto normal_method_dispatch;
|
goto normal_method_dispatch;
|
||||||
|
@ -622,7 +640,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
|
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;
|
num -= 1;
|
||||||
DEC_SP(1);
|
DEC_SP(1);
|
||||||
flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT;
|
flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT;
|
||||||
|
@ -665,8 +683,6 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
val = vm_method_missing(th, id, recv, num, blockptr, stat);
|
val = vm_method_missing(th, id, recv, num, blockptr, stat);
|
||||||
}
|
}
|
||||||
else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) {
|
else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) {
|
||||||
VALUE defined_class = me->klass;
|
|
||||||
|
|
||||||
if (RB_TYPE_P(defined_class, T_ICLASS)) {
|
if (RB_TYPE_P(defined_class, T_ICLASS)) {
|
||||||
defined_class = RBASIC(defined_class)->klass;
|
defined_class = RBASIC(defined_class)->klass;
|
||||||
}
|
}
|
||||||
|
@ -759,7 +775,8 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfp = vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self,
|
cfp = vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self,
|
||||||
VM_ENVVAL_PREV_EP_PTR(block->ep), 0, th->cfp->sp, 1, 0);
|
0, VM_ENVVAL_PREV_EP_PTR(block->ep), 0,
|
||||||
|
th->cfp->sp, 1, 0);
|
||||||
|
|
||||||
if (blockargptr) {
|
if (blockargptr) {
|
||||||
VM_CF_LEP(cfp)[0] = VM_ENVVAL_BLOCK_PTR(blockargptr);
|
VM_CF_LEP(cfp)[0] = VM_ENVVAL_BLOCK_PTR(blockargptr);
|
||||||
|
@ -976,6 +993,7 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_n
|
||||||
block_proc_is_lambda(block->proc));
|
block_proc_is_lambda(block->proc));
|
||||||
|
|
||||||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_BLOCK, block->self,
|
vm_push_frame(th, iseq, VM_FRAME_MAGIC_BLOCK, block->self,
|
||||||
|
block->klass,
|
||||||
VM_ENVVAL_PREV_EP_PTR(block->ep),
|
VM_ENVVAL_PREV_EP_PTR(block->ep),
|
||||||
iseq->iseq_encoded + opt_pc,
|
iseq->iseq_encoded + opt_pc,
|
||||||
rsp + arg_size,
|
rsp + arg_size,
|
||||||
|
@ -1396,22 +1414,28 @@ vm_setivar(VALUE obj, ID id, VALUE val, IC ic)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const rb_method_entry_t *
|
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;
|
rb_method_entry_t *me;
|
||||||
#if OPT_INLINE_METHOD_CACHE
|
#if OPT_INLINE_METHOD_CACHE
|
||||||
if (LIKELY(klass == ic->ic_class &&
|
if (LIKELY(klass == ic->ic_class &&
|
||||||
GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
|
GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
|
||||||
me = ic->ic_value.method;
|
me = ic->ic_value.method;
|
||||||
|
if (defined_class_ptr)
|
||||||
|
*defined_class_ptr = ic->ic_value2.defined_class;
|
||||||
}
|
}
|
||||||
else {
|
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_class = klass;
|
||||||
ic->ic_value.method = me;
|
ic->ic_value.method = me;
|
||||||
|
ic->ic_value2.defined_class = defined_class;
|
||||||
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
me = rb_method_entry(klass, id);
|
me = rb_method_entry(klass, id, defined_class_ptr);
|
||||||
#endif
|
#endif
|
||||||
return me;
|
return me;
|
||||||
}
|
}
|
||||||
|
@ -1419,7 +1443,7 @@ vm_method_search(VALUE id, VALUE klass, IC ic)
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
vm_search_normal_superclass(VALUE klass, VALUE recv)
|
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) {
|
||||||
klass = RCLASS_ORIGIN(klass);
|
klass = RCLASS_ORIGIN(klass);
|
||||||
return RCLASS_SUPER(klass);
|
return RCLASS_SUPER(klass);
|
||||||
}
|
}
|
||||||
|
@ -1488,10 +1512,10 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq,
|
||||||
}
|
}
|
||||||
|
|
||||||
id = lcfp->me->def->original_id;
|
id = lcfp->me->def->original_id;
|
||||||
klass = vm_search_normal_superclass(lcfp->me->klass, recv);
|
klass = vm_search_normal_superclass(lcfp->klass, recv);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
klass = vm_search_normal_superclass(iseq->klass, recv);
|
klass = vm_search_normal_superclass(reg_cfp->klass, recv);
|
||||||
}
|
}
|
||||||
|
|
||||||
*idp = id;
|
*idp = id;
|
||||||
|
@ -1771,7 +1795,7 @@ opt_eq_func(VALUE recv, VALUE obj, IC ic)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
||||||
if (check_cfunc(me, rb_obj_equal)) {
|
if (check_cfunc(me, rb_obj_equal)) {
|
||||||
return recv == obj ? Qtrue : Qfalse;
|
return recv == obj ? Qtrue : Qfalse;
|
||||||
|
|
|
@ -170,8 +170,8 @@ enum vm_regan_acttype {
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define CALL_METHOD(num, blockptr, flag, id, me, recv) do { \
|
#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)); \
|
VALUE v = vm_call_method(th, GET_CFP(), (num), (blockptr), (flag), (id), (me), (recv), (defined_class)); \
|
||||||
if (v == Qundef) { \
|
if (v == Qundef) { \
|
||||||
RESTORE_REGS(); \
|
RESTORE_REGS(); \
|
||||||
NEXT_INSN(); \
|
NEXT_INSN(); \
|
||||||
|
@ -213,8 +213,9 @@ enum vm_regan_acttype {
|
||||||
#if USE_IC_FOR_SPECIALIZED_METHOD
|
#if USE_IC_FOR_SPECIALIZED_METHOD
|
||||||
|
|
||||||
#define CALL_SIMPLE_METHOD(num, id, recv) do { \
|
#define CALL_SIMPLE_METHOD(num, id, recv) do { \
|
||||||
VALUE klass = CLASS_OF(recv); \
|
VALUE klass = CLASS_OF(recv), defined_class; \
|
||||||
CALL_METHOD((num), 0, 0, (id), vm_method_search((id), klass, ic), (recv)); \
|
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)
|
} while (0)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
49
vm_method.c
49
vm_method.c
|
@ -22,6 +22,7 @@ struct cache_entry { /* method hash table. */
|
||||||
ID mid; /* method's id */
|
ID mid; /* method's id */
|
||||||
VALUE klass; /* receiver's class */
|
VALUE klass; /* receiver's class */
|
||||||
rb_method_entry_t *me;
|
rb_method_entry_t *me;
|
||||||
|
VALUE defined_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cache_entry cache[CACHE_SIZE];
|
static struct cache_entry cache[CACHE_SIZE];
|
||||||
|
@ -373,7 +374,7 @@ rb_get_alloc_func(VALUE klass)
|
||||||
{
|
{
|
||||||
rb_method_entry_t *me;
|
rb_method_entry_t *me;
|
||||||
Check_Type(klass, T_CLASS);
|
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) {
|
if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC) {
|
||||||
return (rb_alloc_func_t)me->def->body.cfunc.func;
|
return (rb_alloc_func_t)me->def->body.cfunc.func;
|
||||||
|
@ -384,7 +385,7 @@ rb_get_alloc_func(VALUE klass)
|
||||||
}
|
}
|
||||||
|
|
||||||
static rb_method_entry_t*
|
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;
|
st_data_t body;
|
||||||
|
|
||||||
|
@ -396,6 +397,8 @@ search_method(VALUE klass, ID id)
|
||||||
if (st_lookup(m_tbl, id, &body)) break;
|
if (st_lookup(m_tbl, id, &body)) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (defined_class_ptr)
|
||||||
|
*defined_class_ptr = klass;
|
||||||
return (rb_method_entry_t *)body;
|
return (rb_method_entry_t *)body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,15 +409,18 @@ search_method(VALUE klass, ID id)
|
||||||
* rb_method_entry() simply.
|
* rb_method_entry() simply.
|
||||||
*/
|
*/
|
||||||
rb_method_entry_t *
|
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 = search_method(klass, id, &defined_class);
|
||||||
|
|
||||||
if (ruby_running) {
|
if (ruby_running) {
|
||||||
struct cache_entry *ent;
|
struct cache_entry *ent;
|
||||||
ent = cache + EXPR1(klass, id);
|
ent = cache + EXPR1(klass, id);
|
||||||
ent->filled_version = GET_VM_STATE_VERSION();
|
ent->filled_version = GET_VM_STATE_VERSION();
|
||||||
ent->klass = klass;
|
ent->klass = klass;
|
||||||
|
ent->defined_class = defined_class;
|
||||||
|
|
||||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||||
ent->mid = id;
|
ent->mid = id;
|
||||||
|
@ -427,21 +433,25 @@ rb_method_entry_get_without_cache(VALUE klass, ID id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (defined_class_ptr)
|
||||||
|
*defined_class_ptr = defined_class;
|
||||||
return me;
|
return me;
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_method_entry_t *
|
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;
|
struct cache_entry *ent;
|
||||||
|
|
||||||
ent = cache + EXPR1(klass, id);
|
ent = cache + EXPR1(klass, id);
|
||||||
if (ent->filled_version == GET_VM_STATE_VERSION() &&
|
if (ent->filled_version == GET_VM_STATE_VERSION() &&
|
||||||
ent->mid == id && ent->klass == klass) {
|
ent->mid == id && ent->klass == klass) {
|
||||||
|
if (defined_class_ptr)
|
||||||
|
*defined_class_ptr = ent->defined_class;
|
||||||
return ent->me;
|
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
|
static void
|
||||||
|
@ -534,14 +544,15 @@ static void
|
||||||
rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
|
rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
|
||||||
{
|
{
|
||||||
rb_method_entry_t *me;
|
rb_method_entry_t *me;
|
||||||
|
VALUE defined_class;
|
||||||
|
|
||||||
if (klass == rb_cObject) {
|
if (klass == rb_cObject) {
|
||||||
rb_secure(4);
|
rb_secure(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
me = search_method(klass, name);
|
me = search_method(klass, name, &defined_class);
|
||||||
if (!me && RB_TYPE_P(klass, T_MODULE)) {
|
if (!me && RB_TYPE_P(klass, T_MODULE)) {
|
||||||
me = search_method(rb_cObject, name);
|
me = search_method(rb_cObject, name, &defined_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||||
|
@ -551,7 +562,7 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
|
||||||
if (me->flag != noex) {
|
if (me->flag != noex) {
|
||||||
rb_vm_check_redefinition_opt_method(me, klass);
|
rb_vm_check_redefinition_opt_method(me, klass);
|
||||||
|
|
||||||
if (klass == me->klass) {
|
if (klass == defined_class) {
|
||||||
me->flag = noex;
|
me->flag = noex;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -563,7 +574,7 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
|
||||||
int
|
int
|
||||||
rb_method_boundp(VALUE klass, ID id, int ex)
|
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 (me != 0) {
|
||||||
if ((ex & ~NOEX_RESPONDS) &&
|
if ((ex & ~NOEX_RESPONDS) &&
|
||||||
|
@ -644,7 +655,7 @@ rb_undef(VALUE klass, ID id)
|
||||||
rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
|
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)) {
|
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||||
const char *s0 = " class";
|
const char *s0 = " class";
|
||||||
|
@ -773,7 +784,7 @@ check_definition(VALUE mod, VALUE mid, rb_method_flag_t noex)
|
||||||
const rb_method_entry_t *me;
|
const rb_method_entry_t *me;
|
||||||
ID id = rb_check_id(&mid);
|
ID id = rb_check_id(&mid);
|
||||||
if (!id) return Qfalse;
|
if (!id) return Qfalse;
|
||||||
me = rb_method_entry(mod, id);
|
me = rb_method_entry(mod, id, 0);
|
||||||
if (me) {
|
if (me) {
|
||||||
if (VISI_CHECK(me->flag, noex))
|
if (VISI_CHECK(me->flag, noex))
|
||||||
return Qtrue;
|
return Qtrue;
|
||||||
|
@ -969,11 +980,12 @@ rb_alias(VALUE klass, ID name, ID def)
|
||||||
}
|
}
|
||||||
|
|
||||||
again:
|
again:
|
||||||
orig_me = search_method(klass, def);
|
orig_me = search_method(klass, def, 0);
|
||||||
|
|
||||||
if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
|
if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
|
||||||
if ((!RB_TYPE_P(klass, T_MODULE)) ||
|
if ((!RB_TYPE_P(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);
|
rb_print_undef(klass, def, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1248,9 +1260,9 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
|
||||||
|
|
||||||
id = rb_to_id(argv[i]);
|
id = rb_to_id(argv[i]);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
me = search_method(m, id);
|
me = search_method(m, id, 0);
|
||||||
if (me == 0) {
|
if (me == 0) {
|
||||||
me = search_method(rb_cObject, id);
|
me = search_method(rb_cObject, id, 0);
|
||||||
}
|
}
|
||||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||||
rb_print_undef(module, id, 0);
|
rb_print_undef(module, id, 0);
|
||||||
|
@ -1270,7 +1282,7 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
|
||||||
int
|
int
|
||||||
rb_method_basic_definition_p(VALUE klass, ID id)
|
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))
|
if (me && (me->flag & NOEX_BASIC))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1402,7 +1414,8 @@ Init_eval_method(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
#define REPLICATE_METHOD(klass, id, noex) \
|
#define REPLICATE_METHOD(klass, id, noex) \
|
||||||
rb_method_entry_set((klass), (id), rb_method_entry((klass), (id)), \
|
rb_method_entry_set((klass), (id), \
|
||||||
|
rb_method_entry((klass), (id), 0), \
|
||||||
(rb_method_flag_t)(noex | NOEX_BASIC | NOEX_NOREDEF))
|
(rb_method_flag_t)(noex | NOEX_BASIC | NOEX_NOREDEF))
|
||||||
REPLICATE_METHOD(rb_eException, idMethodMissing, NOEX_PRIVATE);
|
REPLICATE_METHOD(rb_eException, idMethodMissing, NOEX_PRIVATE);
|
||||||
REPLICATE_METHOD(rb_eException, idRespond_to, NOEX_PUBLIC);
|
REPLICATE_METHOD(rb_eException, idRespond_to, NOEX_PUBLIC);
|
||||||
|
|
Loading…
Reference in a new issue