diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-07-05 10:04:56 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-07-05 10:04:56 +0000 |
commit | 0bb4c2b3db16c7e1c23877f1f1efc216c601f3d0 (patch) | |
tree | d9045d9e1835d881258b638ceb4552c887f720c8 /insns.def | |
parent | a74dbca6863a41bd948961944d1c6b19e01070c7 (diff) | |
download | ruby-0bb4c2b3db16c7e1c23877f1f1efc216c601f3d0.tar.gz |
* 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
Diffstat (limited to 'insns.def')
-rw-r--r-- | insns.def | 92 |
1 files changed, 78 insertions, 14 deletions
@@ -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; i<iseq->catch_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 { |