/* Find error function for runtime errors. Requires an extra stack traversal. */ static ptrdiff_t finderrfunc(lua_State *L) { cTValue *frame = L->base-1, *bot = tvref(L->stack); void *cf = L->cframe; while (frame > bot && cf) { while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ if (frame >= restorestack(L, -cframe_nres(cf))) break; if (cframe_errfunc(cf) >= 0) /* Error handler not inherited (-1)? */ return cframe_errfunc(cf); cf = cframe_prev(cf); /* Else unwind cframe and continue searching. */ if (cf == NULL) return 0; } switch (frame_typep(frame)) { case FRAME_LUA: case FRAME_LUAP: frame = frame_prevl(frame); break; case FRAME_C: cf = cframe_prev(cf); /* fallthrough */ case FRAME_VARG: frame = frame_prevd(frame); break; case FRAME_CONT: #if LJ_HASFFI if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK) cf = cframe_prev(cf); #endif frame = frame_prevd(frame); break; case FRAME_CP: if (cframe_canyield(cf)) return 0; if (cframe_errfunc(cf) >= 0) return cframe_errfunc(cf); frame = frame_prevd(frame); break; case FRAME_PCALL: case FRAME_PCALLH: if (frame_ftsz(frame) >= (ptrdiff_t)(2*sizeof(TValue))) /* xpcall? */ return savestack(L, frame-1); /* Point to xpcall's errorfunc. */ return 0; default: lua_assert(0); return 0; } } return 0; }
/* Find error function for runtime errors. Requires an extra stack traversal. */ static ptrdiff_t finderrfunc(lua_State *L) { cTValue *frame = L->base-1, *bot = tvref(L->stack)+LJ_FR2; void *cf = L->cframe; while (frame > bot && cf) { while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ if (frame >= restorestack(L, -cframe_nres(cf))) break; if (cframe_errfunc(cf) >= 0) /* Error handler not inherited (-1)? */ return cframe_errfunc(cf); cf = cframe_prev(cf); /* Else unwind cframe and continue searching. */ if (cf == NULL) return 0; } switch (frame_typep(frame)) { case FRAME_LUA: case FRAME_LUAP: frame = frame_prevl(frame); break; case FRAME_C: cf = cframe_prev(cf); /* fallthrough */ case FRAME_VARG: frame = frame_prevd(frame); break; case FRAME_CONT: if (frame_iscont_fficb(frame)) cf = cframe_prev(cf); frame = frame_prevd(frame); break; case FRAME_CP: if (cframe_canyield(cf)) return 0; if (cframe_errfunc(cf) >= 0) return cframe_errfunc(cf); frame = frame_prevd(frame); break; case FRAME_PCALL: case FRAME_PCALLH: if (frame_func(frame_prevd(frame))->c.ffid == FF_xpcall) return savestack(L, frame_prevd(frame)+1); /* xpcall's errorfunc. */ return 0; default: lua_assert(0); return 0; } } return 0; }
/* Unwind until stop frame. Optionally cleanup frames. */ static void *err_unwind(lua_State *L, void *stopcf, int errcode) { TValue *frame = L->base-1; void *cf = L->cframe; while (cf) { int32_t nres = cframe_nres(cframe_raw(cf)); if (nres < 0) { /* C frame without Lua frame? */ TValue *top = restorestack(L, -nres); if (frame < top) { /* Frame reached? */ if (errcode) { L->cframe = cframe_prev(cf); L->base = frame+1; unwindstack(L, top); } return cf; } } if (frame <= tvref(L->stack)) break; switch (frame_typep(frame)) { case FRAME_LUA: /* Lua frame. */ case FRAME_LUAP: frame = frame_prevl(frame); break; case FRAME_C: /* C frame. */ #if LJ_UNWIND_EXT if (errcode) { L->cframe = cframe_prev(cf); L->base = frame_prevd(frame) + 1; unwindstack(L, frame); } else if (cf != stopcf) { cf = cframe_prev(cf); frame = frame_prevd(frame); break; } return NULL; /* Continue unwinding. */ #else UNUSED(stopcf); cf = cframe_prev(cf); frame = frame_prevd(frame); break; #endif case FRAME_CP: /* Protected C frame. */ if (cframe_canyield(cf)) { /* Resume? */ if (errcode) { L->cframe = NULL; L->status = (uint8_t)errcode; } return cf; } if (errcode) { L->cframe = cframe_prev(cf); L->base = frame_prevd(frame) + 1; unwindstack(L, frame); } return cf; case FRAME_CONT: /* Continuation frame. */ case FRAME_VARG: /* Vararg frame. */ frame = frame_prevd(frame); break; case FRAME_PCALL: /* FF pcall() frame. */ case FRAME_PCALLH: /* FF pcall() frame inside hook. */ if (errcode) { if (errcode == LUA_YIELD) { frame = frame_prevd(frame); break; } if (frame_typep(frame) == FRAME_PCALL) hook_leave(G(L)); L->cframe = cf; L->base = frame_prevd(frame) + 1; unwindstack(L, L->base); } return (void *)((intptr_t)cf | CFRAME_UNWIND_FF); } } /* No C frame. */ if (errcode) { L->cframe = NULL; L->base = tvref(L->stack)+1; unwindstack(L, L->base); if (G(L)->panic) G(L)->panic(L); exit(EXIT_FAILURE); } return L; /* Anything non-NULL will do. */ }