зеркало из https://github.com/github/ruby.git
* 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
This commit is contained in:
Родитель
10fe26fe29
Коммит
e62a99b924
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
Fri Jan 16 11:44:44 2015 Kazuki Tsujimoto <kazuki@callcc.net>
|
||||
|
||||
* 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.
|
||||
|
||||
Thu Jan 15 23:55:15 2015 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* io.c (rb_io_close_m): Don't raise when the IO object is closed.
|
||||
|
|
|
@ -207,7 +207,7 @@ enum ruby_tag_type {
|
|||
(RNODE((obj))->u3.value = (val))
|
||||
|
||||
#define GET_THROWOBJ_VAL(obj) ((VALUE)RNODE((obj))->u1.value)
|
||||
#define GET_THROWOBJ_CATCH_POINT(obj) ((VALUE*)RNODE((obj))->u2.value)
|
||||
#define GET_THROWOBJ_CATCH_POINT(obj) ((rb_control_frame_t*)RNODE((obj))->u2.value)
|
||||
#define GET_THROWOBJ_STATE(obj) ((int)RNODE((obj))->u3.value)
|
||||
|
||||
#define SCOPE_TEST(f) (rb_vm_cref()->nd_visi & (f))
|
||||
|
|
|
@ -977,6 +977,27 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_trace_point_binding_after_break
|
||||
bug10689 = '[ruby-dev:48797]'
|
||||
assert_in_out_err([], <<-INPUT, [], [], bug10689)
|
||||
class Bug
|
||||
include Enumerable
|
||||
|
||||
def each
|
||||
[0].each do
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
TracePoint.trace(:c_return) do |tp|
|
||||
tp.binding
|
||||
end
|
||||
|
||||
Bug.new.all? { false }
|
||||
INPUT
|
||||
end
|
||||
|
||||
def test_tracepoint_b_return_with_next
|
||||
n = 0
|
||||
TracePoint.new(:b_return){
|
||||
|
|
69
vm.c
69
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:
|
||||
|
|
10
vm_eval.c
10
vm_eval.c
|
@ -1100,10 +1100,9 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1,
|
|||
else {
|
||||
VALUE err = th->errinfo;
|
||||
if (state == TAG_BREAK) {
|
||||
VALUE *escape_ep = GET_THROWOBJ_CATCH_POINT(err);
|
||||
VALUE *cep = cfp->ep;
|
||||
rb_control_frame_t *escape_cfp = GET_THROWOBJ_CATCH_POINT(err);
|
||||
|
||||
if (cep == escape_ep) {
|
||||
if (cfp == escape_cfp) {
|
||||
state = 0;
|
||||
th->state = 0;
|
||||
th->errinfo = Qnil;
|
||||
|
@ -1116,10 +1115,9 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1,
|
|||
}
|
||||
}
|
||||
else if (state == TAG_RETRY) {
|
||||
VALUE *escape_ep = GET_THROWOBJ_CATCH_POINT(err);
|
||||
VALUE *cep = cfp->ep;
|
||||
rb_control_frame_t *escape_cfp = GET_THROWOBJ_CATCH_POINT(err);
|
||||
|
||||
if (cep == escape_ep) {
|
||||
if (cfp == escape_cfp) {
|
||||
rb_vm_rewind_cfp(th, cfp);
|
||||
|
||||
state = 0;
|
||||
|
|
323
vm_insnhelper.c
323
vm_insnhelper.c
|
@ -572,175 +572,176 @@ vm_setinstancevariable(VALUE obj, ID id, VALUE val, IC ic)
|
|||
vm_setivar(obj, id, val, ic, 0, 0);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
vm_throw_continue(rb_thread_t *th, VALUE throwobj)
|
||||
{
|
||||
/* continue throw */
|
||||
VALUE err = throwobj;
|
||||
|
||||
if (FIXNUM_P(err)) {
|
||||
th->state = FIX2INT(err);
|
||||
}
|
||||
else if (SYMBOL_P(err)) {
|
||||
th->state = TAG_THROW;
|
||||
}
|
||||
else if (BUILTIN_TYPE(err) == T_NODE) {
|
||||
th->state = GET_THROWOBJ_STATE(err);
|
||||
}
|
||||
else {
|
||||
th->state = TAG_RAISE;
|
||||
/*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
vm_throw_start(rb_thread_t * const th, rb_control_frame_t * const reg_cfp, int state, const int flag, const rb_num_t level, const VALUE throwobj)
|
||||
{
|
||||
rb_control_frame_t *escape_cfp = NULL;
|
||||
const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME(th); /* end of control frame pointer */
|
||||
|
||||
if (flag != 0) {
|
||||
/* do nothing */
|
||||
}
|
||||
else if (state == TAG_BREAK) {
|
||||
int is_orphan = 1;
|
||||
VALUE *ep = GET_EP();
|
||||
rb_iseq_t *base_iseq = GET_ISEQ();
|
||||
escape_cfp = reg_cfp;
|
||||
|
||||
search_parent:
|
||||
if (base_iseq->type != ISEQ_TYPE_BLOCK) {
|
||||
if (escape_cfp->iseq->type == ISEQ_TYPE_CLASS) {
|
||||
escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
|
||||
ep = escape_cfp->ep;
|
||||
base_iseq = escape_cfp->iseq;
|
||||
goto search_parent;
|
||||
}
|
||||
else {
|
||||
ep = VM_EP_PREV_EP(ep);
|
||||
base_iseq = base_iseq->parent_iseq;
|
||||
escape_cfp = rb_vm_search_cf_from_ep(th, escape_cfp, ep);
|
||||
assert(escape_cfp->iseq == base_iseq);
|
||||
}
|
||||
}
|
||||
|
||||
if (VM_FRAME_TYPE(escape_cfp) == VM_FRAME_MAGIC_LAMBDA) {
|
||||
/* lambda{... break ...} */
|
||||
is_orphan = 0;
|
||||
state = TAG_RETURN;
|
||||
}
|
||||
else {
|
||||
ep = VM_EP_PREV_EP(ep);
|
||||
|
||||
while (escape_cfp < eocfp) {
|
||||
if (escape_cfp->ep == ep) {
|
||||
const VALUE epc = escape_cfp->pc - escape_cfp->iseq->iseq_encoded;
|
||||
const rb_iseq_t * const iseq = escape_cfp->iseq;
|
||||
const struct iseq_catch_table * const ct = iseq->catch_table;
|
||||
const int ct_size = ct->size;
|
||||
int i;
|
||||
|
||||
for (i=0; i<ct_size; i++) {
|
||||
const struct iseq_catch_table_entry * const entry = &ct->entries[i];;
|
||||
|
||||
if (entry->type == CATCH_TYPE_BREAK && entry->start < epc && entry->end >= epc) {
|
||||
if (entry->cont == epc) { /* found! */
|
||||
is_orphan = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_orphan) {
|
||||
rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
|
||||
}
|
||||
}
|
||||
else if (state == TAG_RETRY) {
|
||||
rb_num_t i;
|
||||
VALUE *ep = VM_EP_PREV_EP(GET_EP());
|
||||
|
||||
for (i = 0; i < level; i++) {
|
||||
ep = VM_EP_PREV_EP(ep);
|
||||
}
|
||||
|
||||
escape_cfp = rb_vm_search_cf_from_ep(th, reg_cfp, ep);
|
||||
}
|
||||
else if (state == TAG_RETURN) {
|
||||
VALUE *current_ep = GET_EP();
|
||||
VALUE *target_lep = VM_EP_LEP(current_ep);
|
||||
int in_class_frame = 0;
|
||||
escape_cfp = reg_cfp;
|
||||
|
||||
while (escape_cfp < eocfp) {
|
||||
VALUE *lep = VM_CF_LEP(escape_cfp);
|
||||
|
||||
if (!target_lep) {
|
||||
target_lep = lep;
|
||||
}
|
||||
|
||||
if (lep == target_lep && escape_cfp->iseq->type == ISEQ_TYPE_CLASS) {
|
||||
in_class_frame = 1;
|
||||
target_lep = 0;
|
||||
}
|
||||
|
||||
if (lep == target_lep) {
|
||||
if (VM_FRAME_TYPE(escape_cfp) == VM_FRAME_MAGIC_LAMBDA) {
|
||||
if (in_class_frame) {
|
||||
/* lambda {class A; ... return ...; end} */
|
||||
goto valid_return;
|
||||
}
|
||||
else {
|
||||
VALUE *tep = current_ep;
|
||||
|
||||
while (target_lep != tep) {
|
||||
if (escape_cfp->ep == tep) {
|
||||
/* in lambda */
|
||||
goto valid_return;
|
||||
}
|
||||
tep = VM_EP_PREV_EP(tep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (escape_cfp->ep == target_lep && escape_cfp->iseq->type == ISEQ_TYPE_METHOD) {
|
||||
goto valid_return;
|
||||
}
|
||||
|
||||
escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp);
|
||||
}
|
||||
rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
|
||||
|
||||
valid_return:;
|
||||
/* do nothing */
|
||||
}
|
||||
else {
|
||||
rb_bug("isns(throw): unsupport throw type");
|
||||
}
|
||||
|
||||
th->state = state;
|
||||
return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE)escape_cfp, state);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
||||
rb_num_t throw_state, VALUE throwobj)
|
||||
{
|
||||
int state = (int)(throw_state & 0xff);
|
||||
int flag = (int)(throw_state & 0x8000);
|
||||
rb_num_t level = throw_state >> 16;
|
||||
const int state = (int)(throw_state & 0xff);
|
||||
const int flag = (int)(throw_state & 0x8000);
|
||||
const rb_num_t level = throw_state >> 16;
|
||||
|
||||
if (state != 0) {
|
||||
VALUE *pt = 0;
|
||||
if (flag != 0) {
|
||||
pt = (void *) 1;
|
||||
}
|
||||
else {
|
||||
if (state == TAG_BREAK) {
|
||||
rb_control_frame_t *cfp = GET_CFP();
|
||||
VALUE *ep = GET_EP();
|
||||
int is_orphan = 1;
|
||||
rb_iseq_t *base_iseq = GET_ISEQ();
|
||||
|
||||
search_parent:
|
||||
if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {
|
||||
if (cfp->iseq->type == ISEQ_TYPE_CLASS) {
|
||||
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
||||
ep = cfp->ep;
|
||||
goto search_parent;
|
||||
}
|
||||
ep = VM_EP_PREV_EP(ep);
|
||||
base_iseq = base_iseq->parent_iseq;
|
||||
|
||||
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
||||
if (cfp->ep == ep) {
|
||||
goto search_parent;
|
||||
}
|
||||
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
||||
}
|
||||
rb_bug("VM (throw): can't find break base.");
|
||||
}
|
||||
|
||||
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
|
||||
/* lambda{... break ...} */
|
||||
is_orphan = 0;
|
||||
pt = cfp->ep;
|
||||
state = TAG_RETURN;
|
||||
}
|
||||
else {
|
||||
ep = VM_EP_PREV_EP(ep);
|
||||
|
||||
while ((VALUE *)cfp < th->stack + th->stack_size) {
|
||||
if (cfp->ep == ep) {
|
||||
VALUE epc = cfp->pc - cfp->iseq->iseq_encoded;
|
||||
rb_iseq_t *iseq = cfp->iseq;
|
||||
struct iseq_catch_table *ct = iseq->catch_table;
|
||||
struct iseq_catch_table_entry *entry;
|
||||
int i;
|
||||
|
||||
for (i=0; i<ct->size; i++) {
|
||||
entry = &ct->entries[i];
|
||||
|
||||
if (entry->type == CATCH_TYPE_BREAK &&
|
||||
entry->start < epc && entry->end >= epc) {
|
||||
if (entry->cont == epc) {
|
||||
goto found;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
found:
|
||||
pt = ep;
|
||||
is_orphan = 0;
|
||||
break;
|
||||
}
|
||||
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_orphan) {
|
||||
rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
|
||||
}
|
||||
}
|
||||
else if (state == TAG_RETRY) {
|
||||
rb_num_t i;
|
||||
pt = VM_EP_PREV_EP(GET_EP());
|
||||
for (i = 0; i < level; i++) {
|
||||
pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
|
||||
}
|
||||
}
|
||||
else if (state == TAG_RETURN) {
|
||||
rb_control_frame_t *cfp = GET_CFP();
|
||||
VALUE *ep = GET_EP();
|
||||
VALUE *target_lep = VM_CF_LEP(cfp);
|
||||
int in_class_frame = 0;
|
||||
|
||||
/* check orphan and get dfp */
|
||||
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
||||
VALUE *lep = VM_CF_LEP(cfp);
|
||||
|
||||
if (!target_lep) {
|
||||
target_lep = lep;
|
||||
}
|
||||
|
||||
if (lep == target_lep && cfp->iseq->type == ISEQ_TYPE_CLASS) {
|
||||
in_class_frame = 1;
|
||||
target_lep = 0;
|
||||
}
|
||||
|
||||
if (lep == target_lep) {
|
||||
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
|
||||
VALUE *tep = ep;
|
||||
|
||||
if (in_class_frame) {
|
||||
/* lambda {class A; ... return ...; end} */
|
||||
ep = cfp->ep;
|
||||
goto valid_return;
|
||||
}
|
||||
|
||||
while (target_lep != tep) {
|
||||
if (cfp->ep == tep) {
|
||||
/* in lambda */
|
||||
ep = cfp->ep;
|
||||
goto valid_return;
|
||||
}
|
||||
tep = VM_EP_PREV_EP(tep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfp->ep == target_lep && cfp->iseq->type == ISEQ_TYPE_METHOD) {
|
||||
ep = target_lep;
|
||||
goto valid_return;
|
||||
}
|
||||
|
||||
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
||||
}
|
||||
|
||||
rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
|
||||
|
||||
valid_return:
|
||||
pt = ep;
|
||||
}
|
||||
else {
|
||||
rb_bug("isns(throw): unsupport throw type");
|
||||
}
|
||||
}
|
||||
th->state = state;
|
||||
return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state);
|
||||
return vm_throw_start(th, reg_cfp, state, flag, level, throwobj);
|
||||
}
|
||||
else {
|
||||
/* continue throw */
|
||||
VALUE err = throwobj;
|
||||
|
||||
if (FIXNUM_P(err)) {
|
||||
th->state = FIX2INT(err);
|
||||
}
|
||||
else if (SYMBOL_P(err)) {
|
||||
th->state = TAG_THROW;
|
||||
}
|
||||
else if (BUILTIN_TYPE(err) == T_NODE) {
|
||||
th->state = GET_THROWOBJ_STATE(err);
|
||||
}
|
||||
else {
|
||||
th->state = TAG_RAISE;
|
||||
/*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
|
||||
}
|
||||
return err;
|
||||
return vm_throw_continue(th, throwobj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче