/* Specialize to the CTypeID held by a cdata constructor. */ static CTypeID crec_constructor(jit_State *J, GCcdata *cd, TRef tr) { CTypeID id; lua_assert(tref_iscdata(tr) && cd->typeid == CTID_CTYPEID); id = *(CTypeID *)cdataptr(cd); tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCcdata))); tr = emitir(IRT(IR_XLOAD, IRT_INT), tr, 0); emitir(IRTG(IR_EQ, IRT_INT), tr, lj_ir_kint(J, (int32_t)id)); return id; }
static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd) { GCudata *ud = udataV(&J->fn->c.upvalue[0]); TRef tr, one; lj_ir_kgc(J, obj2gco(ud), IRT_UDATA); /* Prevent collection. */ tr = lj_ir_call(J, IRCALL_lj_math_random_step, lj_ir_kptr(J, uddata(ud))); one = lj_ir_knum_one(J); tr = emitir(IRTN(IR_SUB), tr, one); if (J->base[0]) { TRef tr1 = lj_ir_tonum(J, J->base[0]); if (J->base[1]) { /* d = floor(d*(r2-r1+1.0)) + r1 */ TRef tr2 = lj_ir_tonum(J, J->base[1]); tr2 = emitir(IRTN(IR_SUB), tr2, tr1); tr2 = emitir(IRTN(IR_ADD), tr2, one); tr = emitir(IRTN(IR_MUL), tr, tr2); tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR); tr = emitir(IRTN(IR_ADD), tr, tr1); } else { /* d = floor(d*r1) + 1.0 */ tr = emitir(IRTN(IR_MUL), tr, tr1); tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR); tr = emitir(IRTN(IR_ADD), tr, one); } } J->base[0] = tr; UNUSED(rd); }
/* Narrowing of power operator or math.pow. */ TRef lj_opt_narrow_pow(jit_State *J, TRef rb, TRef rc, TValue *vc) { lua_Number n; if (tvisstr(vc) && !lj_str_tonum(strV(vc), vc)) lj_trace_err(J, LJ_TRERR_BADTYPE); n = numV(vc); /* Limit narrowing for pow to small exponents (or for two constants). */ if ((tref_isk(rc) && tref_isint(rc) && tref_isk(rb)) || ((J->flags & JIT_F_OPT_NARROW) && (numisint(n) && n >= -65536.0 && n <= 65536.0))) { TRef tmp; if (!tref_isinteger(rc)) { if (tref_isstr(rc)) rc = emitir(IRTG(IR_STRTO, IRT_NUM), rc, 0); rc = emitir(IRTGI(IR_TOINT), rc, IRTOINT_CHECK); /* Guarded TOINT! */ } if (!tref_isk(rc)) { /* Range guard: -65536 <= i <= 65536 */ tmp = emitir(IRTI(IR_ADD), rc, lj_ir_kint(J, 65536-2147483647-1)); emitir(IRTGI(IR_LE), tmp, lj_ir_kint(J, 2*65536-2147483647-1)); } return emitir(IRTN(IR_POWI), rb, rc); } /* FOLD covers most cases, but some are easier to do here. */ if (tref_isk(rb) && tvispone(ir_knum(IR(tref_ref(rb))))) return rb; /* 1 ^ x ==> 1 */ rc = lj_ir_tonum(J, rc); if (tref_isk(rc) && ir_knum(IR(tref_ref(rc)))->n == 0.5) return emitir(IRTN(IR_FPMATH), rb, IRFPM_SQRT); /* x ^ 0.5 ==> sqrt(x) */ /* Split up b^c into exp2(c*log2(b)). Assembler may rejoin later. */ rb = emitir(IRTN(IR_FPMATH), rb, IRFPM_LOG2); rc = emitir(IRTN(IR_MUL), rb, rc); return emitir(IRTN(IR_FPMATH), rc, IRFPM_EXP2); }
/* Record math.asin, math.acos, math.atan. */ static void LJ_FASTCALL recff_math_atrig(jit_State *J, RecordFFData *rd) { TRef y = lj_ir_tonum(J, J->base[0]); TRef x = lj_ir_knum_one(J); uint32_t ffid = rd->data; if (ffid != FF_math_atan) { TRef tmp = emitir(IRTN(IR_MUL), y, y); tmp = emitir(IRTN(IR_SUB), x, tmp); tmp = emitir(IRTN(IR_FPMATH), tmp, IRFPM_SQRT); if (ffid == FF_math_asin) { x = tmp; } else { x = y; y = tmp; } } J->base[0] = emitir(IRTN(IR_ATAN2), y, x); }
/* Record rounding functions math.floor and math.ceil. */ static void LJ_FASTCALL recff_math_round(jit_State *J, RecordFFData *rd) { TRef tr = J->base[0]; if (!tref_isinteger(tr)) { /* Pass through integers unmodified. */ tr = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, tr), rd->data); /* Result is integral (or NaN/Inf), but may not fit an int32_t. */ if (LJ_DUALNUM) { /* Try to narrow using a guarded conversion to int. */ lua_Number n = lj_vm_foldfpm(numberVnum(&rd->argv[0]), rd->data); if (n == (lua_Number)lj_num2int(n)) tr = emitir(IRTGI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_CHECK); } J->base[0] = tr; } }
static void LJ_FASTCALL recff_math_modf(jit_State *J, RecordFFData *rd) { TRef tr = J->base[0]; if (tref_isinteger(tr)) { J->base[0] = tr; J->base[1] = lj_ir_kint(J, 0); } else { TRef trt; tr = lj_ir_tonum(J, tr); trt = emitir(IRTN(IR_FPMATH), tr, IRFPM_TRUNC); J->base[0] = trt; J->base[1] = emitir(IRTN(IR_SUB), tr, trt); } rd->nres = 2; }
static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd) { TRef tr = J->base[0]; TRef base = J->base[1]; if (tr && base) { base = lj_opt_narrow_toint(J, base); if (!tref_isk(base) || IR(tref_ref(base))->i != 10) recff_nyiu(J); } if (tref_isnumber_str(tr)) { if (tref_isstr(tr)) { TValue tmp; if (!lj_str_tonum(strV(&rd->argv[0]), &tmp)) recff_nyiu(J); /* Would need an inverted STRTO for this case. */ tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); } #if LJ_HASFFI } else if (tref_iscdata(tr)) { lj_crecord_tonumber(J, rd); return; #endif } else { tr = TREF_NIL; } J->base[0] = tr; UNUSED(rd); }
static void LJ_FASTCALL recff_math_degrad(jit_State *J, RecordFFData *rd) { TRef tr = lj_ir_tonum(J, J->base[0]); TRef trm = lj_ir_knum(J, numV(&J->fn->c.upvalue[0])); J->base[0] = emitir(IRTN(IR_MUL), tr, trm); UNUSED(rd); }
/* Record bit shifts. */ static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) { TRef tr = lj_opt_narrow_tobit(J, J->base[0]); TRef tsh = lj_opt_narrow_tobit(J, J->base[1]); IROp op = (IROp)rd->data; if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && !tref_isk(tsh)) tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31)); #ifdef LJ_TARGET_UNIFYROT if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) { op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR; tsh = emitir(IRTI(IR_NEG), tsh, tsh); } #endif J->base[0] = emitir(IRTI(op), tr, tsh); }
static void LJ_FASTCALL recff_table_remove(jit_State *J, RecordFFData *rd) { TRef tab = J->base[0]; rd->nres = 0; if (tref_istab(tab)) { if (!J->base[1] || tref_isnil(J->base[1])) { /* Simple pop: t[#t] = nil */ TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, tab); GCtab *t = tabV(&rd->argv[0]); MSize len = lj_tab_len(t); emitir(IRTGI(len ? IR_NE : IR_EQ), trlen, lj_ir_kint(J, 0)); if (len) { RecordIndex ix; ix.tab = tab; ix.key = trlen; settabV(J->L, &ix.tabv, t); setintV(&ix.keyv, len); ix.idxchain = 0; if (results_wanted(J) != 0) { /* Specialize load only if needed. */ ix.val = 0; J->base[0] = lj_record_idx(J, &ix); /* Load previous value. */ rd->nres = 1; /* Assumes ix.key/ix.tab is not modified for raw lj_record_idx(). */ } ix.val = TREF_NIL; lj_record_idx(J, &ix); /* Remove value. */ } } else { /* Complex case: remove in the middle. */ recff_nyiu(J); } } /* else: Interpreter will throw. */ }
/* Record math.atan2. */ static void LJ_FASTCALL recff_math_atan2(jit_State *J, RecordFFData *rd) { TRef tr = lj_ir_tonum(J, J->base[0]); TRef tr2 = lj_ir_tonum(J, J->base[1]); J->base[0] = emitir(IRTN(IR_ATAN2), tr, tr2); UNUSED(rd); }
/* Determine mode of select() call. */ int32_t lj_ffrecord_select_mode(jit_State *J, TRef tr, TValue *tv) { if (tref_isstr(tr) && *strVdata(tv) == '#') { /* select('#', ...) */ if (strV(tv)->len == 1) { emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, strV(tv))); } else { TRef trptr = emitir(IRT(IR_STRREF, IRT_P32), tr, lj_ir_kint(J, 0)); TRef trchar = emitir(IRT(IR_XLOAD, IRT_U8), trptr, IRXLOAD_READONLY); emitir(IRTG(IR_EQ, IRT_INT), trchar, lj_ir_kint(J, '#')); } return 0; } else { /* select(n, ...) */ int32_t start = argv2int(J, tv); if (start == 0) lj_trace_err(J, LJ_TRERR_BADTYPE); /* A bit misleading. */ return start; } }
/* Emit the conversions collected during backpropagation. */ static IRRef narrow_conv_emit(jit_State *J, NarrowConv *nc) { /* The fins fields must be saved now -- emitir() overwrites them. */ IROpT guardot = irt_isguard(fins->t) ? IRTG(IR_ADDOV-IR_ADD, 0) : 0; IROpT convot = fins->ot; IRRef1 convop2 = fins->op2; NarrowIns *next = nc->stack; /* List of instructions from backpropagation. */ NarrowIns *last = nc->sp; NarrowIns *sp = nc->stack; /* Recycle the stack to store operands. */ while (next < last) { /* Simple stack machine to process the ins. list. */ NarrowIns ref = *next++; IROpT op = narrow_op(ref); if (op == NARROW_REF) { *sp++ = ref; } else if (op == NARROW_CONV) { *sp++ = emitir_raw(convot, ref, convop2); /* Raw emit avoids a loop. */ } else if (op == NARROW_SEXT) { lua_assert(sp >= nc->stack+1); sp[-1] = emitir(IRT(IR_CONV, IRT_I64), sp[-1], (IRT_I64<<5)|IRT_INT|IRCONV_SEXT); } else if (op == NARROW_INT) { lua_assert(next < last); *sp++ = nc->t == IRT_I64 ? lj_ir_kint64(J, (int64_t)(int32_t)*next++) : lj_ir_kint(J, *next++); } else { /* Regular IROpT. Pops two operands and pushes one result. */ IRRef mode = nc->mode; lua_assert(sp >= nc->stack+2); sp--; /* Omit some overflow checks for array indexing. See comments above. */ if ((mode & IRCONV_CONVMASK) == IRCONV_INDEX) { if (next == last && irref_isk(narrow_ref(sp[0])) && (uint32_t)IR(narrow_ref(sp[0]))->i + 0x40000000u < 0x80000000u) guardot = 0; else /* Otherwise cache a stronger check. */ mode += IRCONV_CHECK-IRCONV_INDEX; } sp[-1] = emitir(op+guardot, sp[-1], sp[0]); /* Add to cache. */ if (narrow_ref(ref)) narrow_bpc_set(J, narrow_ref(ref), narrow_ref(sp[-1]), mode); } } lua_assert(sp == nc->stack+1); return nc->stack[0]; }
static void LJ_FASTCALL recff_math_minmax(jit_State *J, RecordFFData *rd) { TRef tr = lj_ir_tonumber(J, J->base[0]); uint32_t op = rd->data; BCReg i; for (i = 1; J->base[i] != 0; i++) { TRef tr2 = lj_ir_tonumber(J, J->base[i]); IRType t = IRT_INT; if (!(tref_isinteger(tr) && tref_isinteger(tr2))) { if (tref_isinteger(tr)) tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT); if (tref_isinteger(tr2)) tr2 = emitir(IRTN(IR_CONV), tr2, IRCONV_NUM_INT); t = IRT_NUM; } tr = emitir(IRT(op, t), tr, tr2); } J->base[0] = tr; }
/* Get FILE* for I/O function. Any I/O error aborts recording, so there's ** no need to encode the alternate cases for any of the guards. */ static TRef recff_io_fp(jit_State *J, uint32_t id) { TRef tr, ud, fp; if (id) { /* io.func() */ tr = lj_ir_kptr(J, &J2G(J)->gcroot[id]); ud = emitir(IRT(IR_XLOAD, IRT_UDATA), tr, 0); } else { /* fp:method() */ ud = J->base[0]; if (!tref_isudata(ud)) lj_trace_err(J, LJ_TRERR_BADTYPE); tr = emitir(IRT(IR_FLOAD, IRT_U8), ud, IRFL_UDATA_UDTYPE); emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, UDTYPE_IO_FILE)); } fp = emitir(IRT(IR_FLOAD, IRT_PTR), ud, IRFL_UDATA_FILE); emitir(IRTG(IR_NE, IRT_PTR), fp, lj_ir_knull(J, IRT_PTR)); return fp; }
static void LJ_FASTCALL recff_io_flush(jit_State *J, RecordFFData *rd) { TRef fp = recff_io_fp(J, rd->data); TRef tr = lj_ir_call(J, IRCALL_fflush, fp); if (results_wanted(J) != 0) /* Check result only if not ignored. */ emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, 0)); J->base[0] = TREF_TRUE; }
/* Record N-ary bit.band, bit.bor, bit.bxor. */ static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd) { TRef tr = lj_opt_narrow_tobit(J, J->base[0]); uint32_t op = rd->data; BCReg i; for (i = 1; J->base[i] != 0; i++) tr = emitir(IRTI(op), tr, lj_opt_narrow_tobit(J, J->base[i])); J->base[0] = tr; }
static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp) { CTState *cts = ctype_ctsG(J2G(J)); CTInfo sinfo = s->info; lua_assert(!ctype_isenum(sinfo)); if (ctype_isnum(sinfo)) { IRType t = crec_ct2irt(s); TRef tr; if (t == IRT_CDATA) goto err_nyi; /* NYI: copyval of >64 bit integers. */ tr = emitir(IRT(IR_XLOAD, t), sp, 0); if (t == IRT_FLOAT || t == IRT_U32) { /* Keep uint32_t/float as numbers. */ return emitconv(tr, IRT_NUM, t, 0); } else if (t == IRT_I64 || t == IRT_U64) { /* Box 64 bit integer. */ sp = tr; lj_needsplit(J); } else if ((sinfo & CTF_BOOL)) { /* Assume not equal to zero. Fixup and emit pending guard later. */ lj_ir_set(J, IRTGI(IR_NE), tr, lj_ir_kint(J, 0)); J->postproc = LJ_POST_FIXGUARD; return TREF_TRUE; } else { return tr; } } else if (ctype_isptr(sinfo)) { IRType t = (LJ_64 && s->size == 8) ? IRT_P64 : IRT_P32; sp = emitir(IRT(IR_XLOAD, t), sp, 0); } else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) { cts->L = J->L; sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */ } else if (ctype_iscomplex(sinfo)) { /* Unbox/box complex. */ IRType t = s->size == 2*sizeof(double) ? IRT_NUM : IRT_FLOAT; ptrdiff_t esz = (ptrdiff_t)(s->size >> 1); TRef ptr, tr1, tr2, dp; dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, sid), TREF_NIL); tr1 = emitir(IRT(IR_XLOAD, t), sp, 0); ptr = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, esz)); tr2 = emitir(IRT(IR_XLOAD, t), ptr, 0); ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata))); emitir(IRT(IR_XSTORE, t), ptr, tr1); ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata)+esz)); emitir(IRT(IR_XSTORE, t), ptr, tr2); return dp; } else {
static void LJ_FASTCALL recff_setmetatable(jit_State *J, RecordFFData *rd) { TRef tr = J->base[0]; TRef mt = J->base[1]; if (tref_istab(tr) && (tref_istab(mt) || (mt && tref_isnil(mt)))) { TRef fref, mtref; RecordIndex ix; ix.tab = tr; copyTV(J->L, &ix.tabv, &rd->argv[0]); lj_record_mm_lookup(J, &ix, MM_metatable); /* Guard for no __metatable. */ fref = emitir(IRT(IR_FREF, IRT_P32), tr, IRFL_TAB_META); mtref = tref_isnil(mt) ? lj_ir_knull(J, IRT_TAB) : mt; emitir(IRT(IR_FSTORE, IRT_TAB), fref, mtref); if (!tref_isnil(mt)) emitir(IRT(IR_TBAR, IRT_TAB), tr, 0); J->base[0] = tr; J->needsnap = 1; } /* else: Interpreter will throw. */ }
/* Narrowing of modulo operator. */ TRef lj_opt_narrow_mod(jit_State *J, TRef rb, TRef rc) { TRef tmp; if ((J->flags & JIT_F_OPT_NARROW) && tref_isk(rc) && tref_isint(rc)) { /* Optimize x % k. */ int32_t k = IR(tref_ref(rc))->i; if (k > 0 && (k & (k-1)) == 0) { /* i % 2^k ==> band(i, 2^k-1) */ if (tref_isinteger(rb)) return emitir(IRTI(IR_BAND), rb, lj_ir_kint(J, k-1)); } } /* b % c ==> b - floor(b/c)*c */ rb = lj_ir_tonum(J, rb); rc = lj_ir_tonum(J, rc); tmp = emitir(IRTN(IR_DIV), rb, rc); tmp = emitir(IRTN(IR_FPMATH), tmp, IRFPM_FLOOR); tmp = emitir(IRTN(IR_MUL), tmp, rc); return emitir(IRTN(IR_SUB), rb, tmp); }
static void LJ_FASTCALL recff_rawlen(jit_State *J, RecordFFData *rd) { TRef tr = J->base[0]; if (tref_isstr(tr)) J->base[0] = emitir(IRTI(IR_FLOAD), tr, IRFL_STR_LEN); else if (tref_istab(tr)) J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, tr); /* else: Interpreter will throw. */ UNUSED(rd); }
/* Record math.ldexp. */ static void LJ_FASTCALL recff_math_ldexp(jit_State *J, RecordFFData *rd) { TRef tr = lj_ir_tonum(J, J->base[0]); #if LJ_TARGET_X86ORX64 TRef tr2 = lj_ir_tonum(J, J->base[1]); #else TRef tr2 = lj_opt_narrow_toint(J, J->base[1]); #endif J->base[0] = emitir(IRTN(IR_LDEXP), tr, tr2); UNUSED(rd); }
/* Record math.log. */ static void LJ_FASTCALL recff_math_log(jit_State *J, RecordFFData *rd) { TRef tr = lj_ir_tonum(J, J->base[0]); if (J->base[1]) { #ifdef LUAJIT_NO_LOG2 uint32_t fpm = IRFPM_LOG; #else uint32_t fpm = IRFPM_LOG2; #endif TRef trb = lj_ir_tonum(J, J->base[1]); tr = emitir(IRTN(IR_FPMATH), tr, fpm); trb = emitir(IRTN(IR_FPMATH), trb, fpm); trb = emitir(IRTN(IR_DIV), lj_ir_knum_one(J), trb); tr = emitir(IRTN(IR_MUL), tr, trb); } else { tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_LOG); } J->base[0] = tr; UNUSED(rd); }
static GCcdata *argv2cdata(jit_State *J, TRef tr, cTValue *o) { GCcdata *cd; TRef trtypeid; if (!tref_iscdata(tr)) lj_trace_err(J, LJ_TRERR_BADTYPE); cd = cdataV(o); /* Specialize to the CTypeID. */ trtypeid = emitir(IRT(IR_FLOAD, IRT_U16), tr, IRFL_CDATA_TYPEID); emitir(IRTG(IR_EQ, IRT_INT), trtypeid, lj_ir_kint(J, (int32_t)cd->typeid)); return cd; }
/* Emit parent reference with de-duplication. */ static TRef snap_pref(jit_State *J, GCtrace *T, SnapEntry *map, MSize nmax, BloomFilter seen, IRRef ref) { IRIns *ir = &T->ir[ref]; TRef tr; if (irref_isk(ref)) tr = snap_replay_const(J, ir); else if (!regsp_used(ir->prev)) tr = 0; else if (!bloomtest(seen, ref) || (tr = snap_dedup(J, map, nmax, ref)) == 0) tr = emitir(IRT(IR_PVAL, irt_type(ir->t)), ref - REF_BIAS, 0); return tr; }
static void LJ_FASTCALL recff_io_write(jit_State *J, RecordFFData *rd) { TRef fp = recff_io_fp(J, rd->data); TRef zero = lj_ir_kint(J, 0); TRef one = lj_ir_kint(J, 1); ptrdiff_t i = rd->data == 0 ? 1 : 0; for (; J->base[i]; i++) { TRef str = lj_ir_tostr(J, J->base[i]); TRef buf = emitir(IRT(IR_STRREF, IRT_P32), str, zero); TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN); if (tref_isk(len) && IR(tref_ref(len))->i == 1) { TRef tr = emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY); tr = lj_ir_call(J, IRCALL_fputc, tr, fp); if (results_wanted(J) != 0) /* Check result only if not ignored. */ emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1)); } else { TRef tr = lj_ir_call(J, IRCALL_fwrite, buf, one, len, fp); if (results_wanted(J) != 0) /* Check result only if not ignored. */ emitir(IRTGI(IR_EQ), tr, len); } } J->base[0] = TREF_TRUE; }
static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd) { RecordIndex ix; ix.tab = J->base[0]; if (tref_istab(ix.tab)) { if (!tvisnumber(&rd->argv[1])) /* No support for string coercion. */ lj_trace_err(J, LJ_TRERR_BADTYPE); setintV(&ix.keyv, numberVint(&rd->argv[1])+1); settabV(J->L, &ix.tabv, tabV(&rd->argv[0])); ix.val = 0; ix.idxchain = 0; ix.key = lj_opt_narrow_toint(J, J->base[1]); J->base[0] = ix.key = emitir(IRTI(IR_ADD), ix.key, lj_ir_kint(J, 1)); J->base[1] = lj_record_idx(J, &ix); rd->nres = tref_isnil(J->base[1]) ? 0 : 2; } /* else: Interpreter will throw. */ }
static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd) { TRef tr = J->base[0]; if (tref_isstr(tr)) { /* Ignore __tostring in the string base metatable. */ /* Pass on result in J->base[0]. */ } else if (!recff_metacall(J, rd, MM_tostring)) { if (tref_isnumber(tr)) { J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); } else if (tref_ispri(tr)) { J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)])); } else { recff_nyiu(J); } } }
static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) { RecordIndex ix; ix.tab = J->base[0]; ix.val = J->base[1]; rd->nres = 0; if (tref_istab(ix.tab) && ix.val) { if (!J->base[2]) { /* Simple push: t[#t+1] = v */ TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, ix.tab); GCtab *t = tabV(&rd->argv[0]); ix.key = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1)); settabV(J->L, &ix.tabv, t); setintV(&ix.keyv, lj_tab_len(t) + 1); ix.idxchain = 0; lj_record_idx(J, &ix); /* Set new value. */ } else { /* Complex case: insert in the middle. */ recff_nyiu(J); } } /* else: Interpreter will throw. */ }
static CTypeID argv2ctype(jit_State *J, TRef tr, cTValue *o) { if (tref_isstr(tr)) { GCstr *s = strV(o); CPState cp; CTypeID oldtop; /* Specialize to the string containing the C type declaration. */ emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, s)); cp.L = J->L; cp.cts = ctype_ctsG(J2G(J)); oldtop = cp.cts->top; cp.srcname = strdata(s); cp.p = strdata(s); cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT; if (lj_cparse(&cp) || cp.cts->top > oldtop) /* Avoid new struct defs. */ lj_trace_err(J, LJ_TRERR_BADTYPE); return cp.val.id; } else { GCcdata *cd = argv2cdata(J, tr, o); return cd->typeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->typeid; } }