예제 #1
0
파일: signal.c 프로젝트: yugui/ruby
static void
signal_exec(VALUE cmd, int safe, int sig)
{
    rb_thread_t *cur_th = GET_THREAD();
    volatile unsigned long old_interrupt_mask = cur_th->interrupt_mask;
    int state;

    /*
     * workaround the following race:
     * 1. signal_enque queues signal for execution
     * 2. user calls trap(sig, "IGNORE"), setting SIG_IGN
     * 3. rb_signal_exec runs on queued signal
     */
    if (IMMEDIATE_P(cmd))
	return;

    cur_th->interrupt_mask |= TRAP_INTERRUPT_MASK;
    TH_PUSH_TAG(cur_th);
    if ((state = EXEC_TAG()) == 0) {
	VALUE signum = INT2NUM(sig);
	rb_eval_cmd(cmd, rb_ary_new3(1, signum), safe);
    }
    TH_POP_TAG();
    cur_th = GET_THREAD();
    cur_th->interrupt_mask = old_interrupt_mask;

    if (state) {
	/* XXX: should be replaced with rb_threadptr_pending_interrupt_enque() */
	JUMP_TAG(state);
    }
}
예제 #2
0
VALUE
rb_method_call(int argc, VALUE *argv, VALUE method)
{
    VALUE result = Qnil;	/* OK */
    struct METHOD *data;
    int state;
    volatile int safe = -1;

    Data_Get_Struct(method, struct METHOD, data);
    if (data->recv == Qundef) {
	rb_raise(rb_eTypeError, "can't call unbound method; bind first");
    }
    PUSH_TAG();
    if (OBJ_TAINTED(method)) {
	safe = rb_safe_level();
	if (rb_safe_level() < 4) {
	    rb_set_safe_level_force(4);
	}
    }
    if ((state = EXEC_TAG()) == 0) {
	rb_thread_t *th = GET_THREAD();
	VALUE rb_vm_call(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid,
			 int argc, const VALUE *argv, const NODE *body, int nosuper);

	PASS_PASSED_BLOCK_TH(th);
	result = rb_vm_call(th, data->oclass, data->recv, data->id, data->oid,
			    argc, argv, data->body, 0);
    }
    POP_TAG();
    if (safe >= 0)
	rb_set_safe_level_force(safe);
    if (state)
	JUMP_TAG(state);
    return result;
}
예제 #3
0
파일: vm_backtrace.c 프로젝트: sho-h/ruby
VALUE
rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
{
    rb_debug_inspector_t dbg_context;
    rb_thread_t *th = GET_THREAD();
    int state;
    volatile VALUE UNINITIALIZED_VAR(result);

    dbg_context.th = th;
    dbg_context.cfp = dbg_context.th->cfp;
    dbg_context.backtrace = rb_vm_backtrace_location_ary(th, 0, 0);
    dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
    dbg_context.contexts = collect_caller_bindings(th);

    TH_PUSH_TAG(th);
    if ((state = EXEC_TAG()) == 0) {
	result = (*func)(&dbg_context, data);
    }
    TH_POP_TAG();

    /* invalidate bindings? */

    if (state) {
	JUMP_TAG(state);
    }

    return result;
}
예제 #4
0
파일: vm.c 프로젝트: qnighy/ruby-1.9.2p0
VALUE
rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
		  int argc, const VALUE *argv, const rb_block_t * blockptr)
{
    VALUE val = Qundef;
    int state;
    volatile int stored_safe = th->safe_level;

    TH_PUSH_TAG(th);
    if ((state = EXEC_TAG()) == 0) {
	if (!proc->is_from_method) {
	    th->safe_level = proc->safe_level;
	}
	val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0);
    }
    TH_POP_TAG();

    if (!proc->is_from_method) {
	th->safe_level = stored_safe;
    }

    if (state) {
	JUMP_TAG(state);
    }
    return val;
}
예제 #5
0
파일: vm_eval.c 프로젝트: 3runo5ouza/rhodes
static VALUE
rb_f_catch(int argc, VALUE *argv)
{
    VALUE tag;
    int state;
    VALUE val = Qnil;		/* OK */
    rb_thread_t *th = GET_THREAD();
    rb_control_frame_t *saved_cfp = th->cfp;

    if (argc == 0) {
	tag = rb_obj_alloc(rb_cObject);
    }
    else {
	rb_scan_args(argc, argv, "01", &tag);
    }
    PUSH_TAG();

    th->tag->tag = tag;

    if ((state = EXEC_TAG()) == 0) {
	val = rb_yield_0(1, &tag);
    }
    else if (state == TAG_THROW && RNODE(th->errinfo)->u1.value == tag) {
	th->cfp = saved_cfp;
	val = th->tag->retval;
	th->errinfo = Qnil;
	state = 0;
    }
    POP_TAG();
    if (state)
	JUMP_TAG(state);

    return val;
}
예제 #6
0
파일: load.c 프로젝트: Subv/Ruby-Impl
VALUE
rb_require_safe(VALUE fname, int safe)
{
    volatile VALUE result = Qnil;
    rb_thread_t *th = GET_THREAD();
    volatile VALUE errinfo = th->errinfo;
    int state;
    struct {
	int safe;
    } volatile saved;
    char *volatile ftptr = 0;

    PUSH_TAG();
    saved.safe = rb_safe_level();
    if ((state = EXEC_TAG()) == 0) {
	VALUE path;
	long handle;
	int found;

	rb_set_safe_level_force(safe);
	FilePathValue(fname);
	rb_set_safe_level_force(0);
	found = search_required(fname, &path, safe);
	if (found) {
	    if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
		result = Qfalse;
	    }
	    else {
		switch (found) {
		  case 'r':
		    rb_load_internal(path, 0);
		    break;

		  case 's':
		    handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
						    path, 0, path);
		    rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
		    break;
		}
		rb_provide_feature(path);
		result = Qtrue;
	    }
	}
    }
    POP_TAG();
    load_unlock(ftptr, !state);

    rb_set_safe_level_force(saved.safe);
    if (state) {
	JUMP_TAG(state);
    }

    if (NIL_P(result)) {
	load_failed(fname);
    }

    th->errinfo = errinfo;

    return result;
}
예제 #7
0
파일: vm_eval.c 프로젝트: 3runo5ouza/rhodes
VALUE
rb_eval_string_wrap(const char *str, int *state)
{
    int status;
    rb_thread_t *th = GET_THREAD();
    VALUE self = th->top_self;
    VALUE wrapper = th->top_wrapper;
    VALUE val;

    th->top_wrapper = rb_module_new();
    th->top_self = rb_obj_clone(rb_vm_top_self());
    rb_extend_object(th->top_self, th->top_wrapper);

    val = rb_eval_string_protect(str, &status);

    th->top_self = self;
    th->top_wrapper = wrapper;

    if (state) {
	*state = status;
    }
    else if (status) {
	JUMP_TAG(status);
    }
    return val;
}
예제 #8
0
파일: vm_eval.c 프로젝트: 3runo5ouza/rhodes
static VALUE
rb_f_throw(int argc, VALUE *argv)
{
    VALUE tag, value;
    rb_thread_t *th = GET_THREAD();
    struct rb_vm_tag *tt = th->tag;

    rb_scan_args(argc, argv, "11", &tag, &value);
    while (tt) {
	if (tt->tag == tag) {
	    tt->retval = value;
	    break;
	}
	tt = tt->prev;
    }
    if (!tt) {
	VALUE desc = rb_inspect(tag);
	rb_raise(rb_eArgError, "uncaught throw %s", RSTRING_PTR(desc));
    }
    rb_trap_restore_mask();
    th->errinfo = NEW_THROW_OBJECT(tag, 0, TAG_THROW);

    JUMP_TAG(TAG_THROW);
#ifndef __GNUC__
    return Qnil;		/* not reached */
#endif
}
예제 #9
0
VALUE
rb_method_call(int argc, VALUE *argv, VALUE method)
{
    VALUE result = Qnil;	/* OK */
    struct METHOD *data;
    int state;
    volatile int safe = -1;

    Data_Get_Struct(method, struct METHOD, data);
    if (data->recv == Qundef) {
	rb_raise(rb_eTypeError, "can't call unbound method; bind first");
    }
    PUSH_TAG(PROT_NONE);
    if (OBJ_TAINTED(method)) {
	safe = rb_safe_level();
	if (rb_safe_level() < 4) {
	    rb_set_safe_level_force(4);
	}
    }
    if ((state = EXEC_TAG()) == 0) {
	PASS_PASSED_BLOCK();
	result = th_call0(GET_THREAD(),
			  data->klass, data->recv, data->id, data->oid,
			  argc, argv, data->body, 0);
    }
    POP_TAG();
    if (safe >= 0)
	rb_set_safe_level_force(safe);
    if (state)
	JUMP_TAG(state);
    return result;
}
예제 #10
0
파일: vm.c 프로젝트: qnighy/ruby-1.9.2p0
void
rb_vm_jump_tag_but_local_jump(int state, VALUE val)
{
    if (val != Qnil) {
	VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, val);
	rb_exc_raise(exc);
    }
    JUMP_TAG(state);
}
예제 #11
0
파일: load.c 프로젝트: scorpion007/ruby
static void
rb_load_internal(VALUE fname, int wrap)
{
    rb_thread_t *curr_th = GET_THREAD();
    int state = rb_load_internal0(curr_th, fname, wrap);
    if (state) {
	if (state == TAG_RAISE) rb_exc_raise(curr_th->errinfo);
	JUMP_TAG(state);
    }
}
예제 #12
0
파일: load.c 프로젝트: scorpion007/ruby
VALUE
rb_require_safe(VALUE fname, int safe)
{
    int result = rb_require_internal(fname, safe);

    if (result > TAG_RETURN) {
	JUMP_TAG(result);
    }
    if (result < 0) {
	load_failed(fname);
    }

    return result ? Qtrue : Qfalse;
}
예제 #13
0
파일: signal.c 프로젝트: Danylyuk/first_app
static void
signal_exec(VALUE cmd, int safe, int sig)
{
    rb_thread_t *cur_th = GET_THREAD();
    volatile unsigned long old_interrupt_mask = cur_th->interrupt_mask;
    int state;

    cur_th->interrupt_mask |= TRAP_INTERRUPT_MASK;
    TH_PUSH_TAG(cur_th);
    if ((state = EXEC_TAG()) == 0) {
	VALUE signum = INT2NUM(sig);
	rb_eval_cmd(cmd, rb_ary_new3(1, signum), safe);
    }
    TH_POP_TAG();
    cur_th = GET_THREAD();
    cur_th->interrupt_mask = old_interrupt_mask;

    if (state) {
	/* XXX: should be replaced with rb_threadptr_pending_interrupt_enque() */
	JUMP_TAG(state);
    }
}
예제 #14
0
파일: vm_trace.c 프로젝트: ksperling/ruby
VALUE
rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg)
{
    volatile int raised;
    volatile int outer_state;
    VALUE result = Qnil;
    rb_thread_t *th = GET_THREAD();
    int state;
    const int tracing = th->trace_arg ? 1 : 0;
    rb_trace_arg_t dummy_trace_arg;
    dummy_trace_arg.event = 0;

    if (!tracing) th->vm->trace_running++;
    if (!th->trace_arg) th->trace_arg = &dummy_trace_arg;

    raised = rb_threadptr_reset_raised(th);
    outer_state = th->state;
    th->state = 0;

    TH_PUSH_TAG(th);
    if ((state = TH_EXEC_TAG()) == 0) {
        result = (*func)(arg);
    }
    TH_POP_TAG();

    if (raised) {
        rb_threadptr_set_raised(th);
    }

    if (th->trace_arg == &dummy_trace_arg) th->trace_arg = 0;
    if (!tracing) th->vm->trace_running--;

    if (state) {
        JUMP_TAG(state);
    }

    th->state = outer_state;
    return result;
}
예제 #15
0
파일: vm_eval.c 프로젝트: 3runo5ouza/rhodes
VALUE
rb_eval_cmd(VALUE cmd, VALUE arg, int level)
{
    int state;
    VALUE val = Qnil;		/* OK */
    volatile int safe = rb_safe_level();

    if (OBJ_TAINTED(cmd)) {
	level = 4;
    }

    if (TYPE(cmd) != T_STRING) {
	PUSH_TAG();
	rb_set_safe_level_force(level);
	if ((state = EXEC_TAG()) == 0) {
	    val = rb_funcall2(cmd, rb_intern("call"), RARRAY_LEN(arg),
			      RARRAY_PTR(arg));
	}
	POP_TAG();

	rb_set_safe_level_force(safe);

	if (state)
	  JUMP_TAG(state);
	return val;
    }

    PUSH_TAG();
    if ((state = EXEC_TAG()) == 0) {
	val = eval_string(rb_vm_top_self(), cmd, Qnil, 0, 0);
    }
    POP_TAG();

    rb_set_safe_level_force(safe);
    if (state) rb_vm_jump_tag_but_local_jump(state, val);
    return val;
}
예제 #16
0
파일: vm_eval.c 프로젝트: 3runo5ouza/rhodes
/*RHO static*/ VALUE
eval_string_with_cref(VALUE self, VALUE src, VALUE scope, NODE *cref, const char *file, int line)
{
    int state;
    VALUE result = Qundef;
    VALUE envval;
    rb_binding_t *bind = 0;
    rb_thread_t *th = GET_THREAD();
    rb_env_t *env = NULL;
    rb_block_t block;
    volatile int parse_in_eval;
    volatile int mild_compile_error;

    if (file == 0) {
	file = rb_sourcefile();
	line = rb_sourceline();
    }

    parse_in_eval = th->parse_in_eval;
    mild_compile_error = th->mild_compile_error;
    PUSH_TAG();
    if ((state = EXEC_TAG()) == 0) {
	rb_iseq_t *iseq;
	volatile VALUE iseqval;

	if (scope != Qnil) {
	    if (rb_obj_is_kind_of(scope, rb_cBinding)) {
		GetBindingPtr(scope, bind);
		envval = bind->env;
	    }
	    else {
		rb_raise(rb_eTypeError,
			 "wrong argument type %s (expected Binding)",
			 rb_obj_classname(scope));
	    }
	    GetEnvPtr(envval, env);
	    th->base_block = &env->block;
	}
	else {
	    rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);

	    if (cfp != 0) {
		block = *RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
		th->base_block = &block;
		th->base_block->self = self;
		th->base_block->iseq = cfp->iseq;	/* TODO */
	    }
	    else {
		rb_raise(rb_eRuntimeError, "Can't eval on top of Fiber or Thread");
	    }
	}

    //RHO
    if ( TYPE(src) != T_STRING ){
        iseqval = src;
    }else
    //RHO
    {
	    /* make eval iseq */
	    th->parse_in_eval++;
	    th->mild_compile_error++;
	    iseqval = rb_iseq_compile(src, rb_str_new2(file), INT2FIX(line));
	    th->mild_compile_error--;
	    th->parse_in_eval--;
    }

	vm_set_eval_stack(th, iseqval, cref);
	th->base_block = 0;

	if (0) {		/* for debug */
	    printf("%s\n", RSTRING_PTR(rb_iseq_disasm(iseqval)));
	}

	/* save new env */
	GetISeqPtr(iseqval, iseq);
	if (bind && iseq->local_size > 0) {
	    bind->env = rb_vm_make_env_object(th, th->cfp);
	}

	/* kick */
	CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
	result = vm_exec(th);
    }
    POP_TAG();
    th->mild_compile_error = mild_compile_error;
    th->parse_in_eval = parse_in_eval;

    if (state) {
	if (state == TAG_RAISE) {
	    VALUE errinfo = th->errinfo;
	    if (strcmp(file, "(eval)") == 0) {
		VALUE mesg, errat, bt2;
		extern VALUE rb_get_backtrace(VALUE info);
		ID id_mesg;

		CONST_ID(id_mesg, "mesg");
		errat = rb_get_backtrace(errinfo);
		mesg = rb_attr_get(errinfo, id_mesg);
		if (!NIL_P(errat) && TYPE(errat) == T_ARRAY &&
		    (bt2 = vm_backtrace(th, -2), RARRAY_LEN(bt2) > 0)) {
		    if (!NIL_P(mesg) && TYPE(mesg) == T_STRING && !RSTRING_LEN(mesg)) {
			if (OBJ_FROZEN(mesg)) {
			    VALUE m = rb_str_cat(rb_str_dup(RARRAY_PTR(errat)[0]), ": ", 2);
			    rb_ivar_set(errinfo, id_mesg, rb_str_append(m, mesg));
			}
			else {
			    rb_str_update(mesg, 0, 0, rb_str_new2(": "));
			    rb_str_update(mesg, 0, 0, RARRAY_PTR(errat)[0]);
			}
		    }
		    RARRAY_PTR(errat)[0] = RARRAY_PTR(bt2)[0];
		}
	    }
	    rb_exc_raise(errinfo);
	}
	JUMP_TAG(state);
    }
    return result;
}
예제 #17
0
파일: vm.c 프로젝트: qnighy/ruby-1.9.2p0
static VALUE
vm_exec(rb_thread_t *th)
{
    int state;
    VALUE result, err;
    VALUE initial = 0;
    VALUE *escape_dfp = NULL;

    TH_PUSH_TAG(th);
    _tag.retval = Qnil;
    if ((state = EXEC_TAG()) == 0) {
      vm_loop_start:
	result = vm_exec_core(th, initial);
	if ((state = th->state) != 0) {
	    err = result;
	    th->state = 0;
	    goto exception_handler;
	}
    }
    else {
	int i;
	struct iseq_catch_table_entry *entry;
	unsigned long epc, cont_pc, cont_sp;
	VALUE catch_iseqval;
	rb_control_frame_t *cfp;
	VALUE type;

	err = th->errinfo;

      exception_handler:
	cont_pc = cont_sp = catch_iseqval = 0;

	while (th->cfp->pc == 0 || th->cfp->iseq == 0) {
	    if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) {
		const rb_method_entry_t *me = th->cfp->me;
		EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass);
	    }
	    th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
	}

	cfp = th->cfp;
	epc = cfp->pc - cfp->iseq->iseq_encoded;

	if (state == TAG_BREAK || state == TAG_RETURN) {
	    escape_dfp = GET_THROWOBJ_CATCH_POINT(err);

	    if (cfp->dfp == escape_dfp) {
		if (state == TAG_RETURN) {
		    if ((cfp + 1)->pc != &finish_insn_seq[0]) {
			SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)->dfp);
			SET_THROWOBJ_STATE(err, state = TAG_BREAK);
		    }
		    else {
			for (i = 0; i < cfp->iseq->catch_table_size; i++) {
			    entry = &cfp->iseq->catch_table[i];
			    if (entry->start < epc && entry->end >= epc) {
				if (entry->type == CATCH_TYPE_ENSURE) {
				    catch_iseqval = entry->iseq;
				    cont_pc = entry->cont;
				    cont_sp = entry->sp;
				    break;
				}
			    }
			}
			if (!catch_iseqval) {
			    result = GET_THROWOBJ_VAL(err);
			    th->errinfo = Qnil;
			    th->cfp += 2;
			    goto finish_vme;
			}
		    }
		    /* through */
		}
		else {
		    /* TAG_BREAK */
#if OPT_STACK_CACHING
		    initial = (GET_THROWOBJ_VAL(err));
#else
		    *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
#endif
		    th->errinfo = Qnil;
		    goto vm_loop_start;
		}
	    }
	}

	if (state == TAG_RAISE) {
	    for (i = 0; i < cfp->iseq->catch_table_size; i++) {
		entry = &cfp->iseq->catch_table[i];
		if (entry->start < epc && entry->end >= epc) {

		    if (entry->type == CATCH_TYPE_RESCUE ||
			entry->type == CATCH_TYPE_ENSURE) {
			catch_iseqval = entry->iseq;
			cont_pc = entry->cont;
			cont_sp = entry->sp;
			break;
		    }
		}
	    }
	}
	else if (state == TAG_RETRY) {
	    for (i = 0; i < cfp->iseq->catch_table_size; i++) {
		entry = &cfp->iseq->catch_table[i];
		if (entry->start < epc && entry->end >= epc) {

		    if (entry->type == CATCH_TYPE_ENSURE) {
			catch_iseqval = entry->iseq;
			cont_pc = entry->cont;
			cont_sp = entry->sp;
			break;
		    }
		    else if (entry->type == CATCH_TYPE_RETRY) {
			VALUE *escape_dfp;
			escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
			if (cfp->dfp == escape_dfp) {
			    cfp->pc = cfp->iseq->iseq_encoded + entry->cont;
			    th->errinfo = Qnil;
			    goto vm_loop_start;
			}
		    }
		}
	    }
	}
	else if (state == TAG_BREAK && ((VALUE)escape_dfp & ~0x03) == 0) {
	    type = CATCH_TYPE_BREAK;

	  search_restart_point:
	    for (i = 0; i < cfp->iseq->catch_table_size; i++) {
		entry = &cfp->iseq->catch_table[i];

		if (entry->start < epc && entry->end >= epc) {
		    if (entry->type == CATCH_TYPE_ENSURE) {
			catch_iseqval = entry->iseq;
			cont_pc = entry->cont;
			cont_sp = entry->sp;
			break;
		    }
		    else if (entry->type == type) {
			cfp->pc = cfp->iseq->iseq_encoded + entry->cont;
			cfp->sp = cfp->bp + entry->sp;

			if (state != TAG_REDO) {
#if OPT_STACK_CACHING
			    initial = (GET_THROWOBJ_VAL(err));
#else
			    *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
#endif
			}
			th->errinfo = Qnil;
			goto vm_loop_start;
		    }
		}
	    }
	}
	else if (state == TAG_REDO) {
	    type = CATCH_TYPE_REDO;
	    goto search_restart_point;
	}
	else if (state == TAG_NEXT) {
	    type = CATCH_TYPE_NEXT;
	    goto search_restart_point;
	}
	else {
	    for (i = 0; i < cfp->iseq->catch_table_size; i++) {
		entry = &cfp->iseq->catch_table[i];
		if (entry->start < epc && entry->end >= epc) {

		    if (entry->type == CATCH_TYPE_ENSURE) {
			catch_iseqval = entry->iseq;
			cont_pc = entry->cont;
			cont_sp = entry->sp;
			break;
		    }
		}
	    }
	}

	if (catch_iseqval != 0) {
	    /* found catch table */
	    rb_iseq_t *catch_iseq;

	    /* enter catch scope */
	    GetISeqPtr(catch_iseqval, catch_iseq);
	    cfp->sp = cfp->bp + cont_sp;
	    cfp->pc = cfp->iseq->iseq_encoded + cont_pc;

	    /* push block frame */
	    cfp->sp[0] = err;
	    vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK,
			  cfp->self, (VALUE)cfp->dfp, catch_iseq->iseq_encoded,
			  cfp->sp + 1 /* push value */, cfp->lfp, catch_iseq->local_size - 1);

	    state = 0;
	    th->state = 0;
	    th->errinfo = Qnil;
	    goto vm_loop_start;
	}
	else {
	    /* skip frame */

	    switch (VM_FRAME_TYPE(th->cfp)) {
	      case VM_FRAME_MAGIC_METHOD:
		EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0);
		break;
	      case VM_FRAME_MAGIC_CLASS:
		EXEC_EVENT_HOOK(th, RUBY_EVENT_END, th->cfp->self, 0, 0);
		break;
	    }

	    th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);

	    if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_FINISH) {
		goto exception_handler;
	    }
	    else {
		vm_pop_frame(th);
		th->errinfo = err;
		TH_POP_TAG2();
		JUMP_TAG(state);
	    }
	}
    }
  finish_vme:
    TH_POP_TAG();
    return result;
}