diff --git a/ChangeLog b/ChangeLog index 248cc22c11..a6f35f650d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Sun May 5 18:56:52 2013 Nobuyoshi Nakada + + * insns.def (defined): use vm_search_superclass() like as normal super + call. based on a patch by + wanabe. + + * vm_insnhelper.c (vm_search_superclass): return error but not raise + exceptions. + + * vm_insnhelper.c (vm_search_super_method): check the result of + vm_search_superclass and raise execptions on error. + Sun May 5 16:29:41 2013 Nobuyoshi Nakada * insns.def (defined): get method entry from the method top level diff --git a/insns.def b/insns.def index d8be61114e..d49b6a7c92 100644 --- a/insns.def +++ b/insns.def @@ -764,21 +764,10 @@ defined } break; case DEFINED_ZSUPER:{ - const rb_method_entry_t *me = GET_CFP()->me; - if (!me) { - const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(GET_THREAD()); - const rb_control_frame_t *cfp = GET_CFP(); - const VALUE *const local_ep = rb_vm_ep_local_ep(cfp->ep); - while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp), end_cfp)) { - if (cfp->ep == local_ep) { - me = cfp->me; - break; - } - } - } - if (me) { - VALUE klass = vm_search_normal_superclass(GET_CFP()->klass); - ID id = me->def ? me->def->original_id : me->called_id; + rb_call_info_t cit; + if (vm_search_superclass(GET_CFP(), GET_ISEQ(), Qnil, &cit) == 0) { + VALUE klass = cit.klass; + ID id = cit.mid; if (rb_method_boundp(klass, id, 0)) { expr_type = DEFINED_ZSUPER; } diff --git a/vm_insnhelper.c b/vm_insnhelper.c index d4d0d45ef4..98ca16cdd3 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1954,7 +1954,7 @@ vm_super_outside(void) rb_raise(rb_eNoMethodError, "super called outside of method"); } -static void +static int vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci) { while (iseq && !iseq->klass) { @@ -1962,7 +1962,7 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, } if (iseq == 0) { - vm_super_outside(); + return -1; } ci->mid = iseq->defined_method_id; @@ -1973,7 +1973,7 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, if (!sigval) { /* zsuper */ - rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly."); + return -2; } while (lcfp->iseq != iseq) { @@ -1982,7 +1982,7 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, while (1) { lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp); if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, lcfp)) { - vm_super_outside(); + return -1; } if (lcfp->ep == tep) { break; @@ -1992,7 +1992,7 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, /* temporary measure for [Bug #2420] [Bug #3136] */ if (!lcfp->me) { - vm_super_outside(); + return -1; } ci->mid = lcfp->me->def->original_id; @@ -2001,6 +2001,8 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, else { ci->klass = vm_search_normal_superclass(reg_cfp->klass); } + + return 0; } static void @@ -2030,7 +2032,15 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf rb_obj_classname(ci->recv), rb_class2name(m)); } - vm_search_superclass(GET_CFP(), iseq, sigval, ci); + switch (vm_search_superclass(GET_CFP(), iseq, sigval, ci)) { + case -1: + vm_super_outside(); + case -2: + rb_raise(rb_eRuntimeError, + "implicit argument passing of super from method defined" + " by define_method() is not supported." + " Specify all arguments explicitly."); + } /* TODO: use inline cache */ ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);