/* Check first argument for a C type and returns its ID. */ static CTypeID ffi_checkctype(lua_State *L, CTState *cts, TValue *param) { TValue *o = L->base; if (!(o < L->top)) { err_argtype: lj_err_argtype(L, 1, "C type"); } if (tvisstr(o)) { /* Parse an abstract C type declaration. */ GCstr *s = strV(o); CPState cp; int errcode; cp.L = L; cp.cts = cts; cp.srcname = strdata(s); cp.p = strdata(s); cp.param = param; cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT; errcode = lj_cparse(&cp); if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */ return cp.val.id; } else { GCcdata *cd; if (!tviscdata(o)) goto err_argtype; if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM); cd = cdataV(o); return cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->ctypeid; } }
static int recff_metacall(jit_State *J, RecordFFData *rd, MMS mm) { RecordIndex ix; ix.tab = J->base[0]; copyTV(J->L, &ix.tabv, &rd->argv[0]); if (lj_record_mm_lookup(J, &ix, mm)) { /* Has metamethod? */ int errcode; TValue argv0; /* Temporarily insert metamethod below object. */ J->base[1] = J->base[0]; J->base[0] = ix.mobj; copyTV(J->L, &argv0, &rd->argv[0]); copyTV(J->L, &rd->argv[1], &rd->argv[0]); copyTV(J->L, &rd->argv[0], &ix.mobjv); /* Need to protect lj_record_tailcall because it may throw. */ errcode = lj_vm_cpcall(J->L, NULL, J, recff_metacall_cp); /* Always undo Lua stack changes to avoid confusing the interpreter. */ copyTV(J->L, &rd->argv[0], &argv0); if (errcode) lj_err_throw(J->L, errcode); /* Propagate errors. */ rd->nres = -1; /* Pending call. */ return 1; /* Tailcalled to metamethod. */ } return 0; }
/* DWARF2 personality handler referenced from interpreter .eh_frame. */ LJ_FUNCA int lj_err_unwind_dwarf(int version, _Unwind_Action actions, uint64_t uexclass, struct _Unwind_Exception *uex, struct _Unwind_Context *ctx) { void *cf; lua_State *L; if (version != 1) return _URC_FATAL_PHASE1_ERROR; UNUSED(uexclass); cf = (void *)_Unwind_GetCFA(ctx); L = cframe_L(cf); if ((actions & _UA_SEARCH_PHASE)) { #if LJ_UNWIND_EXT if (err_unwind(L, cf, 0) == NULL) return _URC_CONTINUE_UNWIND; #endif if (!LJ_UEXCLASS_CHECK(uexclass)) { setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); } return _URC_HANDLER_FOUND; } if ((actions & _UA_CLEANUP_PHASE)) { int errcode; if (LJ_UEXCLASS_CHECK(uexclass)) { errcode = LJ_UEXCLASS_ERRCODE(uexclass); } else { if ((actions & _UA_HANDLER_FRAME)) _Unwind_DeleteException(uex); errcode = LUA_ERRRUN; } #if LJ_UNWIND_EXT cf = err_unwind(L, cf, errcode); if ((actions & _UA_FORCE_UNWIND)) { return _URC_CONTINUE_UNWIND; } else if (cf) { _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); _Unwind_SetIP(ctx, (uintptr_t)(cframe_unwind_ff(cf) ? lj_vm_unwind_ff_eh : lj_vm_unwind_c_eh)); return _URC_INSTALL_CONTEXT; } #if LJ_TARGET_X86ORX64 else if ((actions & _UA_HANDLER_FRAME)) { /* Workaround for ancient libgcc bug. Still present in RHEL 5.5. :-/ ** Real fix: http://gcc.gnu.org/viewcvs/trunk/gcc/unwind-dw2.c?r1=121165&r2=124837&pathrev=153877&diff_format=h */ _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); _Unwind_SetIP(ctx, (uintptr_t)lj_vm_unwind_rethrow); return _URC_INSTALL_CONTEXT; } #endif #else /* This is not the proper way to escape from the unwinder. We get away with ** it on x86/PPC because the interpreter restores all callee-saved regs. */ lj_err_throw(L, errcode); #endif } return _URC_CONTINUE_UNWIND; }
/* Loop optimization. */ int lj_opt_loop(jit_State *J) { IRRef nins = J->cur.nins; SnapNo nsnap = J->cur.nsnap; MSize nsnapmap = J->cur.nsnapmap; int errcode = lj_vm_cpcall(J->L, NULL, J, cploop_opt); if (LJ_UNLIKELY(errcode)) { lua_State *L = J->L; if (errcode == LUA_ERRRUN && tvisnumber(L->top-1)) { /* Trace error? */ int32_t e = numberVint(L->top-1); switch ((TraceError)e) { case LJ_TRERR_TYPEINS: /* Type instability. */ case LJ_TRERR_GFAIL: /* Guard would always fail. */ /* Unrolling via recording fixes many cases, e.g. a flipped boolean. */ if (--J->instunroll < 0) /* But do not unroll forever. */ break; L->top--; /* Remove error object. */ loop_undo(J, nins, nsnap, nsnapmap); return 1; /* Loop optimization failed, continue recording. */ default: break; } } lj_err_throw(L, errcode); /* Propagate all other errors. */ } return 0; /* Loop optimization is ok. */ }
/* Out-of-memory error. */ LJ_NOINLINE void lj_err_mem(lua_State *L) { if (L->status == LUA_ERRERR+1) /* Don't touch the stack during lua_open. */ lj_vm_unwind_c(L->cframe, LUA_ERRMEM); setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM)); lj_err_throw(L, LUA_ERRMEM); }
/* Setup lexer state. */ void lj_lex_setup(lua_State *L, LexState *ls) { ls->L = L; ls->fs = NULL; ls->n = 0; ls->p = NULL; ls->vstack = NULL; ls->sizevstack = 0; ls->vtop = 0; ls->bcstack = NULL; ls->sizebcstack = 0; ls->lookahead = TK_eof; /* No look-ahead token. */ ls->linenumber = 1; ls->lastline = 1; lj_str_resizebuf(ls->L, &ls->sb, LJ_MIN_SBUF); next(ls); /* Read-ahead first char. */ if (ls->current == 0xef && ls->n >= 2 && char2int(ls->p[0]) == 0xbb && char2int(ls->p[1]) == 0xbf) { /* Skip UTF-8 BOM (if buffered). */ ls->n -= 2; ls->p += 2; next(ls); } if (ls->current == '#') { /* Skip POSIX #! header line. */ do { next(ls); if (ls->current == END_OF_STREAM) return; } while (!currIsNewline(ls)); inclinenumber(ls); } if (ls->current == LUA_SIGNATURE[0]) { setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XBCLOAD)); lj_err_throw(L, LUA_ERRSYNTAX); } }
/* Runtime error. */ LJ_NOINLINE void lj_err_run(lua_State *L) { ptrdiff_t ef = finderrfunc(L); if (ef) { TValue *errfunc = restorestack(L, ef); TValue *top = L->top; lj_trace_abort(G(L)); if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) { setstrV(L, top-1, lj_err_str(L, LJ_ERR_ERRERR)); lj_err_throw(L, LUA_ERRERR); } L->status = LUA_ERRERR; copyTV(L, top, top-1); copyTV(L, top-1, errfunc); L->top = top+1; lj_vm_call(L, top, 1+1); /* Stack: |errfunc|msg| -> |msg| */ } lj_err_throw(L, LUA_ERRRUN); }
/* Lexer error. */ LJ_NOINLINE void lj_err_lex(lua_State *L, GCstr *src, const char *tok, BCLine line, ErrMsg em, va_list argp) { char buff[LUA_IDSIZE]; const char *msg; lj_debug_shortname(buff, src); msg = lj_str_pushvf(L, err2msg(em), argp); msg = lj_str_pushf(L, "%s:%d: %s", buff, line, msg); if (tok) lj_str_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tok); lj_err_throw(L, LUA_ERRSYNTAX); }
/* SPLIT pass. */ void lj_opt_split(jit_State *J) { lua_assert(J->needsplit >= split_needsplit(J)); /* Verify flag. */ if (J->needsplit) { int errcode = lj_vm_cpcall(J->L, NULL, J, cpsplit); if (errcode) { /* Completely reset the trace to avoid inconsistent dump on abort. */ J->cur.nins = J->cur.nk = REF_BASE; J->cur.nsnap = 0; lj_err_throw(J->L, errcode); /* Propagate errors. */ } } }
/* Setup lexer state. */ int lj_lex_setup(lua_State *L, LexState *ls) { int header = 0; ls->L = L; ls->fs = NULL; ls->n = 0; ls->p = NULL; ls->vstack = NULL; ls->sizevstack = 0; ls->vtop = 0; ls->bcstack = NULL; ls->sizebcstack = 0; ls->lookahead = TK_eof; /* No look-ahead token. */ ls->linenumber = 1; ls->lastline = 1; lj_str_resizebuf(ls->L, &ls->sb, LJ_MIN_SBUF); next(ls); /* Read-ahead first char. */ if (ls->current == 0xef && ls->n >= 2 && char2int(ls->p[0]) == 0xbb && char2int(ls->p[1]) == 0xbf) { /* Skip UTF-8 BOM (if buffered). */ ls->n -= 2; ls->p += 2; next(ls); header = 1; } if (ls->current == '#') { /* Skip POSIX #! header line. */ do { next(ls); if (ls->current == END_OF_STREAM) return 0; } while (!currIsNewline(ls)); inclinenumber(ls); header = 1; } if (ls->current == LUA_SIGNATURE[0]) { /* Bytecode dump. */ if (header) { /* ** Loading bytecode with an extra header is disabled for security ** reasons. This may circumvent the usual check for bytecode vs. ** Lua code by looking at the first char. Since this is a potential ** security violation no attempt is made to echo the chunkname either. */ setstrV(L, L->top++, lj_err_str(L, LJ_ERR_BCBAD)); lj_err_throw(L, LUA_ERRSYNTAX); } return 1; } return 0; }
static TValue *cpparser(lua_State *L, lua_CFunction dummy, void *ud) { LexState *ls = (LexState *)ud; GCproto *pt; GCfunc *fn; int bc; UNUSED(dummy); cframe_errfunc(L->cframe) = -1; /* Inherit error function. */ bc = lj_lex_setup(L, ls); if (ls->mode && !strchr(ls->mode, bc ? 'b' : 't')) { setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XMODE)); lj_err_throw(L, LUA_ERRSYNTAX); } pt = bc ? lj_bcread(ls) : lj_parse(ls); fn = lj_func_newL_empty(L, pt, tabref(L->env)); /* Don't combine above/below into one statement. */ setfuncV(L, L->top++, fn); return NULL; }
static void LJ_FASTCALL recff_xpcall(jit_State *J, RecordFFData *rd) { if (J->maxslot >= 2) { TValue argv0, argv1; TRef tmp; int errcode; /* Swap function and traceback. */ tmp = J->base[0]; J->base[0] = J->base[1]; J->base[1] = tmp; copyTV(J->L, &argv0, &rd->argv[0]); copyTV(J->L, &argv1, &rd->argv[1]); copyTV(J->L, &rd->argv[0], &argv1); copyTV(J->L, &rd->argv[1], &argv0); /* Need to protect lj_record_call because it may throw. */ errcode = lj_vm_cpcall(J->L, NULL, J, recff_xpcall_cp); /* Always undo Lua stack swap to avoid confusing the interpreter. */ copyTV(J->L, &rd->argv[0], &argv0); copyTV(J->L, &rd->argv[1], &argv1); if (errcode) lj_err_throw(J->L, errcode); /* Propagate errors. */ rd->nres = -1; /* Pending call. */ } /* else: Interpreter will throw. */ }
/* Synchronous abort with error message and error info. */ void lj_trace_err_info(jit_State *J, TraceError e) { setintV(J->L->top++, (int32_t)e); lj_err_throw(J->L, LUA_ERRRUN); }
/* Synchronous abort with error message. */ void lj_trace_err(jit_State *J, TraceError e) { setnilV(&J->errinfo); /* No error info. */ setintV(J->L->top++, (int32_t)e); lj_err_throw(J->L, LUA_ERRRUN); }