LUA_API void lua_replace (lua_State *L, int idx) { lua_lock(L); /* explicit test for incompatible code */ if ( idx == LUA_ENVIRONINDEX && !hascallingenv( L ) ) { luaG_runerror(L, "no calling environment"); } api_checknelems(L, 1); { rtStack_t& rtStack = L->rtStack; rtStack.Lock( L ); StkId stackTop = L->GetCurrentStackFrame().TopMutable( L, L->rtStack ); if ( idx == LUA_ENVIRONINDEX ) { Closure *func = curr_func(L); const TValue *val = stackTop; func->env = gcvalue(val); luaC_barrier(L, func, val); } else if ( idx == LUA_STORAGEINDEX ) { const TValue *val = stackTop; setgcvalue( L, &L->storage, gcvalue( val ) ); luaC_barrier( L, L, val ); } else { ValueAddress o = index2adr(L, idx); api_checkvalidindex(L, o); setobj( L, o, stackTop ); if ( idx < LUA_GLOBALSINDEX ) /* function upvalue? */ { luaC_barrier(L, curr_func(L), stackTop); } } popstack( L, 1 ); rtStack.Unlock( L ); } lua_unlock(L); }
LJLIB_ASM(bit_band) LJLIB_REC(bit_nary IR_BAND) { #if LJ_HASFFI CTypeID id = 0; TValue *o = L->base, *top = L->top; int i = 0; do { lj_carith_check64(L, ++i, &id); } while (++o < top); if (id) { CTState *cts = ctype_cts(L); CType *ct = ctype_get(cts, id); int op = curr_func(L)->c.ffid - (int)FF_bit_bor; uint64_t x, y = op >= 0 ? 0 : ~(uint64_t)0; o = L->base; do { lj_cconv_ct_tv(cts, ct, (uint8_t *)&x, o, 0); if (op < 0) y &= x; else if (op == 0) y |= x; else y ^= x; } while (++o < top); return bit_result64(L, id, y); } return FFH_RETRY; #else int i = 0; do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top); return FFH_RETRY; #endif }
int lj_lib_postreg(lua_State *L, lua_CFunction cf, int id, const char *name) { GCfunc *fn = lj_lib_pushcf(L, cf, id); GCtab *t = tabref(curr_func(L)->c.env); /* Reference to parent table. */ setfuncV(L, lj_tab_setstr(L, t, lj_str_newz(L, name)), fn); lj_gc_anybarriert(L, t); setfuncV(L, L->top++, fn); return 1; }
static IOFileUD *io_file_new(lua_State *L) { IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD)); GCudata *ud = udataV(L->top-1); ud->udtype = UDTYPE_IO_FILE; /* NOBARRIER: The GCudata is new (marked white). */ setgcrefr(ud->metatable, curr_func(L)->c.env); iof->fp = NULL; iof->type = IOFILE_TYPE_FILE; return iof; }
LJLIB_ASM(bit_lshift) LJLIB_REC(bit_shift IR_BSHL) { #if LJ_HASFFI CTypeID id = 0, id2 = 0; uint64_t x = lj_carith_check64(L, 1, &id); int32_t sh = (int32_t)lj_carith_check64(L, 2, &id2); if (id) { x = lj_carith_shift64(x, sh, curr_func(L)->c.ffid - (int)FF_bit_lshift); return bit_result64(L, id, x); } if (id2) setintV(L->base+1, sh); return FFH_RETRY; #else lj_lib_checknumber(L, 1); bit_checkbit(L, 2); return FFH_RETRY; #endif }
/* Call dispatch. Used by call hooks, hot calls or when recording. */ ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns *pc) { GCfunc *fn = curr_func(L); BCOp op; global_State *g = G(L); #if LJ_HASJIT jit_State *J = G2J(g); #endif int missing = call_init(L, fn); #if LJ_HASJIT J->L = L; if ((uintptr_t)pc & 1) { /* Marker for hot call. */ pc = (const BCIns *)((uintptr_t)pc & ~(uintptr_t)1); lj_trace_hot(J, pc); goto out; } else if (J->state != LJ_TRACE_IDLE && !(g->hookmask & (HOOK_GC|HOOK_VMEVENT))) { /* Record the FUNC* bytecodes, too. */ lj_trace_ins(J, pc-1); /* The interpreter bytecode PC is offset by 1. */ } #endif if ((g->hookmask & LUA_MASKCALL)) { int i; for (i = 0; i < missing; i++) /* Add missing parameters. */ setnilV(L->top++); callhook(L, LUA_HOOKCALL, -1); /* Preserve modifications of missing parameters by lua_setlocal(). */ while (missing-- > 0 && tvisnil(L->top - 1)) L->top--; } #if LJ_HASJIT out: #endif op = bc_op(pc[-1]); /* Get FUNC* op. */ #if LJ_HASJIT /* Use the non-hotcounting variants if JIT is off or while recording. */ if ((!(J->flags & JIT_F_ON) || J->state != LJ_TRACE_IDLE) && (op == BC_FUNCF || op == BC_FUNCV)) op = (BCOp)((int)op+(int)BC_IFUNCF-(int)BC_FUNCF); #endif return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */ }
/* Typecheck error for arguments. */ LJ_NOINLINE void lj_err_argtype(lua_State *L, int narg, const char *xname) { const char *tname, *msg; if (narg <= LUA_REGISTRYINDEX) { if (narg >= LUA_GLOBALSINDEX) { tname = lj_obj_itypename[~LJ_TTAB]; } else { GCfunc *fn = curr_func(L); int idx = LUA_GLOBALSINDEX - narg; if (idx <= fn->c.nupvalues) tname = lj_typename(&fn->c.upvalue[idx-1]); else tname = lj_obj_typename[0]; } } else { TValue *o = narg < 0 ? L->top + narg : L->base + narg-1; tname = o < L->top ? lj_typename(o) : lj_obj_typename[0]; } msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_BADTYPE), xname, tname); err_argmsg(L, narg, msg); }
/* Instruction dispatch. Used by instr/line/return hooks or when recording. */ void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc) { GCfunc *fn = curr_func(L); GCproto *pt = funcproto(fn); void *cf = cframe_raw(L->cframe); const BCIns *oldpc = cframe_pc(cf); global_State *g = G(L); BCReg slots; setcframe_pc(cf, pc); slots = cur_topslot(pt, pc, cframe_multres_n(cf)); L->top = L->base + slots; /* Fix top. */ #if LJ_HASJIT { jit_State *J = G2J(g); if (J->state != LJ_TRACE_IDLE) { J->L = L; lj_trace_ins(J, pc-1); /* The interpreter bytecode PC is offset by 1. */ } } #endif if ((g->hookmask & LUA_MASKCOUNT) && g->hookcount == 0) { g->hookcount = g->hookcstart; callhook(L, LUA_HOOKCOUNT, -1); L->top = L->base + slots; /* Fix top again. */ } if ((g->hookmask & LUA_MASKLINE)) { BCPos npc = proto_bcpos(pt, pc) - 1; BCPos opc = proto_bcpos(pt, oldpc) - 1; BCLine line = proto_line(pt, npc); if (pc <= oldpc || opc >= pt->sizebc || line != proto_line(pt, opc)) { callhook(L, LUA_HOOKLINE, line); L->top = L->base + slots; /* Fix top again. */ } } if ((g->hookmask & LUA_MASKRET) && bc_isret(bc_op(pc[-1]))) callhook(L, LUA_HOOKRET, -1); }
static int io_file_iter(lua_State *L) { GCfunc *fn = curr_func(L); IOFileUD *iof = uddata(udataV(&fn->c.upvalue[0])); int n = fn->c.nupvalues - 1; if (iof->fp == NULL) lj_err_caller(L, LJ_ERR_IOCLFL); L->top = L->base; if (n) { /* Copy upvalues with options to stack. */ if (n > LUAI_MAXCSTACK) lj_err_caller(L, LJ_ERR_STKOV); lj_state_checkstack(L, (MSize)n); memcpy(L->top, &fn->c.upvalue[1], n*sizeof(TValue)); L->top += n; } n = io_file_read(L, iof->fp, 0); if (ferror(iof->fp)) lj_err_callermsg(L, strVdata(L->top-2)); if (tvisnil(L->base) && (iof->type & IOFILE_FLAG_CLOSE)) { io_file_close(L, iof); /* Return values are ignored. */ return 0; } return n; }
/* Instruction dispatch callback for instr/line hooks or when recording. */ void lj_dispatch_ins(lua_State *L, const BCIns *pc, uint32_t nres) { GCfunc *fn = curr_func(L); GCproto *pt = funcproto(fn); BCReg slots = cur_topslot(pt, pc, nres); global_State *g = G(L); const BCIns *oldpc = cframe_Lpc(L); cframe_Lpc(L) = pc; L->top = L->base + slots; /* Fix top. */ #if LJ_HASJIT { jit_State *J = G2J(g); if (J->state != LJ_TRACE_IDLE) { J->L = L; J->pc = pc-1; J->fn = fn; J->pt = pt; lj_trace_ins(J); } } #endif if ((g->hookmask & LUA_MASKCOUNT) && g->hookcount == 0) { g->hookcount = g->hookcstart; callhook(L, LUA_HOOKCOUNT, -1); } if ((g->hookmask & LUA_MASKLINE) && pt->lineinfo) { BCPos npc = (BCPos)(pc - pt->bc)-1; BCPos opc = (BCPos)(oldpc - pt->bc)-1; BCLine line = pt->lineinfo[npc]; if (npc == 0 || pc <= oldpc || opc >= pt->sizebc || line != pt->lineinfo[opc]) { L->top = L->base + slots; /* Fix top again after instruction hook. */ callhook(L, LUA_HOOKLINE, line); } } }