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:
parent
a74dbca686
commit
0bb4c2b3db
4 changed files with 125 additions and 51 deletions
|
@ -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>
|
Thu Jul 5 18:44:12 2007 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* parse.y (mlhs_basic): use mlhs_post after tSTAR.
|
* parse.y (mlhs_basic): use mlhs_post after tSTAR.
|
||||||
|
|
51
compile.c
51
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_ITER:
|
||||||
case NODE_FOR:{
|
case NODE_FOR:{
|
||||||
VALUE prevblock = iseq->compile_data->current_block;
|
VALUE prevblock = iseq->compile_data->current_block;
|
||||||
LABEL *retry_label = NEW_LABEL(nd_line(node));
|
LABEL *retry_label = NEW_LABEL(nd_line(node));
|
||||||
LABEL *retry_end_l = NEW_LABEL(nd_line(node));
|
LABEL *retry_end_l = NEW_LABEL(nd_line(node));
|
||||||
ID mid = 0;
|
ID mid = 0;
|
||||||
|
|
||||||
ADD_LABEL(ret, retry_label);
|
ADD_LABEL(ret, retry_label);
|
||||||
if (nd_type(node) == NODE_FOR) {
|
if (nd_type(node) == NODE_FOR) {
|
||||||
COMPILE(ret, "iter caller (for)", node->nd_iter);
|
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),
|
NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
|
||||||
ISEQ_TYPE_BLOCK);
|
ISEQ_TYPE_BLOCK);
|
||||||
|
|
||||||
mid = idEach;
|
mid = idEach;
|
||||||
ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0),
|
ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0),
|
||||||
iseq->compile_data->current_block, INT2FIX(0));
|
iseq->compile_data->current_block, INT2FIX(0));
|
||||||
if (poped) {
|
}
|
||||||
ADD_INSN(ret, nd_line(node), pop);
|
else {
|
||||||
}
|
iseq->compile_data->current_block =
|
||||||
}
|
|
||||||
else {
|
|
||||||
iseq->compile_data->current_block =
|
|
||||||
NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
|
NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq),
|
||||||
ISEQ_TYPE_BLOCK);
|
ISEQ_TYPE_BLOCK);
|
||||||
COMPILE_(ret, "iter caller", node->nd_iter, poped);
|
COMPILE(ret, "iter caller", node->nd_iter);
|
||||||
}
|
}
|
||||||
ADD_LABEL(ret, retry_end_l);
|
ADD_LABEL(ret, retry_end_l);
|
||||||
iseq->compile_data->current_block = prevblock;
|
|
||||||
|
|
||||||
ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, retry_label, retry_end_l, 0,
|
if (poped) {
|
||||||
retry_label);
|
ADD_INSN(ret, nd_line(node), pop);
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
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:{
|
case NODE_BREAK:{
|
||||||
unsigned long level = 0;
|
unsigned long level = 0;
|
||||||
|
|
94
insns.def
94
insns.def
|
@ -1386,7 +1386,70 @@ throw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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());
|
pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP());
|
||||||
for (i = 0; i < level; i++) {
|
for (i = 0; i < level; i++) {
|
||||||
pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
|
pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
|
||||||
|
@ -1394,31 +1457,32 @@ throw
|
||||||
}
|
}
|
||||||
else if (state == TAG_RETURN) {
|
else if (state == TAG_RETURN) {
|
||||||
rb_control_frame_t *cfp = GET_CFP();
|
rb_control_frame_t *cfp = GET_CFP();
|
||||||
int is_orphan = 1;
|
|
||||||
VALUE *dfp = GET_DFP();
|
VALUE *dfp = GET_DFP();
|
||||||
|
int is_orphan = 1;
|
||||||
|
|
||||||
/* check orphan */
|
/**
|
||||||
|
* check orphan:
|
||||||
|
*/
|
||||||
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
||||||
if (GET_LFP() == cfp->lfp) {
|
if (GET_DFP() == dfp) {
|
||||||
is_orphan = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (dfp == cfp->dfp) {
|
|
||||||
/* return from lambda{} */
|
|
||||||
if (cfp->magic == FRAME_MAGIC_LAMBDA) {
|
if (cfp->magic == FRAME_MAGIC_LAMBDA) {
|
||||||
|
/* in lambda */
|
||||||
is_orphan = 0;
|
is_orphan = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dfp = GC_GUARDED_PTR_REF(*cfp->dfp);
|
|
||||||
}
|
}
|
||||||
cfp++;
|
cfp++;
|
||||||
}
|
if (GET_LFP() == cfp->lfp &&
|
||||||
if (is_orphan) {
|
cfp->iseq->type == ISEQ_TYPE_METHOD) {
|
||||||
vm_localjump_error("unexpected return", throwobj,
|
is_orphan = 0;
|
||||||
TAG_RETURN);
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_orphan) {
|
||||||
|
vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set current lfp */
|
|
||||||
pt = GET_LFP();
|
pt = GET_LFP();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
20
vm.c
20
vm.c
|
@ -606,12 +606,15 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc,
|
||||||
TH_PUSH_TAG(th);
|
TH_PUSH_TAG(th);
|
||||||
if ((state = EXEC_TAG()) == 0) {
|
if ((state = EXEC_TAG()) == 0) {
|
||||||
th->safe_level = proc->safe_level;
|
th->safe_level = proc->safe_level;
|
||||||
|
|
||||||
val = invoke_block(th, &proc->block, self, argc, argv);
|
val = invoke_block(th, &proc->block, self, argc, argv);
|
||||||
}
|
}
|
||||||
else {
|
TH_POP_TAG();
|
||||||
if (state == TAG_BREAK ||
|
|
||||||
(state == TAG_RETURN && proc->is_lambda)) {
|
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 err = th->errinfo;
|
||||||
VALUE *escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
|
VALUE *escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
|
||||||
VALUE *cdfp = proc->block.dfp;
|
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) {
|
if (state) {
|
||||||
JUMP_TAG(state);
|
JUMP_TAG(state);
|
||||||
|
@ -873,9 +872,8 @@ vm_get_cbase(rb_thread_t *th)
|
||||||
static VALUE
|
static VALUE
|
||||||
make_localjump_error(const char *mesg, VALUE value, int reason)
|
make_localjump_error(const char *mesg, VALUE value, int reason)
|
||||||
{
|
{
|
||||||
VALUE exc =
|
extern VALUE rb_eLocalJumpError;
|
||||||
rb_exc_new2(rb_const_get(rb_cObject, rb_intern("LocalJumpError")),
|
VALUE exc = rb_exc_new2(rb_eLocalJumpError, mesg);
|
||||||
mesg);
|
|
||||||
ID id;
|
ID id;
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue