Esempio n. 1
0
VALUE
yarv_invoke_Integer_times_special_block(VALUE num)
{
    rb_thread_t *th = GET_THREAD();
    rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);

    if (orig_block && BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
	VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq,
						  build_Integer_times_node);
	rb_iseq_t *tsiseq;
	VALUE argv[2], val;

	if (tsiseqval) {
	    rb_block_t block = *orig_block;
	    GetISeqPtr(tsiseqval, tsiseq);
	    block.iseq = tsiseq;
	    th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
	    argv[0] = INT2FIX(0);
	    argv[1] = num;
	    val = th_invoke_yield(th, 2, argv);
	    if (val == Qundef) {
		return num;
	    }
	    else {
		return val;
	    }
	}
    }
    return Qundef;
}
Esempio n. 2
0
VALUE
yarv_invoke_Range_each_special_block(VALUE range,
				     VALUE beg, VALUE end, int excl)
{
    rb_thread_t *th = GET_THREAD();
    rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);

    if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
	void *builder =
	    excl ? build_Range_each_node_LT : build_Range_each_node_LE;
	VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, builder);
	rb_iseq_t *tsiseq;
	VALUE argv[2];

	if (tsiseqval) {
	    VALUE val;
	    rb_block_t block = *orig_block;
	    GetISeqPtr(tsiseqval, tsiseq);
	    block.iseq = tsiseq;
	    th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
	    argv[0] = beg;
	    argv[1] = end;
	    val = th_invoke_yield(th, 2, argv);
	    if (val == Qundef) {
		return range;
	    }
	    else {
		return val;
	    }
	}
    }
    return Qundef;
}
Esempio n. 3
0
VALUE
yarv_invoke_Array_each_special_block(VALUE ary)
{
    rb_thread_t *th = GET_THREAD();
    rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);

    if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
	VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq,
						  build_Array_each_node);
	rb_iseq_t *tsiseq;
	VALUE argv[2];

	if (tsiseqval) {
	    VALUE val;
	    rb_block_t block = *orig_block;
	    GetISeqPtr(tsiseqval, tsiseq);
	    block.iseq = tsiseq;
	    th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
	    argv[0] = 0;
	    argv[1] = ary;
	    val = th_invoke_yield(th, 2, argv);
	    if (val == Qundef) {
		return ary;
	    }
	    else {
		return val;
	    }
	}
    }
    return Qundef;
}
Esempio n. 4
0
int
rb_node_arity(NODE* body)
{
    switch (nd_type(body)) {
      case NODE_CFUNC:
	if (body->nd_argc < 0)
	    return -1;
	return body->nd_argc;
      case NODE_ZSUPER:
	return -1;
      case NODE_ATTRSET:
	return 1;
      case NODE_IVAR:
	return 0;
      case NODE_BMETHOD:
	return rb_proc_arity(body->nd_cval);
      case RUBY_VM_METHOD_NODE:
	{
	    rb_iseq_t *iseq;
	    GetISeqPtr((VALUE)body->nd_body, iseq);
	    if (iseq->arg_rest == -1 && iseq->arg_opts == 0) {
		return iseq->argc;
	    }
	    else {
		return -(iseq->argc + 1 + iseq->arg_post_len);
	    }
	}
      default:
	rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body));
    }
}
Esempio n. 5
0
static void
vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
		 rb_num_t is_singleton, NODE *cref)
{
    VALUE klass = cref->nd_clss;
    int noex = (int)cref->nd_visi;
    rb_iseq_t *miseq;
    GetISeqPtr(iseqval, miseq);

    if (miseq->klass) {
	iseqval = rb_iseq_clone(iseqval, 0);
	RB_GC_GUARD(iseqval);
	GetISeqPtr(iseqval, miseq);
    }

    if (NIL_P(klass)) {
	rb_raise(rb_eTypeError, "no class/module to add method");
    }

    if (is_singleton) {
	if (FIXNUM_P(obj) || SYMBOL_P(obj)) {
	    rb_raise(rb_eTypeError,
		     "can't define singleton method \"%s\" for %s",
		     rb_id2name(id), rb_obj_classname(obj));
	}

	rb_check_frozen(obj);
	klass = rb_singleton_class(obj);
	noex = NOEX_PUBLIC;
    }

    /* dup */
    COPY_CREF(miseq->cref_stack, cref);
    miseq->cref_stack->nd_visi = NOEX_PUBLIC;
    miseq->klass = klass;
    miseq->defined_method_id = id;
    rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);

    if (!is_singleton && noex == NOEX_MODFUNC) {
	rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
    }
    INC_VM_STATE_VERSION();
}
Esempio n. 6
0
static inline void
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
		const int argc, const rb_block_t *blockptr, const VALUE flag,
		const VALUE iseqval, const VALUE recv)
{
    rb_iseq_t *iseq;
    int opt_pc, i;
    VALUE *sp, *rsp = cfp->sp - argc;

    /* TODO: eliminate it */
    GetISeqPtr(iseqval, iseq);
    VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, rsp, &blockptr);

    /* stack overflow check */
    CHECK_STACK_OVERFLOW(cfp, iseq->stack_max);

    sp = rsp + iseq->arg_size;

    if (LIKELY(!(flag & VM_CALL_TAILCALL_BIT))) {
	if (0) printf("local_size: %d, arg_size: %d\n",
		      iseq->local_size, iseq->arg_size);

	/* clear local variables */
	for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
	    *sp++ = Qnil;
	}

	vm_push_frame(th, iseq,
		      VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
		      iseq->iseq_encoded + opt_pc, sp, 0, 0);

	cfp->sp = rsp - 1 /* recv */;
    }
    else {
	VALUE *p_rsp;
	th->cfp++; /* pop cf */
	p_rsp = th->cfp->sp;

	/* copy arguments */
	for (i=0; i < (sp - rsp); i++) {
	    p_rsp[i] = rsp[i];
	}

	sp -= rsp - p_rsp;

	/* clear local variables */
	for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
	    *sp++ = Qnil;
	}

	vm_push_frame(th, iseq,
		      VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
		      iseq->iseq_encoded + opt_pc, sp, 0, 0);
    }
}
Esempio n. 7
0
static void
clone_method(VALUE klass, ID mid, const rb_method_entry_t *me)
{
    VALUE newiseqval;
    if (me->def && me->def->type == VM_METHOD_TYPE_ISEQ) {
	rb_iseq_t *iseq;
	newiseqval = rb_iseq_clone(me->def->body.iseq->self, klass);
	GetISeqPtr(newiseqval, iseq);
	OBJ_WRITE(iseq->self, &iseq->cref_stack, rewrite_cref_stack(me->def->body.iseq->cref_stack, me->klass, klass));
	rb_add_method(klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag);
	RB_GC_GUARD(newiseqval);
    }
    else {
	rb_method_entry_set(klass, mid, me, me->flag);
    }
}
Esempio n. 8
0
File: class.c Progetto: fi8on/ruby
static int
clone_method(ID mid, const rb_method_entry_t *me, struct clone_method_data *data)
{
    VALUE newiseqval;
    if (me->def && me->def->type == VM_METHOD_TYPE_ISEQ) {
	rb_iseq_t *iseq;
	newiseqval = rb_iseq_clone(me->def->body.iseq->self, data->klass);
	GetISeqPtr(newiseqval, iseq);
	rb_add_method(data->klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag);
	RB_GC_GUARD(newiseqval);
    }
    else {
	rb_method_entry_set(data->klass, mid, me, me->flag);
    }
    return ST_CONTINUE;
}
Esempio n. 9
0
static int
clone_method(ID mid, const rb_method_entry_t *me, struct clone_method_data *data)
{
    switch (me->type) {
      case VM_METHOD_TYPE_ISEQ: {
	  VALUE newiseqval = rb_iseq_clone(me->body.iseq->self, data->klass);
	  rb_iseq_t *iseq;
	  GetISeqPtr(newiseqval, iseq);
	  rb_add_method(data->klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag);
	  break;
      }
      default:
	rb_add_method_me(data->klass, mid, me, me->flag);
	break;
    }
    return ST_CONTINUE;
}
Esempio n. 10
0
/* From iseq.c */
static rb_iseq_t *
iseq_check(VALUE val)
{
  rb_iseq_t *iseq;
  if(!rb_obj_is_kind_of(val, rb_cISeq))
  {
    rb_raise(
        rb_eTypeError,
        "Expected VM::InstructionSequence, but got %s",
        rb_class2name(CLASS_OF(val)));
  }
  GetISeqPtr(val, iseq);
  if (!iseq->name) {
    rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
  }
  return iseq;
}
Esempio n. 11
0
static rb_iseq_t *
get_method_iseq(VALUE method)
{
    struct METHOD *data;
    NODE *body;
    rb_iseq_t *iseq;

    Data_Get_Struct(method, struct METHOD, data);
    body = data->body;
    switch (nd_type(body)) {
      case RUBY_VM_METHOD_NODE:
	GetISeqPtr((VALUE)body->nd_body, iseq);
	if (RUBY_VM_NORMAL_ISEQ_P(iseq)) break;
      default:
	return 0;
    }
    return iseq;
}
Esempio n. 12
0
static void
vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
{
    rb_iseq_t *iseq;
    GetISeqPtr(iseqval, iseq);

    if (iseq->type != ISEQ_TYPE_TOP) {
	rb_raise(rb_eTypeError, "Not a toplevel InstructionSequence");
    }

    /* for return */
    rb_vm_set_finish_env(th);

    vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP,
		  th->top_self, 0, iseq->iseq_encoded,
		  th->cfp->sp, 0, iseq->local_size);

    CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
}
Esempio n. 13
0
static void
vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref)
{
    rb_iseq_t *iseq;
    rb_block_t * const block = th->base_block;
    GetISeqPtr(iseqval, iseq);

    /* for return */
    rb_vm_set_finish_env(th);
    vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self,
		  GC_GUARDED_PTR(block->dfp), iseq->iseq_encoded,
		  th->cfp->sp, block->lfp, iseq->local_size);

    if (cref) {
	th->cfp->dfp[-1] = (VALUE)cref;
    }

    CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
}
Esempio n. 14
0
int
rb_node_arity(NODE* body)
{
    int n;

    switch (nd_type(body)) {
    case NODE_CFUNC:
	if (body->nd_argc < 0)
	    return -1;
	return body->nd_argc;
    case NODE_ZSUPER:
	return -1;
    case NODE_ATTRSET:
	return 1;
    case NODE_IVAR:
	return 0;
    case NODE_BMETHOD:
	return rb_proc_arity(body->nd_cval);
    case NODE_SCOPE:
	body = body->nd_next;	/* skip NODE_SCOPE */
	if (nd_type(body) == NODE_BLOCK)
	    body = body->nd_head;
	if (!body)
	    return 0;
	n = body->nd_frml ? RARRAY_LEN(body->nd_frml) : 0;
	if (body->nd_opt || body->nd_rest)
	    n = -n - 1;
	return n;
    case RUBY_VM_METHOD_NODE:{
	    rb_iseq_t *iseq;
	    GetISeqPtr((VALUE)body->nd_body, iseq);
	    if (iseq->arg_rest == 0 && iseq->arg_opts == 0) {
		return iseq->argc;
	    }
	    else {
		return -iseq->argc - 1;
	    }
	}
    default:
	rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body));
    }
}
Esempio n. 15
0
static void
vm_set_main_stack(rb_thread_t *th, VALUE iseqval)
{
    VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
    rb_binding_t *bind;
    rb_iseq_t *iseq;
    rb_env_t *env;

    GetBindingPtr(toplevel_binding, bind);
    GetEnvPtr(bind->env, env);
    th->base_block = &env->block;
    vm_set_eval_stack(th, iseqval, 0);
    th->base_block = 0;

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

    CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
/*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;
}