summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
authorktsj <ktsj@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-01-16 02:54:22 (GMT)
committerktsj <ktsj@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-01-16 02:54:22 (GMT)
commite62a99b924a9b629eca48bfa3f74d1965bc0ecad (patch)
treed3627ccb92d1795c232ddf0dfa8787173571a1ca /vm.c
parent10fe26fe29681e1b33ee9881efab8e21a7b4fc4d (diff)
* eval_intern.h, vm.c, vm_eval.c, vm_insnhelper.c:
change throw mechanism (not save target ep, but save target cfp). It fixes `unexpected break' bug that occurs when TracePoint#binding is called. [ruby-dev:48797] [Bug #10689] * test/ruby/test_settracefunc.rb: add a test. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49266 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c69
1 files changed, 31 insertions, 38 deletions
diff --git a/vm.c b/vm.c
index 750c756..e6ef3a8 100644
--- a/vm.c
+++ b/vm.c
@@ -28,6 +28,26 @@ VM_EP_LEP(VALUE *ep)
return ep;
}
+static inline rb_control_frame_t *
+rb_vm_search_cf_from_ep(const rb_thread_t * const th, rb_control_frame_t *cfp, const VALUE * const ep)
+{
+ if (!ep) {
+ return NULL;
+ }
+ else {
+ const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME(th); /* end of control frame pointer */
+
+ while (cfp < eocfp) {
+ if (cfp->ep == ep) {
+ return cfp;
+ }
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+
+ rb_bug("rb_vm_search_cf_from_ep: no corresponding cfp");
+ }
+}
+
VALUE *
rb_vm_ep_local_ep(VALUE *ep)
{
@@ -550,7 +570,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 +596,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 +604,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)
{
@@ -1152,9 +1144,10 @@ vm_iter_break(rb_thread_t *th, VALUE val)
{
rb_control_frame_t *cfp = th->cfp;
VALUE *ep = VM_CF_PREV_EP(cfp);
+ rb_control_frame_t *target_cfp = rb_vm_search_cf_from_ep(th, cfp, ep);
th->state = TAG_BREAK;
- th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)ep, TAG_BREAK);
+ th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)target_cfp, TAG_BREAK);
TH_JUMP_TAG(th, TAG_BREAK);
}
@@ -1419,7 +1412,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 +1431,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 +1512,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 +1523,7 @@ vm_exec(rb_thread_t *th)
}
}
}
- else if (state == TAG_BREAK && ((VALUE)escape_ep & ~0x03) == 0) {
+ else if (state == TAG_BREAK && !escape_cfp) {
type = CATCH_TYPE_BREAK;
search_restart_point: