From 0bb4c2b3db16c7e1c23877f1f1efc216c601f3d0 Mon Sep 17 00:00:00 2001 From: ko1 Date: Thu, 5 Jul 2007 10:04:56 +0000 Subject: * compile.c (iseq_compile_each): add break catch point. * insns.def (throw): support correct "break" and "return". this commit achieve that "make test" passes all tests. * vm.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12703 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 9 +++++++ compile.c | 51 ++++++++++++++++++----------------- insns.def | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------- vm.c | 20 +++++++------- 4 files changed, 123 insertions(+), 49 deletions(-) diff --git a/ChangeLog b/ChangeLog index d016a08cb3..d126017c87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Thu Jul 5 18:42:01 2007 Koichi Sasada + + * compile.c (iseq_compile_each): add break catch point. + + * insns.def (throw): support correct "break" and "return". + this commit achieve that "make test" passes all tests. + + * vm.c: ditto. + Thu Jul 5 18:44:12 2007 Tanaka Akira * parse.y (mlhs_basic): use mlhs_post after tSTAR. diff --git a/compile.c b/compile.c index 3e237e7f37..6ac0e61f0e 100644 --- a/compile.c +++ b/compile.c @@ -2839,38 +2839,41 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) } case NODE_ITER: case NODE_FOR:{ - VALUE prevblock = iseq->compile_data->current_block; - LABEL *retry_label = NEW_LABEL(nd_line(node)); - LABEL *retry_end_l = NEW_LABEL(nd_line(node)); - ID mid = 0; + VALUE prevblock = iseq->compile_data->current_block; + LABEL *retry_label = NEW_LABEL(nd_line(node)); + LABEL *retry_end_l = NEW_LABEL(nd_line(node)); + ID mid = 0; - ADD_LABEL(ret, retry_label); - if (nd_type(node) == NODE_FOR) { - COMPILE(ret, "iter caller (for)", node->nd_iter); + ADD_LABEL(ret, retry_label); + if (nd_type(node) == NODE_FOR) { + COMPILE(ret, "iter caller (for)", node->nd_iter); - iseq->compile_data->current_block = + iseq->compile_data->current_block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK); - mid = idEach; - ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0), - iseq->compile_data->current_block, INT2FIX(0)); - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - } - else { - iseq->compile_data->current_block = + mid = idEach; + ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0), + iseq->compile_data->current_block, INT2FIX(0)); + } + else { + iseq->compile_data->current_block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK); - COMPILE_(ret, "iter caller", node->nd_iter, poped); - } - ADD_LABEL(ret, retry_end_l); - iseq->compile_data->current_block = prevblock; + COMPILE(ret, "iter caller", node->nd_iter); + } + ADD_LABEL(ret, retry_end_l); - ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, retry_label, retry_end_l, 0, - retry_label); - break; + if (poped) { + ADD_INSN(ret, nd_line(node), pop); + } + + iseq->compile_data->current_block = prevblock; + + ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, retry_label, retry_end_l, 0, retry_label); + ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l); + + break; } case NODE_BREAK:{ unsigned long level = 0; diff --git a/insns.def b/insns.def index 6dbfd09db1..471f2a5bfb 100644 --- a/insns.def +++ b/insns.def @@ -1386,7 +1386,70 @@ throw } } else { - if (state == TAG_BREAK || state == TAG_RETRY) { + if (state == TAG_BREAK) { + rb_control_frame_t *cfp = GET_CFP(); + VALUE *dfp = GET_DFP(); + int is_orphan = 1; + rb_iseq_t *base_iseq = GET_ISEQ(); + + INSN_LABEL(search_parent): + if (cfp->iseq->type != ISEQ_TYPE_BLOCK) { + dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); + base_iseq = base_iseq->parent_iseq; + + while ((VALUE *) cfp < th->stack + th->stack_size) { + if (cfp->dfp == dfp) { + goto INSN_LABEL(search_parent); + } + cfp++; + } + rb_bug("VM (throw): can't find break base."); + } + + if (cfp->magic == FRAME_MAGIC_LAMBDA) { + /* lambda{... break ...} */ + is_orphan = 0; + pt = dfp; + } + else { + dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); + + while ((VALUE *)cfp < th->stack + th->stack_size) { + if (cfp->dfp == dfp) { + VALUE epc = epc = cfp->pc - cfp->iseq->iseq_encoded; + rb_iseq_t *iseq = cfp->iseq; + int i; + + for (i=0; icatch_table_size; i++) { + struct iseq_catch_table_entry *entry = &iseq->catch_table[i]; + + if (entry->type == CATCH_TYPE_BREAK && + entry->start < epc && entry->end >= epc) { + if (entry->cont == epc) { + goto INSN_LABEL(found); + } + else { + break; + } + } + } + break; + + INSN_LABEL(found): + + pt = dfp; + is_orphan = 0; + break; + } + cfp++; + } + } + + if (is_orphan) { + vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK); + } + } + else if (state == TAG_RETRY) { pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP()); for (i = 0; i < level; i++) { pt = GC_GUARDED_PTR_REF((VALUE *) * pt); @@ -1394,31 +1457,32 @@ throw } else if (state == TAG_RETURN) { rb_control_frame_t *cfp = GET_CFP(); - int is_orphan = 1; VALUE *dfp = GET_DFP(); - - /* check orphan */ + int is_orphan = 1; + + /** + * check orphan: + */ while ((VALUE *) cfp < th->stack + th->stack_size) { - if (GET_LFP() == cfp->lfp) { - is_orphan = 0; - break; - } - else if (dfp == cfp->dfp) { - /* return from lambda{} */ + if (GET_DFP() == dfp) { if (cfp->magic == FRAME_MAGIC_LAMBDA) { + /* in lambda */ is_orphan = 0; break; } - dfp = GC_GUARDED_PTR_REF(*cfp->dfp); } cfp++; + if (GET_LFP() == cfp->lfp && + cfp->iseq->type == ISEQ_TYPE_METHOD) { + is_orphan = 0; + break; + } } + if (is_orphan) { - vm_localjump_error("unexpected return", throwobj, - TAG_RETURN); + vm_localjump_error("unexpected return", throwobj, TAG_RETURN); } - /* set current lfp */ pt = GET_LFP(); } else { diff --git a/vm.c b/vm.c index 81e6ee2f81..fd7bd4f372 100644 --- a/vm.c +++ b/vm.c @@ -606,12 +606,15 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { th->safe_level = proc->safe_level; - val = invoke_block(th, &proc->block, self, argc, argv); } - else { - if (state == TAG_BREAK || - (state == TAG_RETURN && proc->is_lambda)) { + TH_POP_TAG(); + + th->safe_level = stored_safe; + lfp_set_special_cref(proc->block.lfp, (NODE*)stored_special_cref_stack); + + if (state) { + if (state == TAG_RETURN && proc->is_lambda) { VALUE err = th->errinfo; VALUE *escape_dfp = GET_THROWOBJ_CATCH_POINT(err); VALUE *cdfp = proc->block.dfp; @@ -624,10 +627,6 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, } } } - TH_POP_TAG(); - - th->safe_level = stored_safe; - lfp_set_special_cref(proc->block.lfp, (NODE*)stored_special_cref_stack); if (state) { JUMP_TAG(state); @@ -873,9 +872,8 @@ vm_get_cbase(rb_thread_t *th) static VALUE make_localjump_error(const char *mesg, VALUE value, int reason) { - VALUE exc = - rb_exc_new2(rb_const_get(rb_cObject, rb_intern("LocalJumpError")), - mesg); + extern VALUE rb_eLocalJumpError; + VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg); ID id; switch (reason) { -- cgit v1.2.3