Bug #10689 » save-target-cfp-in-errinfo.patch
| eval_intern.h | ||
|---|---|---|
|   (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)) | ||
| vm.c | ||
|---|---|---|
|     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) | ||
| { | ||
| ... | ... | |
|     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); | ||
| ... | ... | |
|     } | ||
|     envval = vm_make_env_each(th, cfp, cfp->ep, lep); | ||
|     vm_rewrite_ep_in_errinfo(th); | ||
|     if (PROCDEBUG) { | ||
| 	check_env_value(envval); | ||
| ... | ... | |
|     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) | ||
| { | ||
| ... | ... | |
| 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); | ||
| } | ||
| ... | ... | |
| 	VALUE catch_iseqval; | ||
| 	rb_control_frame_t *cfp; | ||
| 	VALUE type; | ||
| 	VALUE *escape_ep; | ||
| 	rb_control_frame_t *escape_cfp; | ||
| 	err = th->errinfo; | ||
| ... | ... | |
| 	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 { | ||
| ... | ... | |
| 			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; | ||
| ... | ... | |
| 		} | ||
| 	    } | ||
| 	} | ||
| 	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: | ||
| vm_eval.c | ||
|---|---|---|
|     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; | ||
| ... | ... | |
| 	    } | ||
| 	} | ||
| 	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; | ||
| vm_insnhelper.c | ||
|---|---|---|
|     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) { | ||
| ... | ... | |
| 	    } | ||
| 	} | ||
| 	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 */ | ||
- « Previous
- 1
- 2
- Next »