1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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
This commit is contained in:
ko1 2007-07-05 10:04:56 +00:00
parent a74dbca686
commit 0bb4c2b3db
4 changed files with 125 additions and 51 deletions

View file

@ -1,3 +1,12 @@
Thu Jul 5 18:42:01 2007 Koichi Sasada <ko1@atdot.net>
* 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 <akr@fsij.org>
* parse.y (mlhs_basic): use mlhs_post after tSTAR.

View file

@ -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;

View file

@ -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();
int is_orphan = 1;
/* check orphan */
/**
* 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 (is_orphan) {
vm_localjump_error("unexpected return", throwobj,
TAG_RETURN);
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);
}
/* set current lfp */
pt = GET_LFP();
}
else {

20
vm.c
View file

@ -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) {