erlang catch的内部实现(初稿)

/* Fall through here */ find_func_info: {reg[0] = r(0);SWAPOUT;I = handle_error(c_p, I, reg, NULL); // 获取异常错误指令地址goto post_error_handling; } post_error_handling:if (I == 0) { // 等待下次调度 erl_exit(),抛出异常中断 goto do_schedule;} else { r(0) = reg[0]; ASSERT(!is_value(r(0))); if (c_p->mbuf) { // 存在堆外消息数据,执行gcerts_garbage_collect(c_p, 0, reg+1, 3); } SWAPIN; Goto(*I); // 执行指令} }然后,简单看下handle_error函数。// erl_emu.c VM处理异常函数static BeamInstr* handle_error(Process* c_p, BeamInstr* pc, Eterm* reg, BifFunction bf){Eterm* hp;Eterm Value = c_p->fvalue;Eterm Args = am_true;c_p->i = pc; /* In case we call erl_exit(). */ASSERT(c_p->freason != TRAP); /* Should have been handled earlier. *//** Check if we have an arglist for the top level call. If so, this* is encoded in Value, so we have to dig out the real Value as well* as the Arglist.*/if (c_p->freason & EXF_ARGLIST) { Eterm* tp; ASSERT(is_tuple(Value)); tp = tuple_val(Value); Value = tp[1]; Args = tp[2];}/** Save the stack trace info if the EXF_SAVETRACE flag is set. The* main reason for doing this separately is to allow throws to later* become promoted to errors without losing the original stack* trace, even if they have passed through one or more catch and* rethrow. It also makes the creation of symbolic stack traces much* more modular.*/if (c_p->freason & EXF_SAVETRACE) {save_stacktrace(c_p, pc, reg, bf, Args);}/** Throws that are not caught are turned into ‘nocatch’ errors*/if ((c_p->freason & EXF_THROWN) && (c_p->catches <= 0) ) {hp = HAlloc(c_p, 3);Value = TUPLE2(hp, am_nocatch, Value);c_p->freason = EXC_ERROR;}/* Get the fully expanded error term */Value = expand_error_value(c_p, c_p->freason, Value);/* Save final error term and stabilize the exception flags so nofurther expansion is done. */c_p->fvalue = Value;c_p->freason = PRIMARY_EXCEPTION(c_p->freason);/* Find a handler or die */if ((c_p->catches > 0 || IS_TRACED_FL(c_p, F_EXCEPTION_TRACE))&& !(c_p->freason & EXF_PANIC)) {BeamInstr *new_pc;/* The Beam handler code (catch_end or try_end) checks reg[0]for THE_NON_VALUE to see if the previous code finishedabnormally. If so, reg[1], reg[2] and reg[3] should hold theexception class, term and trace, respectively. (If thehandler is just a trap to native code, these registers willbe ignored.) */reg[0] = THE_NON_VALUE;reg[1] = exception_tag[GET_EXC_CLASS(c_p->freason)];reg[2] = Value;reg[3] = c_p->ftrace;if ((new_pc = next_catch(c_p, reg))) { // 从进程栈上找到最近的 catchc_p->cp = 0;/* To avoid keeping stale references. */return new_pc; // 返回 catch end 指令地址}if (c_p->catches > 0) erl_exit(1, "Catch not found");}ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);terminate_proc(c_p, Value);ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);return NULL; // 返回0,就是执行 erl_exit()}

,把艰辛的劳作看作是生命的必然,

erlang catch的内部实现(初稿)

相关文章:

你感兴趣的文章:

标签云: