/* Helper for FORI. Coercion. */ void LJ_FASTCALL lj_meta_for(lua_State *L, TValue *o) { if (!lj_strscan_numberobj(o)) lj_err_msg(L, LJ_ERR_FORINIT); if (!lj_strscan_numberobj(o+1)) lj_err_msg(L, LJ_ERR_FORLIM); if (!lj_strscan_numberobj(o+2)) lj_err_msg(L, LJ_ERR_FORSTEP); if (LJ_DUALNUM) { /* Ensure all slots are integers or all slots are numbers. */ int32_t k[3]; int nint = 0; ptrdiff_t i; for (i = 0; i <= 2; i++) { if (tvisint(o+i)) { k[i] = intV(o+i); nint++; } else { k[i] = lj_num2int(numV(o+i)); nint += ((lua_Number)k[i] == numV(o+i)); } } if (nint == 3) { /* Narrow to integers. */ setintV(o, k[0]); setintV(o+1, k[1]); setintV(o+2, k[2]); } else if (nint != 0) { /* Widen to numbers. */ if (tvisint(o)) setnumV(o, (lua_Number)intV(o)); if (tvisint(o+1)) setnumV(o+1, (lua_Number)intV(o+1)); if (tvisint(o+2)) setnumV(o+2, (lua_Number)intV(o+2)); } } }
/* Restore a value from the trace exit state. */ static void snap_restoreval(jit_State *J, GCtrace *T, ExitState *ex, SnapNo snapno, BloomFilter rfilt, IRRef ref, TValue *o) { IRIns *ir = &T->ir[ref]; IRType1 t = ir->t; RegSP rs = ir->prev; if (irref_isk(ref)) { /* Restore constant slot. */ lj_ir_kvalue(J->L, o, ir); return; } if (LJ_UNLIKELY(bloomtest(rfilt, ref))) rs = snap_renameref(T, snapno, ref, rs); lua_assert(!LJ_GC64); /* TODO_GC64: handle 64 bit references. */ if (ra_hasspill(regsp_spill(rs))) { /* Restore from spill slot. */ int32_t *sps = &ex->spill[regsp_spill(rs)]; if (irt_isinteger(t)) { setintV(o, *sps); #if !LJ_SOFTFP } else if (irt_isnum(t)) { o->u64 = *(uint64_t *)sps; #endif } else if (LJ_64 && irt_islightud(t)) { /* 64 bit lightuserdata which may escape already has the tag bits. */ o->u64 = *(uint64_t *)sps; } else { lua_assert(!irt_ispri(t)); /* PRI refs never have a spill slot. */ setgcV(J->L, o, (GCobj *)(uintptr_t)*(GCSize *)sps, irt_toitype(t)); } } else { /* Restore from register. */ Reg r = regsp_reg(rs); if (ra_noreg(r)) { lua_assert(ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT); snap_restoreval(J, T, ex, snapno, rfilt, ir->op1, o); if (LJ_DUALNUM) setnumV(o, (lua_Number)intV(o)); return; } else if (irt_isinteger(t)) { setintV(o, (int32_t)ex->gpr[r-RID_MIN_GPR]); #if !LJ_SOFTFP } else if (irt_isnum(t)) { setnumV(o, ex->fpr[r-RID_MIN_FPR]); #endif } else if (LJ_64 && irt_is64(t)) { /* 64 bit values that already have the tag bits. */ o->u64 = ex->gpr[r-RID_MIN_GPR]; } else if (irt_ispri(t)) { setpriV(o, irt_toitype(t)); } else { setgcV(J->L, o, (GCobj *)ex->gpr[r-RID_MIN_GPR], irt_toitype(t)); } } }
LUA_API void lua_pushunsigned (lua_State *L, lua_Unsigned u) { lua_Number n=0; lua_lock(L); /* printf("u=%d,%u,%x\n",u,u,u); printf("INT_MAX=%d %u %x, (lua_Unsigned)INT_MAX=%d %u %x (unsigned int)INT_MAX=%d %u %x\n", INT_MAX,INT_MAX,INT_MAX, (lua_Unsigned)INT_MAX,(lua_Unsigned)INT_MAX,(lua_Unsigned)INT_MAX, (unsigned int)INT_MAX,(unsigned int)INT_MAX,(unsigned int)INT_MAX); printf("((u) <= (lua_Unsigned)INT_MAX) :%d\n",(((unsigned int)u) <= (lua_Unsigned)INT_MAX)); printf("(lua_Number)(int)(u) =%d,%u,%x\n",(lua_Number)(int)(u),(lua_Number)(int)(u),(lua_Number)(int)(u)); printf("(lua_Number)(u) =%f,%u,%x\n",(lua_Number)(u),(lua_Number)(u),(lua_Number)(u)); printf("u=%d,%u,%x\n",u,u,u); */ /*printf("n=%d,%u,%x u=%d,%u,%x\n",n,n,n,u,u,u); */ n = lua_unsigned2number(u); /* printf("n=%f \n",n); printf("u=%d %u %x n=%d %u %x\n",u,u,u,n,n,n); printf("n=%d %u %x\n",n,n,n); printf("u=%d,%u,%x\n",u,u,u); */ /* setintptrV(L->top, n); incr_top(L); setnumV(L->top, n); */ setnumV(L->top, n); if (LJ_UNLIKELY(tvisnan(L->top))) setnanV(L->top); /* Canonicalize injected NaNs. */ incr_top(L); /*setnvalue(L->top, n); api_incr_top(L); */ lua_unlock(L); }
/* Index a C library by name. */ TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) { TValue *tv = lj_tab_setstr(L, cl->cache, name); if (LJ_UNLIKELY(tvisnil(tv))) { CTState *cts = ctype_cts(L); CType *ct; CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); if (!id) lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name)); if (ctype_isconstval(ct->info)) { CType *ctt = ctype_child(cts, ct); lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4); if ((ctt->info & CTF_UNSIGNED) && ctt->size == 4) setnumV(tv, (lua_Number)(uint32_t)ct->size); else setnumV(tv, (lua_Number)(int32_t)ct->size); } else { const char *sym = clib_extsym(cts, ct, name); void *p = clib_getsym(cl, sym); GCcdata *cd; lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); #if LJ_TARGET_X86 && LJ_ABI_WIN /* Retry with decorated name for fastcall/stdcall functions. */ if (!p && ctype_isfunc(ct->info)) { CTInfo cconv = ctype_cconv(ct->info); if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) { CTSize sz = clib_func_argsize(cts, ct); sym = lj_str_pushf(L, cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", sym, sz); L->top--; p = clib_getsym(cl, sym); } } #endif if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", strdata(name)); cd = lj_cdata_new(cts, id, CTSIZE_PTR); *(void **)cdataptr(cd) = p; setcdataV(L, tv, cd); } } return tv; }
static int io_file_readnum(lua_State *L, FILE *fp) { lua_Number d; if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) { setnumV(L->top++, d); return 1; } else { setnilV(L->top++); return 0; } }
static cTValue *str2num(cTValue *o, TValue *n) { if (tvisnum(o)) return o; else if (tvisint(o)) return (setnumV(n, (lua_Number)intV(o)), n); else if (tvisstr(o) && lj_strscan_num(strV(o), n)) return n; else return NULL; }
lua_Number lj_lib_checknum(lua_State *L, int narg) { TValue *o = L->base + narg-1; if (!(o < L->top && (tvisnumber(o) || (tvisstr(o) && lj_strscan_num(strV(o), o))))) lj_err_argt(L, narg, LUA_TNUMBER); if (LJ_UNLIKELY(tvisint(o))) { lua_Number n = (lua_Number)intV(o); setnumV(o, n); return n; } else { return numV(o); } }
/* Convert C type to TValue. Caveat: expects to get the raw CType! */ int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid, TValue *o, uint8_t *sp) { CTInfo sinfo = s->info; lua_assert(!ctype_isenum(sinfo)); if (ctype_isnum(sinfo)) { if (!ctype_isbool(sinfo)) { if (ctype_isinteger(sinfo) && s->size > 4) goto copyval; if (LJ_DUALNUM && ctype_isinteger(sinfo)) { int32_t i; lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT32), s, (uint8_t *)&i, sp, 0); if ((sinfo & CTF_UNSIGNED) && i < 0) setnumV(o, (lua_Number)(uint32_t)i); else setintV(o, i); } else { lj_cconv_ct_ct(cts, ctype_get(cts, CTID_DOUBLE), s, (uint8_t *)&o->n, sp, 0); /* Numbers are NOT canonicalized here! Beware of uninitialized data. */ lua_assert(tvisnum(o)); } } else { uint32_t b = ((*sp) & 1); setboolV(o, b); setboolV(&cts->g->tmptv2, b); /* Remember for trace recorder. */ } return 0; } else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) { /* Create reference. */ setcdataV(cts->L, o, lj_cdata_newref(cts, sp, sid)); return 1; /* Need GC step. */ } else { GCcdata *cd; CTSize sz; copyval: /* Copy value. */ sz = s->size; lua_assert(sz != CTSIZE_INVALID); /* Attributes are stripped, qualifiers are kept (but mostly ignored). */ cd = lj_cdata_new(cts, ctype_typeid(cts, s), sz); setcdataV(cts->L, o, cd); memcpy(cdataptr(cd), sp, sz); return 1; /* Need GC step. */ } }
static int io_file_readnum(lua_State *L, FILE *fp) { lua_Number d; if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) { if (LJ_DUALNUM) { int32_t i = lj_num2int(d); if (d == (lua_Number)i && !tvismzero((cTValue *)&d)) { setintV(L->top++, i); return 1; } } setnumV(L->top++, d); return 1; } else { setnilV(L->top++); return 0; } }
/* Helper for TSET*. __newindex chain and metamethod. */ TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k) { TValue tmp; int loop; for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) { cTValue *mo; if (LJ_LIKELY(tvistab(o))) { GCtab *t = tabV(o); cTValue *tv = lj_tab_get(L, t, k); if (LJ_LIKELY(!tvisnil(tv))) { t->nomm = 0; /* Invalidate negative metamethod cache. */ lj_gc_anybarriert(L, t); return (TValue *)tv; } else if (!(mo = lj_meta_fast(L, tabref(t->metatable), MM_newindex))) { t->nomm = 0; /* Invalidate negative metamethod cache. */ lj_gc_anybarriert(L, t); if (tv != niltv(L)) return (TValue *)tv; if (tvisnil(k)) lj_err_msg(L, LJ_ERR_NILIDX); else if (tvisint(k)) { setnumV(&tmp, (lua_Number)intV(k)); k = &tmp; } else if (tvisnum(k) && tvisnan(k)) lj_err_msg(L, LJ_ERR_NANIDX); return lj_tab_newkey(L, t, k); } } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_newindex))) { lj_err_optype(L, o, LJ_ERR_OPINDEX); return NULL; /* unreachable */ } if (tvisfunc(mo)) { L->top = mmcall(L, lj_cont_nop, mo, o, k); /* L->top+2 = v filled in by caller. */ return NULL; /* Trigger metamethod call. */ } copyTV(L, &tmp, mo); o = &tmp; } lj_err_msg(L, LJ_ERR_SETLOOP); return NULL; /* unreachable */ }
/* Helper for arithmetic instructions. Coercion, metamethod. */ TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc, BCReg op) { MMS mm = bcmode_mm(op); TValue tempb, tempc; cTValue *b, *c; if ((b = str2num(rb, &tempb)) != NULL && (c = str2num(rc, &tempc)) != NULL) { /* Try coercion first. */ setnumV(ra, lj_vm_foldarith(numV(b), numV(c), (int)mm-MM_add)); return NULL; } else { cTValue *mo = lj_meta_lookup(L, rb, mm); if (tvisnil(mo)) { mo = lj_meta_lookup(L, rc, mm); if (tvisnil(mo)) { if (str2num(rb, &tempb) == NULL) rc = rb; lj_err_optype(L, rc, LJ_ERR_OPARITH); return NULL; /* unreachable */ } } return mmcall(L, lj_cont_ra, mo, rb, rc); } }
/* Restore interpreter state from exit state with the help of a snapshot. */ const BCIns *lj_snap_restore(jit_State *J, void *exptr) { ExitState *ex = (ExitState *)exptr; SnapNo snapno = J->exitno; /* For now, snapno == exitno. */ GCtrace *T = traceref(J, J->parent); SnapShot *snap = &T->snap[snapno]; MSize n, nent = snap->nent; SnapEntry *map = &T->snapmap[snap->mapofs]; SnapEntry *flinks = map + nent + snap->depth; int32_t ftsz0; BCReg nslots = snap->nslots; TValue *frame; BloomFilter rfilt = snap_renamefilter(T, snapno); const BCIns *pc = snap_pc(map[nent]); lua_State *L = J->L; /* Set interpreter PC to the next PC to get correct error messages. */ setcframe_pc(cframe_raw(L->cframe), pc+1); /* Make sure the stack is big enough for the slots from the snapshot. */ if (LJ_UNLIKELY(L->base + nslots > tvref(L->maxstack))) { L->top = curr_topL(L); lj_state_growstack(L, nslots - curr_proto(L)->framesize); } /* Fill stack slots with data from the registers and spill slots. */ frame = L->base-1; ftsz0 = frame_ftsz(frame); /* Preserve link to previous frame in slot #0. */ for (n = 0; n < nent; n++) { SnapEntry sn = map[n]; IRRef ref = snap_ref(sn); BCReg s = snap_slot(sn); TValue *o = &frame[s]; /* Stack slots are relative to start frame. */ IRIns *ir = &T->ir[ref]; if (irref_isk(ref)) { /* Restore constant slot. */ lj_ir_kvalue(L, o, ir); if ((sn & (SNAP_CONT|SNAP_FRAME))) { /* Overwrite tag with frame link. */ o->fr.tp.ftsz = s != 0 ? (int32_t)*flinks-- : ftsz0; if ((sn & SNAP_FRAME)) { GCfunc *fn = ir_kfunc(ir); if (isluafunc(fn)) { MSize framesize = funcproto(fn)->framesize; L->base = ++o; if (LJ_UNLIKELY(o + framesize > tvref(L->maxstack))) { ptrdiff_t fsave = savestack(L, frame); L->top = o; lj_state_growstack(L, framesize); /* Grow again. */ frame = restorestack(L, fsave); } } } } } else if (!(sn & SNAP_NORESTORE)) { IRType1 t = ir->t; RegSP rs = ir->prev; lua_assert(!(sn & (SNAP_CONT|SNAP_FRAME))); if (LJ_UNLIKELY(bloomtest(rfilt, ref))) rs = snap_renameref(T, snapno, ref, rs); if (ra_hasspill(regsp_spill(rs))) { /* Restore from spill slot. */ int32_t *sps = &ex->spill[regsp_spill(rs)]; if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM)) { o->u32.lo = (uint32_t)*sps; } else if (irt_isinteger(t)) { setintV(o, *sps); #if !LJ_SOFTFP } else if (irt_isnum(t)) { o->u64 = *(uint64_t *)sps; #endif #if LJ_64 } else if (irt_islightud(t)) { /* 64 bit lightuserdata which may escape already has the tag bits. */ o->u64 = *(uint64_t *)sps; #endif } else { lua_assert(!irt_ispri(t)); /* PRI refs never have a spill slot. */ setgcrefi(o->gcr, *sps); setitype(o, irt_toitype(t)); } } else { /* Restore from register. */ Reg r = regsp_reg(rs); lua_assert(ra_hasreg(r)); if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM)) { o->u32.lo = (uint32_t)ex->gpr[r-RID_MIN_GPR]; } else if (irt_isinteger(t)) { setintV(o, (int32_t)ex->gpr[r-RID_MIN_GPR]); #if !LJ_SOFTFP } else if (irt_isnum(t)) { setnumV(o, ex->fpr[r-RID_MIN_FPR]); #endif #if LJ_64 } else if (irt_islightud(t)) { /* 64 bit lightuserdata which may escape already has the tag bits. */ o->u64 = ex->gpr[r-RID_MIN_GPR]; #endif } else { if (!irt_ispri(t)) setgcrefi(o->gcr, ex->gpr[r-RID_MIN_GPR]); setitype(o, irt_toitype(t)); } } if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM)) { rs = (ir+1)->prev; if (LJ_UNLIKELY(bloomtest(rfilt, ref+1))) rs = snap_renameref(T, snapno, ref+1, rs); o->u32.hi = (ra_hasspill(regsp_spill(rs))) ? (uint32_t)*&ex->spill[regsp_spill(rs)] : (uint32_t)ex->gpr[regsp_reg(rs)-RID_MIN_GPR]; } } } switch (bc_op(*pc)) { case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM: L->top = frame + nslots; break; default: L->top = curr_topL(L); break; } lua_assert(map + nent == flinks); return pc; }
/* Restore interpreter state from exit state with the help of a snapshot. */ void lj_snap_restore(jit_State *J, void *exptr) { ExitState *ex = (ExitState *)exptr; SnapNo snapno = J->exitno; /* For now, snapno == exitno. */ Trace *T = J->trace[J->parent]; SnapShot *snap = &T->snap[snapno]; BCReg s, nslots = snap->nslots; IRRef2 *map = &T->snapmap[snap->mapofs]; IRRef2 *flinks = map + nslots + snap->nframelinks; TValue *o, *newbase, *ntop; BloomFilter rfilt = snap_renamefilter(T, snapno); lua_State *L = J->L; /* Make sure the stack is big enough for the slots from the snapshot. */ if (L->base + nslots >= L->maxstack) { L->top = curr_topL(L); lj_state_growstack(L, nslots - curr_proto(L)->framesize); } /* Fill stack slots with data from the registers and spill slots. */ newbase = NULL; ntop = L->base; for (s = 0, o = L->base-1; s < nslots; s++, o++) { IRRef ref = snap_ref(map[s]); if (ref) { IRIns *ir = &T->ir[ref]; if (irref_isk(ref)) { /* Restore constant slot. */ lj_ir_kvalue(L, o, ir); } else { IRType1 t = ir->t; RegSP rs = ir->prev; if (LJ_UNLIKELY(bloomtest(rfilt, ref))) rs = snap_renameref(T, snapno, ref, rs); if (ra_hasspill(regsp_spill(rs))) { /* Restore from spill slot. */ int32_t *sps = &ex->spill[regsp_spill(rs)]; if (irt_isinteger(t)) { setintV(o, *sps); } else if (irt_isnum(t)) { o->u64 = *(uint64_t *)sps; } else { lua_assert(!irt_ispri(t)); /* PRI refs never have a spill slot. */ setgcrefi(o->gcr, *sps); setitype(o, irt_toitype(t)); } } else if (ra_hasreg(regsp_reg(rs))) { /* Restore from register. */ Reg r = regsp_reg(rs); if (irt_isinteger(t)) { setintV(o, ex->gpr[r-RID_MIN_GPR]); } else if (irt_isnum(t)) { setnumV(o, ex->fpr[r-RID_MIN_FPR]); } else { if (!irt_ispri(t)) setgcrefi(o->gcr, ex->gpr[r-RID_MIN_GPR]); setitype(o, irt_toitype(t)); } } else { /* Restore frame slot. */ lua_assert(ir->o == IR_FRAME); /* This works for both PTR and FUNC IR_FRAME. */ setgcrefp(o->fr.func, mref(T->ir[ir->op2].ptr, void)); if (s != 0) /* Do not overwrite link to previous frame. */ o->fr.tp.ftsz = (int32_t)*--flinks; if (irt_isfunc(ir->t)) { GCfunc *fn = gco2func(gcref(T->ir[ir->op2].gcr)); if (isluafunc(fn)) { TValue *fs; newbase = o+1; fs = newbase + funcproto(fn)->framesize; if (fs > ntop) ntop = fs; /* Update top for newly added frames. */ } } } } } else if (newbase) { setnilV(o); /* Clear unreferenced slots of newly added frames. */ } }