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; }
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; }
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); } }
void rb_postponed_job_flush(rb_vm_t *vm) { rb_thread_t *th = GET_THREAD(); unsigned long saved_postponed_job_interrupt_mask = th->interrupt_mask & POSTPONED_JOB_INTERRUPT_MASK; VALUE saved_errno = th->errinfo; th->errinfo = Qnil; /* mask POSTPONED_JOB dispatch */ th->interrupt_mask |= POSTPONED_JOB_INTERRUPT_MASK; { TH_PUSH_TAG(th); EXEC_TAG(); { int index; while ((index = vm->postponed_job_index) > 0) { if (ATOMIC_CAS(vm->postponed_job_index, index, index-1) == index) { rb_postponed_job_t *pjob = &vm->postponed_job_buffer[index-1]; (*pjob->func)(pjob->data); } } } TH_POP_TAG(); } /* restore POSTPONED_JOB mask */ th->interrupt_mask &= ~(saved_postponed_job_interrupt_mask ^ POSTPONED_JOB_INTERRUPT_MASK); th->errinfo = saved_errno; }
/** Destructs the VM. * * Runs the VM finalization processes as well as ruby_finalize(), and frees * resources used by the VM. * * @param ex Default value to the return value. * @return If an error occurred returns a non-zero. If otherwise, returns the * given ex. * @note This function does not raise any exception. */ int ruby_cleanup(volatile int ex) { int state; volatile VALUE errs[2]; rb_thread_t *th = GET_THREAD(); int nerr; rb_threadptr_interrupt(th); rb_threadptr_check_signal(th); TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { SAVE_ROOT_JMPBUF(th, { RUBY_VM_CHECK_INTS(th); });
void rb_fiber_start(void) { rb_thread_t *th = GET_THREAD(); rb_fiber_t *fib; rb_context_t *cont; rb_proc_t *proc; int state; GetFiberPtr(th->fiber, fib); cont = &fib->cont; TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { int argc; VALUE *argv, args; GetProcPtr(cont->saved_thread.first_proc, proc); args = cont->value; argv = (argc = cont->argc) > 1 ? RARRAY_PTR(args) : &args; cont->value = Qnil; th->errinfo = Qnil; th->local_lfp = proc->block.lfp; th->local_svar = Qnil; fib->status = RUNNING; cont->value = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, 0); } TH_POP_TAG(); if (state) { if (TAG_RAISE) { th->thrown_errinfo = th->errinfo; } else { th->thrown_errinfo = rb_vm_make_jump_tag_but_local_jump(state, th->errinfo); } RUBY_VM_SET_INTERRUPT(th); } rb_fiber_terminate(fib); rb_bug("rb_fiber_start: unreachable"); }
void rb_threadptr_error_print(rb_thread_t *volatile th, volatile VALUE errinfo) { volatile VALUE errat = Qundef; volatile int raised_flag = th->raised_flag; volatile VALUE eclass = Qundef, emesg = Qundef; if (NIL_P(errinfo)) return; rb_thread_raised_clear(th); TH_PUSH_TAG(th); if (TH_EXEC_TAG() == 0) { errat = rb_get_backtrace(errinfo); } else if (errat == Qundef) { errat = Qnil; } else if (eclass == Qundef || emesg != Qundef) { goto error; } if ((eclass = CLASS_OF(errinfo)) != Qundef) { VALUE e = rb_check_funcall(errinfo, rb_intern("message"), 0, 0); if (e != Qundef) { if (!RB_TYPE_P(e, T_STRING)) e = rb_check_string_type(e); emesg = e; } } if (rb_stderr_tty_p()) { if (0) warn_print("Traceback (most recent call last):\n"); print_backtrace(eclass, errat, TRUE); print_errinfo(eclass, errat, emesg); } else { print_errinfo(eclass, errat, emesg); print_backtrace(eclass, errat, FALSE); } error: TH_POP_TAG(); th->errinfo = errinfo; rb_thread_raised_set(th, raised_flag); }
static inline VALUE vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, int num, ID id, ID oid, VALUE recv, VALUE klass, VALUE flag, const NODE *mn, const rb_block_t *blockptr) { VALUE val = 0; int state = 0; EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); TH_PUSH_TAG(th); if (th->event_flags & RUBY_EVENT_C_RETURN) { state = TH_EXEC_TAG(); } else { _th->tag = _tag.prev; } if (state == 0) { rb_control_frame_t *cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1); cfp->method_id = oid; cfp->method_class = klass; reg_cfp->sp -= num + 1; val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1); if (reg_cfp != th->cfp + 1) { rb_bug("cfp consistency error - send"); } vm_pop_frame(th); } TH_POP_TAG(); EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); if (state) TH_JUMP_TAG(th, state); return val; }
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; }
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); } }
void rb_fiber_start(void) { rb_thread_t *th = GET_THREAD(); rb_context_t *cont; rb_proc_t *proc; VALUE args; int state; GetContPtr(th->fiber, cont); TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { GetProcPtr(cont->saved_thread.first_proc, proc); args = cont->value; cont->value = Qnil; th->errinfo = Qnil; th->local_lfp = proc->block.lfp; th->local_svar = Qnil; cont->value = vm_invoke_proc(th, proc, proc->block.self, 1, &args, 0); } TH_POP_TAG(); if (state) { if (TAG_RAISE) { th->thrown_errinfo = th->errinfo; } else { th->thrown_errinfo = vm_make_jump_tag_but_local_jump(state, th->errinfo); } RUBY_VM_SET_INTERRUPT(th); } rb_fiber_terminate(cont); rb_bug("rb_fiber_start: unreachable"); }
static int exec_hooks(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg, int can_clean_hooks) { int state; volatile int raised; if (UNLIKELY(list->need_clean > 0) && can_clean_hooks) { clean_hooks(list); } raised = rb_threadptr_reset_raised(th); /* TODO: Support !RUBY_EVENT_HOOK_FLAG_SAFE hooks */ TH_PUSH_TAG(th); if ((state = TH_EXEC_TAG()) == 0) { rb_event_hook_t *hook; for (hook = list->hooks; hook; hook = hook->next) { if (LIKELY(!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED)) && (trace_arg->event & hook->events)) { if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_RAW_ARG)) { (*hook->func)(trace_arg->event, hook->data, trace_arg->self, trace_arg->id, trace_arg->klass); } else { (*((rb_event_hook_raw_arg_func_t)hook->func))(hook->data, trace_arg); } } } } TH_POP_TAG(); if (raised) { rb_threadptr_set_raised(th); } return state; }
static int exec_hooks_protected(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg) { int state; volatile int raised; if (exec_hooks_precheck(th, list, trace_arg) == 0) return 0; raised = rb_threadptr_reset_raised(th); /* TODO: Support !RUBY_EVENT_HOOK_FLAG_SAFE hooks */ TH_PUSH_TAG(th); if ((state = TH_EXEC_TAG()) == 0) { exec_hooks_body(th, list, trace_arg); } TH_POP_TAG(); if (raised) { rb_threadptr_set_raised(th); } return state; }
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; }
void rb_threadptr_error_print(rb_thread_t *th, VALUE errinfo) { volatile VALUE errat = Qundef; int raised_flag = th->raised_flag; volatile VALUE eclass = Qundef, e = Qundef; const char *volatile einfo; volatile long elen; VALUE mesg; if (NIL_P(errinfo)) return; rb_thread_raised_clear(th); TH_PUSH_TAG(th); if (TH_EXEC_TAG() == 0) { errat = rb_get_backtrace(errinfo); } else if (errat == Qundef) { errat = Qnil; } else if (eclass == Qundef || e != Qundef) { goto error; } else { goto no_message; } if (NIL_P(errat) || RARRAY_LEN(errat) == 0 || NIL_P(mesg = RARRAY_AREF(errat, 0))) { error_pos(); } else { warn_print_str(mesg); warn_print(": "); } eclass = CLASS_OF(errinfo); if (eclass != Qundef && (e = rb_check_funcall(errinfo, rb_intern("message"), 0, 0)) != Qundef && (RB_TYPE_P(e, T_STRING) || !NIL_P(e = rb_check_string_type(e)))) { einfo = RSTRING_PTR(e); elen = RSTRING_LEN(e); } else { no_message: einfo = ""; elen = 0; } if (eclass == rb_eRuntimeError && elen == 0) { warn_print("unhandled exception\n"); } else { VALUE epath; epath = rb_class_name(eclass); if (elen == 0) { warn_print_str(epath); warn_print("\n"); } else { const char *tail = 0; long len = elen; if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { len = tail - einfo; tail++; /* skip newline */ } warn_print_str(tail ? rb_str_subseq(e, 0, len) : e); if (epath) { warn_print(" ("); warn_print_str(epath); warn_print(")\n"); } if (tail) { warn_print_str(rb_str_subseq(e, tail - einfo, elen - len - 1)); } if (tail ? einfo[elen-1] != '\n' : !epath) warn_print2("\n", 1); } } if (!NIL_P(errat)) { long i; long len = RARRAY_LEN(errat); int skip = eclass == rb_eSysStackError; #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) #define TRACE_HEAD 8 #define TRACE_TAIL 5 for (i = 1; i < len; i++) { VALUE line = RARRAY_AREF(errat, i); if (RB_TYPE_P(line, T_STRING)) { warn_print_str(rb_sprintf("\tfrom %"PRIsVALUE"\n", line)); } if (skip && i == TRACE_HEAD && len > TRACE_MAX) { warn_print_str(rb_sprintf("\t ... %ld levels...\n", len - TRACE_HEAD - TRACE_TAIL)); i = len - TRACE_TAIL; } } } error: TH_POP_TAG(); th->errinfo = errinfo; rb_thread_raised_set(th, raised_flag); }
/* * returns * 0: if already loaded (false) * 1: successfully loaded (true) * <0: not found (LoadError) * >1: exception */ int rb_require_internal(VALUE fname, int safe) { volatile int result = -1; rb_thread_t *th = GET_THREAD(); volatile VALUE errinfo = th->errinfo; int state; struct { int safe; } volatile saved; char *volatile ftptr = 0; if (RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) { RUBY_DTRACE_REQUIRE_ENTRY(StringValuePtr(fname), rb_sourcefile(), rb_sourceline()); } TH_PUSH_TAG(th); 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); if (RUBY_DTRACE_FIND_REQUIRE_ENTRY_ENABLED()) { RUBY_DTRACE_FIND_REQUIRE_ENTRY(StringValuePtr(fname), rb_sourcefile(), rb_sourceline()); } path = rb_str_encode_ospath(fname); found = search_required(path, &path, safe); if (RUBY_DTRACE_FIND_REQUIRE_RETURN_ENABLED()) { RUBY_DTRACE_FIND_REQUIRE_RETURN(StringValuePtr(fname), rb_sourcefile(), rb_sourceline()); } if (found) { if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) { result = 0; } else if (!*ftptr) { rb_provide_feature(path); result = TAG_RETURN; } 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 = TAG_RETURN; } } } TH_POP_TAG(); load_unlock(ftptr, !state); rb_set_safe_level_force(saved.safe); if (state) { /* never TAG_RETURN */ return state; } th->errinfo = errinfo; if (RUBY_DTRACE_REQUIRE_RETURN_ENABLED()) { RUBY_DTRACE_REQUIRE_RETURN(StringValuePtr(fname), rb_sourcefile(), rb_sourceline()); } return result; }
static int rb_load_internal0(rb_thread_t *th, VALUE fname, int wrap) { int state; volatile VALUE wrapper = th->top_wrapper; volatile VALUE self = th->top_self; volatile int loaded = FALSE; volatile int mild_compile_error; #if !defined __GNUC__ rb_thread_t *volatile th0 = th; #endif th->errinfo = Qnil; /* ensure */ if (!wrap) { th->top_wrapper = 0; } else { /* load in anonymous module as toplevel */ th->top_self = rb_obj_clone(rb_vm_top_self()); th->top_wrapper = rb_module_new(); rb_extend_object(th->top_self, th->top_wrapper); } mild_compile_error = th->mild_compile_error; TH_PUSH_TAG(th); state = EXEC_TAG(); if (state == 0) { NODE *node; rb_iseq_t *iseq; th->mild_compile_error++; node = (NODE *)rb_load_file_str(fname); loaded = TRUE; iseq = rb_iseq_new_top(node, rb_str_new2("<top (required)>"), fname, rb_realpath_internal(Qnil, fname, 1), NULL); th->mild_compile_error--; rb_iseq_eval(iseq); } TH_POP_TAG(); #if !defined __GNUC__ th = th0; fname = RB_GC_GUARD(fname); #endif th->mild_compile_error = mild_compile_error; th->top_self = self; th->top_wrapper = wrapper; if (!loaded && !FIXNUM_P(th->errinfo)) { /* an error on loading don't include INT2FIX(TAG_FATAL) see r35625 */ return TAG_RAISE; } if (state) { VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef); if (NIL_P(exc)) return state; th->errinfo = exc; return TAG_RAISE; } if (!NIL_P(th->errinfo)) { /* exception during load */ return TAG_RAISE; } return state; }
VALUE rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1, VALUE (* bl_proc) (ANYARGS), VALUE data2) { int state; volatile VALUE retval = Qnil; NODE *node = NEW_IFUNC(bl_proc, data2); rb_thread_t *th = GET_THREAD(); rb_control_frame_t *cfp = th->cfp; TH_PUSH_TAG(th); state = TH_EXEC_TAG(); if (state == 0) { iter_retry: { rb_block_t *blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(th->cfp); blockptr->iseq = (void *)node; blockptr->proc = 0; th->passed_block = blockptr; } retval = (*it_proc) (data1); } else { VALUE err = th->errinfo; if (state == TAG_BREAK) { VALUE *escape_dfp = GET_THROWOBJ_CATCH_POINT(err); VALUE *cdfp = cfp->dfp; if (cdfp == escape_dfp) { state = 0; th->state = 0; th->errinfo = Qnil; th->cfp = cfp; } else{ /* SDR(); printf("%p, %p\n", cdfp, escape_dfp); */ } } else if (state == TAG_RETRY) { VALUE *escape_dfp = GET_THROWOBJ_CATCH_POINT(err); VALUE *cdfp = cfp->dfp; if (cdfp == escape_dfp) { state = 0; th->state = 0; th->errinfo = Qnil; th->cfp = cfp; goto iter_retry; } } } TH_POP_TAG(); switch (state) { case 0: break; default: TH_JUMP_TAG(th, state); } return retval; }