diff --git a/eval_intern.h b/eval_intern.h index c457deb..163eeb1 100644 --- a/eval_intern.h +++ b/eval_intern.h @@ -207,7 +207,7 @@ enum ruby_tag_type { (RNODE((obj))->u3.value = (val)) #define GET_THROWOBJ_VAL(obj) ((VALUE)RNODE((obj))->u1.value) -#define GET_THROWOBJ_CATCH_POINT(obj) ((VALUE*)RNODE((obj))->u2.value) +#define GET_THROWOBJ_CATCH_POINT(obj) ((rb_control_frame_t*)RNODE((obj))->u2.value) #define GET_THROWOBJ_STATE(obj) ((int)RNODE((obj))->u3.value) #define SCOPE_TEST(f) (rb_vm_cref()->nd_visi & (f)) diff --git a/vm.c b/vm.c index 750c756..f943182 100644 --- a/vm.c +++ b/vm.c @@ -28,6 +28,22 @@ VM_EP_LEP(VALUE *ep) return ep; } +static inline rb_control_frame_t * +VM_EP_CF(rb_thread_t *th, VALUE *ep) +{ + rb_control_frame_t *cfp = th->cfp; + if (!ep) { + return NULL; + } + while ((VALUE *) cfp < th->stack + th->stack_size) { + if (cfp->ep == ep) { + return cfp; + } + cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); + } + rb_bug("VM_EP_CF: no corresponding cfp"); +} + VALUE * rb_vm_ep_local_ep(VALUE *ep) { @@ -550,7 +566,6 @@ rb_vm_env_local_variables(VALUE envval) return local_var_list_finish(&vars); } -static void vm_rewrite_ep_in_errinfo(rb_thread_t *th); static VALUE vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block); static VALUE vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp, VALUE *blockprocptr); @@ -577,7 +592,6 @@ vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp, VALUE *blockprocptr } envval = vm_make_env_each(th, cfp, cfp->ep, lep); - vm_rewrite_ep_in_errinfo(th); if (PROCDEBUG) { check_env_value(envval); @@ -586,32 +600,6 @@ vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp, VALUE *blockprocptr return envval; } -static void -vm_rewrite_ep_in_errinfo(rb_thread_t *th) -{ - rb_control_frame_t *cfp = th->cfp; - while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { - /* rewrite ep in errinfo to point to heap */ - if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) && - (cfp->iseq->type == ISEQ_TYPE_RESCUE || - cfp->iseq->type == ISEQ_TYPE_ENSURE)) { - VALUE errinfo = cfp->ep[-2]; /* #$! */ - if (RB_TYPE_P(errinfo, T_NODE)) { - VALUE *escape_ep = GET_THROWOBJ_CATCH_POINT(errinfo); - if (! ENV_IN_HEAP_P(th, escape_ep)) { - VALUE epval = *escape_ep; - if (!SPECIAL_CONST_P(epval) && RBASIC(epval)->klass == rb_cEnv) { - rb_env_t *epenv; - GetEnvPtr(epval, epenv); - SET_THROWOBJ_CATCH_POINT(errinfo, (VALUE)(epenv->env + epenv->local_size)); - } - } - } - } - cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); - } -} - void rb_vm_stack_to_heap(rb_thread_t *th) { @@ -1150,11 +1138,11 @@ NORETURN(static void vm_iter_break(rb_thread_t *th, VALUE val)); static void vm_iter_break(rb_thread_t *th, VALUE val) { - rb_control_frame_t *cfp = th->cfp; - VALUE *ep = VM_CF_PREV_EP(cfp); + VALUE *ep = VM_CF_PREV_EP(th->cfp); + rb_control_frame_t *cfp = VM_EP_CF(th, ep); th->state = TAG_BREAK; - th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)ep, TAG_BREAK); + th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)cfp, TAG_BREAK); TH_JUMP_TAG(th, TAG_BREAK); } @@ -1419,7 +1407,7 @@ vm_exec(rb_thread_t *th) VALUE catch_iseqval; rb_control_frame_t *cfp; VALUE type; - VALUE *escape_ep; + rb_control_frame_t *escape_cfp; err = th->errinfo; @@ -1438,14 +1426,14 @@ vm_exec(rb_thread_t *th) cfp = th->cfp; epc = cfp->pc - cfp->iseq->iseq_encoded; - escape_ep = NULL; + escape_cfp = NULL; if (state == TAG_BREAK || state == TAG_RETURN) { - escape_ep = GET_THROWOBJ_CATCH_POINT(err); + escape_cfp = GET_THROWOBJ_CATCH_POINT(err); - if (cfp->ep == escape_ep) { + if (cfp == escape_cfp) { if (state == TAG_RETURN) { if (!VM_FRAME_TYPE_FINISH_P(cfp)) { - SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)->ep); + SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)); SET_THROWOBJ_STATE(err, state = TAG_BREAK); } else { @@ -1519,9 +1507,9 @@ vm_exec(rb_thread_t *th) break; } else if (entry->type == CATCH_TYPE_RETRY) { - VALUE *escape_ep; - escape_ep = GET_THROWOBJ_CATCH_POINT(err); - if (cfp->ep == escape_ep) { + rb_control_frame_t *escape_cfp; + escape_cfp = GET_THROWOBJ_CATCH_POINT(err); + if (cfp == escape_cfp) { cfp->pc = cfp->iseq->iseq_encoded + entry->cont; th->errinfo = Qnil; goto vm_loop_start; @@ -1530,7 +1518,7 @@ vm_exec(rb_thread_t *th) } } } - else if (state == TAG_BREAK && ((VALUE)escape_ep & ~0x03) == 0) { + else if (state == TAG_BREAK && ((VALUE)escape_cfp & ~0x01) == 0) { type = CATCH_TYPE_BREAK; search_restart_point: diff --git a/vm_eval.c b/vm_eval.c index 49ca9d4..a58eefe 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1100,10 +1100,9 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1, else { VALUE err = th->errinfo; if (state == TAG_BREAK) { - VALUE *escape_ep = GET_THROWOBJ_CATCH_POINT(err); - VALUE *cep = cfp->ep; + rb_control_frame_t *escape_cfp = GET_THROWOBJ_CATCH_POINT(err); - if (cep == escape_ep) { + if (cfp == escape_cfp) { state = 0; th->state = 0; th->errinfo = Qnil; @@ -1116,10 +1115,9 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1, } } else if (state == TAG_RETRY) { - VALUE *escape_ep = GET_THROWOBJ_CATCH_POINT(err); - VALUE *cep = cfp->ep; + rb_control_frame_t *escape_cfp = GET_THROWOBJ_CATCH_POINT(err); - if (cep == escape_ep) { + if (cfp == escape_cfp) { rb_vm_rewind_cfp(th, cfp); state = 0; diff --git a/vm_insnhelper.c b/vm_insnhelper.c index b875e2c..d112549 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -581,9 +581,10 @@ vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t level = throw_state >> 16; if (state != 0) { + rb_control_frame_t *escape_cfp = 0; VALUE *pt = 0; if (flag != 0) { - pt = (void *) 1; + escape_cfp = (void *) 0x01; } else { if (state == TAG_BREAK) { @@ -721,7 +722,10 @@ vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp, } } th->state = state; - return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state); + if (pt) { + escape_cfp = VM_EP_CF(th, pt); + } + return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE)escape_cfp, state); } else { /* continue throw */