root/lj_ffrecord.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. argv2int
  2. argv2str
  3. results_wanted
  4. recff_stitch
  5. recff_nyi
  6. recff_bufhdr
  7. recff_assert
  8. recff_type
  9. recff_getmetatable
  10. recff_setmetatable
  11. recff_rawget
  12. recff_rawset
  13. recff_rawequal
  14. recff_rawlen
  15. lj_ffrecord_select_mode
  16. recff_select
  17. recff_tonumber
  18. recff_metacall_cp
  19. recff_metacall
  20. recff_tostring
  21. recff_ipairs_aux
  22. recff_xpairs
  23. recff_pcall
  24. recff_xpcall_cp
  25. recff_xpcall
  26. recff_getfenv
  27. recff_math_abs
  28. recff_math_round
  29. recff_math_unary
  30. recff_math_log
  31. recff_math_atan2
  32. recff_math_ldexp
  33. recff_math_atrig
  34. recff_math_htrig
  35. recff_math_modf
  36. recff_math_pow
  37. recff_math_minmax
  38. recff_math_random
  39. recff_bit_tobit
  40. recff_bit_unary
  41. recff_bit_nary
  42. recff_bit_shift
  43. recff_bit_tohex
  44. recff_string_start
  45. recff_string_range
  46. recff_string_char
  47. recff_string_rep
  48. recff_string_op
  49. recff_string_find
  50. recff_string_format
  51. recff_table_insert
  52. recff_table_concat
  53. recff_table_new
  54. recff_table_clear
  55. recff_io_fp
  56. recff_io_write
  57. recff_io_flush
  58. recff_debug_getmetatable
  59. recdef_lookup
  60. lj_ffrecord_func

   1 /*
   2 ** Fast function call recorder.
   3 ** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
   4 */
   5 
   6 #define lj_ffrecord_c
   7 #define LUA_CORE
   8 
   9 #include "lj_obj.h"
  10 
  11 #if LJ_HASJIT
  12 
  13 #include "lj_err.h"
  14 #include "lj_str.h"
  15 #include "lj_tab.h"
  16 #include "lj_frame.h"
  17 #include "lj_bc.h"
  18 #include "lj_ff.h"
  19 #include "lj_ir.h"
  20 #include "lj_jit.h"
  21 #include "lj_ircall.h"
  22 #include "lj_iropt.h"
  23 #include "lj_trace.h"
  24 #include "lj_record.h"
  25 #include "lj_ffrecord.h"
  26 #include "lj_crecord.h"
  27 #include "lj_dispatch.h"
  28 #include "lj_vm.h"
  29 #include "lj_strscan.h"
  30 #include "lj_strfmt.h"
  31 
  32 /* Some local macros to save typing. Undef'd at the end. */
  33 #define IR(ref)                 (&J->cur.ir[(ref)])
  34 
  35 /* Pass IR on to next optimization in chain (FOLD). */
  36 #define emitir(ot, a, b)        (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J))
  37 
  38 /* -- Fast function recording handlers ------------------------------------ */
  39 
  40 /* Conventions for fast function call handlers:
  41 **
  42 ** The argument slots start at J->base[0]. All of them are guaranteed to be
  43 ** valid and type-specialized references. J->base[J->maxslot] is set to 0
  44 ** as a sentinel. The runtime argument values start at rd->argv[0].
  45 **
  46 ** In general fast functions should check for presence of all of their
  47 ** arguments and for the correct argument types. Some simplifications
  48 ** are allowed if the interpreter throws instead. But even if recording
  49 ** is aborted, the generated IR must be consistent (no zero-refs).
  50 **
  51 ** The number of results in rd->nres is set to 1. Handlers that return
  52 ** a different number of results need to override it. A negative value
  53 ** prevents return processing (e.g. for pending calls).
  54 **
  55 ** Results need to be stored starting at J->base[0]. Return processing
  56 ** moves them to the right slots later.
  57 **
  58 ** The per-ffid auxiliary data is the value of the 2nd part of the
  59 ** LJLIB_REC() annotation. This allows handling similar functionality
  60 ** in a common handler.
  61 */
  62 
  63 /* Type of handler to record a fast function. */
  64 typedef void (LJ_FASTCALL *RecordFunc)(jit_State *J, RecordFFData *rd);
  65 
  66 /* Get runtime value of int argument. */
  67 static int32_t argv2int(jit_State *J, TValue *o)
  68 {
  69   if (!lj_strscan_numberobj(o))
  70     lj_trace_err(J, LJ_TRERR_BADTYPE);
  71   return tvisint(o) ? intV(o) : lj_num2int(numV(o));
  72 }
  73 
  74 /* Get runtime value of string argument. */
  75 static GCstr *argv2str(jit_State *J, TValue *o)
  76 {
  77   if (LJ_LIKELY(tvisstr(o))) {
  78     return strV(o);
  79   } else {
  80     GCstr *s;
  81     if (!tvisnumber(o))
  82       lj_trace_err(J, LJ_TRERR_BADTYPE);
  83     s = lj_strfmt_number(J->L, o);
  84     setstrV(J->L, o, s);
  85     return s;
  86   }
  87 }
  88 
  89 /* Return number of results wanted by caller. */
  90 static ptrdiff_t results_wanted(jit_State *J)
  91 {
  92   TValue *frame = J->L->base-1;
  93   if (frame_islua(frame))
  94     return (ptrdiff_t)bc_b(frame_pc(frame)[-1]) - 1;
  95   else
  96     return -1;
  97 }
  98 
  99 /* Trace stitching: add continuation below frame to start a new trace. */
 100 static void recff_stitch(jit_State *J)
 101 {
 102   ASMFunction cont = lj_cont_stitch;
 103   lua_State *L = J->L;
 104   TValue *base = L->base;
 105   BCReg nslot = J->maxslot + 1 + LJ_FR2;
 106   TValue *nframe = base + 1 + LJ_FR2;
 107   const BCIns *pc = frame_pc(base-1);
 108   TValue *pframe = frame_prevl(base-1);
 109 
 110   /* Move func + args up in Lua stack and insert continuation. */
 111   memmove(&base[1], &base[-1-LJ_FR2], sizeof(TValue)*nslot);
 112   setframe_ftsz(nframe, ((char *)nframe - (char *)pframe) + FRAME_CONT);
 113   setcont(base-LJ_FR2, cont);
 114   setframe_pc(base, pc);
 115   setnilV(base-1-LJ_FR2);  /* Incorrect, but rec_check_slots() won't run anymore. */
 116   L->base += 2 + LJ_FR2;
 117   L->top += 2 + LJ_FR2;
 118 
 119   /* Ditto for the IR. */
 120   memmove(&J->base[1], &J->base[-1-LJ_FR2], sizeof(TRef)*nslot);
 121 #if LJ_FR2
 122   J->base[2] = TREF_FRAME;
 123   J->base[-1] = lj_ir_k64(J, IR_KNUM, u64ptr(contptr(cont)));
 124   J->base[0] = lj_ir_k64(J, IR_KNUM, u64ptr(pc)) | TREF_CONT;
 125 #else
 126   J->base[0] = lj_ir_kptr(J, contptr(cont)) | TREF_CONT;
 127 #endif
 128   J->ktrace = tref_ref((J->base[-1-LJ_FR2] = lj_ir_ktrace(J)));
 129   J->base += 2 + LJ_FR2;
 130   J->baseslot += 2 + LJ_FR2;
 131   J->framedepth++;
 132 
 133   lj_record_stop(J, LJ_TRLINK_STITCH, 0);
 134 
 135   /* Undo Lua stack changes. */
 136   memmove(&base[-1-LJ_FR2], &base[1], sizeof(TValue)*nslot);
 137   setframe_pc(base-1, pc);
 138   L->base -= 2 + LJ_FR2;
 139   L->top -= 2 + LJ_FR2;
 140 }
 141 
 142 /* Fallback handler for fast functions that are not recorded (yet). */
 143 static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd)
 144 {
 145   if (J->cur.nins < (IRRef)J->param[JIT_P_minstitch] + REF_BASE) {
 146     lj_trace_err_info(J, LJ_TRERR_TRACEUV);
 147   } else {
 148     /* Can only stitch from Lua call. */
 149     if (J->framedepth && frame_islua(J->L->base-1)) {
 150       BCOp op = bc_op(*frame_pc(J->L->base-1));
 151       /* Stitched trace cannot start with *M op with variable # of args. */
 152       if (!(op == BC_CALLM || op == BC_CALLMT ||
 153             op == BC_RETM || op == BC_TSETM)) {
 154         switch (J->fn->c.ffid) {
 155         case FF_error:
 156         case FF_debug_sethook:
 157         case FF_jit_flush:
 158           break;  /* Don't stitch across special builtins. */
 159         default:
 160           recff_stitch(J);  /* Use trace stitching. */
 161           rd->nres = -1;
 162           return;
 163         }
 164       }
 165     }
 166     /* Otherwise stop trace and return to interpreter. */
 167     lj_record_stop(J, LJ_TRLINK_RETURN, 0);
 168     rd->nres = -1;
 169   }
 170 }
 171 
 172 /* Fallback handler for unsupported variants of fast functions. */
 173 #define recff_nyiu      recff_nyi
 174 
 175 /* Must stop the trace for classic C functions with arbitrary side-effects. */
 176 #define recff_c         recff_nyi
 177 
 178 /* Emit BUFHDR for the global temporary buffer. */
 179 static TRef recff_bufhdr(jit_State *J)
 180 {
 181   return emitir(IRT(IR_BUFHDR, IRT_PGC),
 182                 lj_ir_kptr(J, &J2G(J)->tmpbuf), IRBUFHDR_RESET);
 183 }
 184 
 185 /* -- Base library fast functions ----------------------------------------- */
 186 
 187 static void LJ_FASTCALL recff_assert(jit_State *J, RecordFFData *rd)
 188 {
 189   /* Arguments already specialized. The interpreter throws for nil/false. */
 190   rd->nres = J->maxslot;  /* Pass through all arguments. */
 191 }
 192 
 193 static void LJ_FASTCALL recff_type(jit_State *J, RecordFFData *rd)
 194 {
 195   /* Arguments already specialized. Result is a constant string. Neat, huh? */
 196   uint32_t t;
 197   if (tvisnumber(&rd->argv[0]))
 198     t = ~LJ_TNUMX;
 199   else if (LJ_64 && !LJ_GC64 && tvislightud(&rd->argv[0]))
 200     t = ~LJ_TLIGHTUD;
 201   else
 202     t = ~itype(&rd->argv[0]);
 203   J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[t]));
 204   UNUSED(rd);
 205 }
 206 
 207 static void LJ_FASTCALL recff_getmetatable(jit_State *J, RecordFFData *rd)
 208 {
 209   TRef tr = J->base[0];
 210   if (tr) {
 211     RecordIndex ix;
 212     ix.tab = tr;
 213     copyTV(J->L, &ix.tabv, &rd->argv[0]);
 214     if (lj_record_mm_lookup(J, &ix, MM_metatable))
 215       J->base[0] = ix.mobj;
 216     else
 217       J->base[0] = ix.mt;
 218   }  /* else: Interpreter will throw. */
 219 }
 220 
 221 static void LJ_FASTCALL recff_setmetatable(jit_State *J, RecordFFData *rd)
 222 {
 223   TRef tr = J->base[0];
 224   TRef mt = J->base[1];
 225   if (tref_istab(tr) && (tref_istab(mt) || (mt && tref_isnil(mt)))) {
 226     TRef fref, mtref;
 227     RecordIndex ix;
 228     ix.tab = tr;
 229     copyTV(J->L, &ix.tabv, &rd->argv[0]);
 230     lj_record_mm_lookup(J, &ix, MM_metatable); /* Guard for no __metatable. */
 231     fref = emitir(IRT(IR_FREF, IRT_PGC), tr, IRFL_TAB_META);
 232     mtref = tref_isnil(mt) ? lj_ir_knull(J, IRT_TAB) : mt;
 233     emitir(IRT(IR_FSTORE, IRT_TAB), fref, mtref);
 234     if (!tref_isnil(mt))
 235       emitir(IRT(IR_TBAR, IRT_TAB), tr, 0);
 236     J->base[0] = tr;
 237     J->needsnap = 1;
 238   }  /* else: Interpreter will throw. */
 239 }
 240 
 241 static void LJ_FASTCALL recff_rawget(jit_State *J, RecordFFData *rd)
 242 {
 243   RecordIndex ix;
 244   ix.tab = J->base[0]; ix.key = J->base[1];
 245   if (tref_istab(ix.tab) && ix.key) {
 246     ix.val = 0; ix.idxchain = 0;
 247     settabV(J->L, &ix.tabv, tabV(&rd->argv[0]));
 248     copyTV(J->L, &ix.keyv, &rd->argv[1]);
 249     J->base[0] = lj_record_idx(J, &ix);
 250   }  /* else: Interpreter will throw. */
 251 }
 252 
 253 static void LJ_FASTCALL recff_rawset(jit_State *J, RecordFFData *rd)
 254 {
 255   RecordIndex ix;
 256   ix.tab = J->base[0]; ix.key = J->base[1]; ix.val = J->base[2];
 257   if (tref_istab(ix.tab) && ix.key && ix.val) {
 258     ix.idxchain = 0;
 259     settabV(J->L, &ix.tabv, tabV(&rd->argv[0]));
 260     copyTV(J->L, &ix.keyv, &rd->argv[1]);
 261     copyTV(J->L, &ix.valv, &rd->argv[2]);
 262     lj_record_idx(J, &ix);
 263     /* Pass through table at J->base[0] as result. */
 264   }  /* else: Interpreter will throw. */
 265 }
 266 
 267 static void LJ_FASTCALL recff_rawequal(jit_State *J, RecordFFData *rd)
 268 {
 269   TRef tra = J->base[0];
 270   TRef trb = J->base[1];
 271   if (tra && trb) {
 272     int diff = lj_record_objcmp(J, tra, trb, &rd->argv[0], &rd->argv[1]);
 273     J->base[0] = diff ? TREF_FALSE : TREF_TRUE;
 274   }  /* else: Interpreter will throw. */
 275 }
 276 
 277 #if LJ_52
 278 static void LJ_FASTCALL recff_rawlen(jit_State *J, RecordFFData *rd)
 279 {
 280   TRef tr = J->base[0];
 281   if (tref_isstr(tr))
 282     J->base[0] = emitir(IRTI(IR_FLOAD), tr, IRFL_STR_LEN);
 283   else if (tref_istab(tr))
 284     J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, tr);
 285   /* else: Interpreter will throw. */
 286   UNUSED(rd);
 287 }
 288 #endif
 289 
 290 /* Determine mode of select() call. */
 291 int32_t lj_ffrecord_select_mode(jit_State *J, TRef tr, TValue *tv)
 292 {
 293   if (tref_isstr(tr) && *strVdata(tv) == '#') {  /* select('#', ...) */
 294     if (strV(tv)->len == 1) {
 295       emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, strV(tv)));
 296     } else {
 297       TRef trptr = emitir(IRT(IR_STRREF, IRT_PGC), tr, lj_ir_kint(J, 0));
 298       TRef trchar = emitir(IRT(IR_XLOAD, IRT_U8), trptr, IRXLOAD_READONLY);
 299       emitir(IRTG(IR_EQ, IRT_INT), trchar, lj_ir_kint(J, '#'));
 300     }
 301     return 0;
 302   } else {  /* select(n, ...) */
 303     int32_t start = argv2int(J, tv);
 304     if (start == 0) lj_trace_err(J, LJ_TRERR_BADTYPE);  /* A bit misleading. */
 305     return start;
 306   }
 307 }
 308 
 309 static void LJ_FASTCALL recff_select(jit_State *J, RecordFFData *rd)
 310 {
 311   TRef tr = J->base[0];
 312   if (tr) {
 313     ptrdiff_t start = lj_ffrecord_select_mode(J, tr, &rd->argv[0]);
 314     if (start == 0) {  /* select('#', ...) */
 315       J->base[0] = lj_ir_kint(J, J->maxslot - 1);
 316     } else if (tref_isk(tr)) {  /* select(k, ...) */
 317       ptrdiff_t n = (ptrdiff_t)J->maxslot;
 318       if (start < 0) start += n;
 319       else if (start > n) start = n;
 320       rd->nres = n - start;
 321       if (start >= 1) {
 322         ptrdiff_t i;
 323         for (i = 0; i < n - start; i++)
 324           J->base[i] = J->base[start+i];
 325       }  /* else: Interpreter will throw. */
 326     } else {
 327       recff_nyiu(J, rd);
 328       return;
 329     }
 330   }  /* else: Interpreter will throw. */
 331 }
 332 
 333 static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd)
 334 {
 335   TRef tr = J->base[0];
 336   TRef base = J->base[1];
 337   if (tr && !tref_isnil(base)) {
 338     base = lj_opt_narrow_toint(J, base);
 339     if (!tref_isk(base) || IR(tref_ref(base))->i != 10) {
 340       recff_nyiu(J, rd);
 341       return;
 342     }
 343   }
 344   if (tref_isnumber_str(tr)) {
 345     if (tref_isstr(tr)) {
 346       TValue tmp;
 347       if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) {
 348         recff_nyiu(J, rd);  /* Would need an inverted STRTO for this case. */
 349         return;
 350       }
 351       tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0);
 352     }
 353 #if LJ_HASFFI
 354   } else if (tref_iscdata(tr)) {
 355     lj_crecord_tonumber(J, rd);
 356     return;
 357 #endif
 358   } else {
 359     tr = TREF_NIL;
 360   }
 361   J->base[0] = tr;
 362   UNUSED(rd);
 363 }
 364 
 365 static TValue *recff_metacall_cp(lua_State *L, lua_CFunction dummy, void *ud)
 366 {
 367   jit_State *J = (jit_State *)ud;
 368   lj_record_tailcall(J, 0, 1);
 369   UNUSED(L); UNUSED(dummy);
 370   return NULL;
 371 }
 372 
 373 static int recff_metacall(jit_State *J, RecordFFData *rd, MMS mm)
 374 {
 375   RecordIndex ix;
 376   ix.tab = J->base[0];
 377   copyTV(J->L, &ix.tabv, &rd->argv[0]);
 378   if (lj_record_mm_lookup(J, &ix, mm)) {  /* Has metamethod? */
 379     int errcode;
 380     TValue argv0;
 381     /* Temporarily insert metamethod below object. */
 382     J->base[1+LJ_FR2] = J->base[0];
 383     J->base[0] = ix.mobj;
 384     copyTV(J->L, &argv0, &rd->argv[0]);
 385     copyTV(J->L, &rd->argv[1+LJ_FR2], &rd->argv[0]);
 386     copyTV(J->L, &rd->argv[0], &ix.mobjv);
 387     /* Need to protect lj_record_tailcall because it may throw. */
 388     errcode = lj_vm_cpcall(J->L, NULL, J, recff_metacall_cp);
 389     /* Always undo Lua stack changes to avoid confusing the interpreter. */
 390     copyTV(J->L, &rd->argv[0], &argv0);
 391     if (errcode)
 392       lj_err_throw(J->L, errcode);  /* Propagate errors. */
 393     rd->nres = -1;  /* Pending call. */
 394     return 1;  /* Tailcalled to metamethod. */
 395   }
 396   return 0;
 397 }
 398 
 399 static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd)
 400 {
 401   TRef tr = J->base[0];
 402   if (tref_isstr(tr)) {
 403     /* Ignore __tostring in the string base metatable. */
 404     /* Pass on result in J->base[0]. */
 405   } else if (tr && !recff_metacall(J, rd, MM_tostring)) {
 406     if (tref_isnumber(tr)) {
 407       J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr,
 408                           tref_isnum(tr) ? IRTOSTR_NUM : IRTOSTR_INT);
 409     } else if (tref_ispri(tr)) {
 410       J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0]));
 411     } else {
 412       recff_nyiu(J, rd);
 413       return;
 414     }
 415   }
 416 }
 417 
 418 static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd)
 419 {
 420   RecordIndex ix;
 421   ix.tab = J->base[0];
 422   if (tref_istab(ix.tab)) {
 423     if (!tvisnumber(&rd->argv[1]))  /* No support for string coercion. */
 424       lj_trace_err(J, LJ_TRERR_BADTYPE);
 425     setintV(&ix.keyv, numberVint(&rd->argv[1])+1);
 426     settabV(J->L, &ix.tabv, tabV(&rd->argv[0]));
 427     ix.val = 0; ix.idxchain = 0;
 428     ix.key = lj_opt_narrow_toint(J, J->base[1]);
 429     J->base[0] = ix.key = emitir(IRTI(IR_ADD), ix.key, lj_ir_kint(J, 1));
 430     J->base[1] = lj_record_idx(J, &ix);
 431     rd->nres = tref_isnil(J->base[1]) ? 0 : 2;
 432   }  /* else: Interpreter will throw. */
 433 }
 434 
 435 static void LJ_FASTCALL recff_xpairs(jit_State *J, RecordFFData *rd)
 436 {
 437   TRef tr = J->base[0];
 438   if (!((LJ_52 || (LJ_HASFFI && tref_iscdata(tr))) &&
 439         recff_metacall(J, rd, MM_pairs + rd->data))) {
 440     if (tref_istab(tr)) {
 441       J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0]));
 442       J->base[1] = tr;
 443       J->base[2] = rd->data ? lj_ir_kint(J, 0) : TREF_NIL;
 444       rd->nres = 3;
 445     }  /* else: Interpreter will throw. */
 446   }
 447 }
 448 
 449 static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd)
 450 {
 451   if (J->maxslot >= 1) {
 452 #if LJ_FR2
 453     /* Shift function arguments up. */
 454     memmove(J->base + 1, J->base, sizeof(TRef) * J->maxslot);
 455 #endif
 456     lj_record_call(J, 0, J->maxslot - 1);
 457     rd->nres = -1;  /* Pending call. */
 458   }  /* else: Interpreter will throw. */
 459 }
 460 
 461 static TValue *recff_xpcall_cp(lua_State *L, lua_CFunction dummy, void *ud)
 462 {
 463   jit_State *J = (jit_State *)ud;
 464   lj_record_call(J, 1, J->maxslot - 2);
 465   UNUSED(L); UNUSED(dummy);
 466   return NULL;
 467 }
 468 
 469 static void LJ_FASTCALL recff_xpcall(jit_State *J, RecordFFData *rd)
 470 {
 471   if (J->maxslot >= 2) {
 472     TValue argv0, argv1;
 473     TRef tmp;
 474     int errcode;
 475     /* Swap function and traceback. */
 476     tmp = J->base[0]; J->base[0] = J->base[1]; J->base[1] = tmp;
 477     copyTV(J->L, &argv0, &rd->argv[0]);
 478     copyTV(J->L, &argv1, &rd->argv[1]);
 479     copyTV(J->L, &rd->argv[0], &argv1);
 480     copyTV(J->L, &rd->argv[1], &argv0);
 481 #if LJ_FR2
 482     /* Shift function arguments up. */
 483     memmove(J->base + 2, J->base + 1, sizeof(TRef) * (J->maxslot-1));
 484 #endif
 485     /* Need to protect lj_record_call because it may throw. */
 486     errcode = lj_vm_cpcall(J->L, NULL, J, recff_xpcall_cp);
 487     /* Always undo Lua stack swap to avoid confusing the interpreter. */
 488     copyTV(J->L, &rd->argv[0], &argv0);
 489     copyTV(J->L, &rd->argv[1], &argv1);
 490     if (errcode)
 491       lj_err_throw(J->L, errcode);  /* Propagate errors. */
 492     rd->nres = -1;  /* Pending call. */
 493   }  /* else: Interpreter will throw. */
 494 }
 495 
 496 static void LJ_FASTCALL recff_getfenv(jit_State *J, RecordFFData *rd)
 497 {
 498   TRef tr = J->base[0];
 499   /* Only support getfenv(0) for now. */
 500   if (tref_isint(tr) && tref_isk(tr) && IR(tref_ref(tr))->i == 0) {
 501     TRef trl = emitir(IRT(IR_LREF, IRT_THREAD), 0, 0);
 502     J->base[0] = emitir(IRT(IR_FLOAD, IRT_TAB), trl, IRFL_THREAD_ENV);
 503     return;
 504   }
 505   recff_nyiu(J, rd);
 506 }
 507 
 508 /* -- Math library fast functions ----------------------------------------- */
 509 
 510 static void LJ_FASTCALL recff_math_abs(jit_State *J, RecordFFData *rd)
 511 {
 512   TRef tr = lj_ir_tonum(J, J->base[0]);
 513   J->base[0] = emitir(IRTN(IR_ABS), tr, lj_ir_ksimd(J, LJ_KSIMD_ABS));
 514   UNUSED(rd);
 515 }
 516 
 517 /* Record rounding functions math.floor and math.ceil. */
 518 static void LJ_FASTCALL recff_math_round(jit_State *J, RecordFFData *rd)
 519 {
 520   TRef tr = J->base[0];
 521   if (!tref_isinteger(tr)) {  /* Pass through integers unmodified. */
 522     tr = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, tr), rd->data);
 523     /* Result is integral (or NaN/Inf), but may not fit an int32_t. */
 524     if (LJ_DUALNUM) {  /* Try to narrow using a guarded conversion to int. */
 525       lua_Number n = lj_vm_foldfpm(numberVnum(&rd->argv[0]), rd->data);
 526       if (n == (lua_Number)lj_num2int(n))
 527         tr = emitir(IRTGI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_CHECK);
 528     }
 529     J->base[0] = tr;
 530   }
 531 }
 532 
 533 /* Record unary math.* functions, mapped to IR_FPMATH opcode. */
 534 static void LJ_FASTCALL recff_math_unary(jit_State *J, RecordFFData *rd)
 535 {
 536   J->base[0] = emitir(IRTN(IR_FPMATH), lj_ir_tonum(J, J->base[0]), rd->data);
 537 }
 538 
 539 /* Record math.log. */
 540 static void LJ_FASTCALL recff_math_log(jit_State *J, RecordFFData *rd)
 541 {
 542   TRef tr = lj_ir_tonum(J, J->base[0]);
 543   if (J->base[1]) {
 544 #ifdef LUAJIT_NO_LOG2
 545     uint32_t fpm = IRFPM_LOG;
 546 #else
 547     uint32_t fpm = IRFPM_LOG2;
 548 #endif
 549     TRef trb = lj_ir_tonum(J, J->base[1]);
 550     tr = emitir(IRTN(IR_FPMATH), tr, fpm);
 551     trb = emitir(IRTN(IR_FPMATH), trb, fpm);
 552     trb = emitir(IRTN(IR_DIV), lj_ir_knum_one(J), trb);
 553     tr = emitir(IRTN(IR_MUL), tr, trb);
 554   } else {
 555     tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_LOG);
 556   }
 557   J->base[0] = tr;
 558   UNUSED(rd);
 559 }
 560 
 561 /* Record math.atan2. */
 562 static void LJ_FASTCALL recff_math_atan2(jit_State *J, RecordFFData *rd)
 563 {
 564   TRef tr = lj_ir_tonum(J, J->base[0]);
 565   TRef tr2 = lj_ir_tonum(J, J->base[1]);
 566   J->base[0] = emitir(IRTN(IR_ATAN2), tr, tr2);
 567   UNUSED(rd);
 568 }
 569 
 570 /* Record math.ldexp. */
 571 static void LJ_FASTCALL recff_math_ldexp(jit_State *J, RecordFFData *rd)
 572 {
 573   TRef tr = lj_ir_tonum(J, J->base[0]);
 574 #if LJ_TARGET_X86ORX64
 575   TRef tr2 = lj_ir_tonum(J, J->base[1]);
 576 #else
 577   TRef tr2 = lj_opt_narrow_toint(J, J->base[1]);
 578 #endif
 579   J->base[0] = emitir(IRTN(IR_LDEXP), tr, tr2);
 580   UNUSED(rd);
 581 }
 582 
 583 /* Record math.asin, math.acos, math.atan. */
 584 static void LJ_FASTCALL recff_math_atrig(jit_State *J, RecordFFData *rd)
 585 {
 586   TRef y = lj_ir_tonum(J, J->base[0]);
 587   TRef x = lj_ir_knum_one(J);
 588   uint32_t ffid = rd->data;
 589   if (ffid != FF_math_atan) {
 590     TRef tmp = emitir(IRTN(IR_MUL), y, y);
 591     tmp = emitir(IRTN(IR_SUB), x, tmp);
 592     tmp = emitir(IRTN(IR_FPMATH), tmp, IRFPM_SQRT);
 593     if (ffid == FF_math_asin) { x = tmp; } else { x = y; y = tmp; }
 594   }
 595   J->base[0] = emitir(IRTN(IR_ATAN2), y, x);
 596 }
 597 
 598 static void LJ_FASTCALL recff_math_htrig(jit_State *J, RecordFFData *rd)
 599 {
 600   TRef tr = lj_ir_tonum(J, J->base[0]);
 601   J->base[0] = emitir(IRTN(IR_CALLN), tr, rd->data);
 602 }
 603 
 604 static void LJ_FASTCALL recff_math_modf(jit_State *J, RecordFFData *rd)
 605 {
 606   TRef tr = J->base[0];
 607   if (tref_isinteger(tr)) {
 608     J->base[0] = tr;
 609     J->base[1] = lj_ir_kint(J, 0);
 610   } else {
 611     TRef trt;
 612     tr = lj_ir_tonum(J, tr);
 613     trt = emitir(IRTN(IR_FPMATH), tr, IRFPM_TRUNC);
 614     J->base[0] = trt;
 615     J->base[1] = emitir(IRTN(IR_SUB), tr, trt);
 616   }
 617   rd->nres = 2;
 618 }
 619 
 620 static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd)
 621 {
 622   J->base[0] = lj_opt_narrow_pow(J, J->base[0], J->base[1],
 623                                  &rd->argv[0], &rd->argv[1]);
 624   UNUSED(rd);
 625 }
 626 
 627 static void LJ_FASTCALL recff_math_minmax(jit_State *J, RecordFFData *rd)
 628 {
 629   TRef tr = lj_ir_tonumber(J, J->base[0]);
 630   uint32_t op = rd->data;
 631   BCReg i;
 632   for (i = 1; J->base[i] != 0; i++) {
 633     TRef tr2 = lj_ir_tonumber(J, J->base[i]);
 634     IRType t = IRT_INT;
 635     if (!(tref_isinteger(tr) && tref_isinteger(tr2))) {
 636       if (tref_isinteger(tr)) tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT);
 637       if (tref_isinteger(tr2)) tr2 = emitir(IRTN(IR_CONV), tr2, IRCONV_NUM_INT);
 638       t = IRT_NUM;
 639     }
 640     tr = emitir(IRT(op, t), tr, tr2);
 641   }
 642   J->base[0] = tr;
 643 }
 644 
 645 static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd)
 646 {
 647   GCudata *ud = udataV(&J->fn->c.upvalue[0]);
 648   TRef tr, one;
 649   lj_ir_kgc(J, obj2gco(ud), IRT_UDATA);  /* Prevent collection. */
 650   tr = lj_ir_call(J, IRCALL_lj_math_random_step, lj_ir_kptr(J, uddata(ud)));
 651   one = lj_ir_knum_one(J);
 652   tr = emitir(IRTN(IR_SUB), tr, one);
 653   if (J->base[0]) {
 654     TRef tr1 = lj_ir_tonum(J, J->base[0]);
 655     if (J->base[1]) {  /* d = floor(d*(r2-r1+1.0)) + r1 */
 656       TRef tr2 = lj_ir_tonum(J, J->base[1]);
 657       tr2 = emitir(IRTN(IR_SUB), tr2, tr1);
 658       tr2 = emitir(IRTN(IR_ADD), tr2, one);
 659       tr = emitir(IRTN(IR_MUL), tr, tr2);
 660       tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR);
 661       tr = emitir(IRTN(IR_ADD), tr, tr1);
 662     } else {  /* d = floor(d*r1) + 1.0 */
 663       tr = emitir(IRTN(IR_MUL), tr, tr1);
 664       tr = emitir(IRTN(IR_FPMATH), tr, IRFPM_FLOOR);
 665       tr = emitir(IRTN(IR_ADD), tr, one);
 666     }
 667   }
 668   J->base[0] = tr;
 669   UNUSED(rd);
 670 }
 671 
 672 /* -- Bit library fast functions ------------------------------------------ */
 673 
 674 /* Record bit.tobit. */
 675 static void LJ_FASTCALL recff_bit_tobit(jit_State *J, RecordFFData *rd)
 676 {
 677   TRef tr = J->base[0];
 678 #if LJ_HASFFI
 679   if (tref_iscdata(tr)) { recff_bit64_tobit(J, rd); return; }
 680 #endif
 681   J->base[0] = lj_opt_narrow_tobit(J, tr);
 682   UNUSED(rd);
 683 }
 684 
 685 /* Record unary bit.bnot, bit.bswap. */
 686 static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd)
 687 {
 688 #if LJ_HASFFI
 689   if (recff_bit64_unary(J, rd))
 690     return;
 691 #endif
 692   J->base[0] = emitir(IRTI(rd->data), lj_opt_narrow_tobit(J, J->base[0]), 0);
 693 }
 694 
 695 /* Record N-ary bit.band, bit.bor, bit.bxor. */
 696 static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd)
 697 {
 698 #if LJ_HASFFI
 699   if (recff_bit64_nary(J, rd))
 700     return;
 701 #endif
 702   {
 703     TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
 704     uint32_t ot = IRTI(rd->data);
 705     BCReg i;
 706     for (i = 1; J->base[i] != 0; i++)
 707       tr = emitir(ot, tr, lj_opt_narrow_tobit(J, J->base[i]));
 708     J->base[0] = tr;
 709   }
 710 }
 711 
 712 /* Record bit shifts. */
 713 static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd)
 714 {
 715 #if LJ_HASFFI
 716   if (recff_bit64_shift(J, rd))
 717     return;
 718 #endif
 719   {
 720     TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
 721     TRef tsh = lj_opt_narrow_tobit(J, J->base[1]);
 722     IROp op = (IROp)rd->data;
 723     if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) &&
 724         !tref_isk(tsh))
 725       tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31));
 726 #ifdef LJ_TARGET_UNIFYROT
 727     if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) {
 728       op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR;
 729       tsh = emitir(IRTI(IR_NEG), tsh, tsh);
 730     }
 731 #endif
 732     J->base[0] = emitir(IRTI(op), tr, tsh);
 733   }
 734 }
 735 
 736 static void LJ_FASTCALL recff_bit_tohex(jit_State *J, RecordFFData *rd)
 737 {
 738 #if LJ_HASFFI
 739   TRef hdr = recff_bufhdr(J);
 740   TRef tr = recff_bit64_tohex(J, rd, hdr);
 741   J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
 742 #else
 743   recff_nyiu(J, rd);  /* Don't bother working around this NYI. */
 744 #endif
 745 }
 746 
 747 /* -- String library fast functions --------------------------------------- */
 748 
 749 /* Specialize to relative starting position for string. */
 750 static TRef recff_string_start(jit_State *J, GCstr *s, int32_t *st, TRef tr,
 751                                TRef trlen, TRef tr0)
 752 {
 753   int32_t start = *st;
 754   if (start < 0) {
 755     emitir(IRTGI(IR_LT), tr, tr0);
 756     tr = emitir(IRTI(IR_ADD), trlen, tr);
 757     start = start + (int32_t)s->len;
 758     emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), tr, tr0);
 759     if (start < 0) {
 760       tr = tr0;
 761       start = 0;
 762     }
 763   } else if (start == 0) {
 764     emitir(IRTGI(IR_EQ), tr, tr0);
 765     tr = tr0;
 766   } else {
 767     tr = emitir(IRTI(IR_ADD), tr, lj_ir_kint(J, -1));
 768     emitir(IRTGI(IR_GE), tr, tr0);
 769     start--;
 770   }
 771   *st = start;
 772   return tr;
 773 }
 774 
 775 /* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */
 776 static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
 777 {
 778   TRef trstr = lj_ir_tostr(J, J->base[0]);
 779   TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN);
 780   TRef tr0 = lj_ir_kint(J, 0);
 781   TRef trstart, trend;
 782   GCstr *str = argv2str(J, &rd->argv[0]);
 783   int32_t start, end;
 784   if (rd->data) {  /* string.sub(str, start [,end]) */
 785     start = argv2int(J, &rd->argv[1]);
 786     trstart = lj_opt_narrow_toint(J, J->base[1]);
 787     trend = J->base[2];
 788     if (tref_isnil(trend)) {
 789       trend = lj_ir_kint(J, -1);
 790       end = -1;
 791     } else {
 792       trend = lj_opt_narrow_toint(J, trend);
 793       end = argv2int(J, &rd->argv[2]);
 794     }
 795   } else {  /* string.byte(str, [,start [,end]]) */
 796     if (tref_isnil(J->base[1])) {
 797       start = 1;
 798       trstart = lj_ir_kint(J, 1);
 799     } else {
 800       start = argv2int(J, &rd->argv[1]);
 801       trstart = lj_opt_narrow_toint(J, J->base[1]);
 802     }
 803     if (J->base[1] && !tref_isnil(J->base[2])) {
 804       trend = lj_opt_narrow_toint(J, J->base[2]);
 805       end = argv2int(J, &rd->argv[2]);
 806     } else {
 807       trend = trstart;
 808       end = start;
 809     }
 810   }
 811   if (end < 0) {
 812     emitir(IRTGI(IR_LT), trend, tr0);
 813     trend = emitir(IRTI(IR_ADD), emitir(IRTI(IR_ADD), trlen, trend),
 814                    lj_ir_kint(J, 1));
 815     end = end+(int32_t)str->len+1;
 816   } else if ((MSize)end <= str->len) {
 817     emitir(IRTGI(IR_ULE), trend, trlen);
 818   } else {
 819     emitir(IRTGI(IR_UGT), trend, trlen);
 820     end = (int32_t)str->len;
 821     trend = trlen;
 822   }
 823   trstart = recff_string_start(J, str, &start, trstart, trlen, tr0);
 824   if (rd->data) {  /* Return string.sub result. */
 825     if (end - start >= 0) {
 826       /* Also handle empty range here, to avoid extra traces. */
 827       TRef trptr, trslen = emitir(IRTI(IR_SUB), trend, trstart);
 828       emitir(IRTGI(IR_GE), trslen, tr0);
 829       trptr = emitir(IRT(IR_STRREF, IRT_PGC), trstr, trstart);
 830       J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen);
 831     } else {  /* Range underflow: return empty string. */
 832       emitir(IRTGI(IR_LT), trend, trstart);
 833       J->base[0] = lj_ir_kstr(J, &J2G(J)->strempty);
 834     }
 835   } else {  /* Return string.byte result(s). */
 836     ptrdiff_t i, len = end - start;
 837     if (len > 0) {
 838       TRef trslen = emitir(IRTI(IR_SUB), trend, trstart);
 839       emitir(IRTGI(IR_EQ), trslen, lj_ir_kint(J, (int32_t)len));
 840       if (J->baseslot + len > LJ_MAX_JSLOTS)
 841         lj_trace_err_info(J, LJ_TRERR_STACKOV);
 842       rd->nres = len;
 843       for (i = 0; i < len; i++) {
 844         TRef tmp = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, (int32_t)i));
 845         tmp = emitir(IRT(IR_STRREF, IRT_PGC), trstr, tmp);
 846         J->base[i] = emitir(IRT(IR_XLOAD, IRT_U8), tmp, IRXLOAD_READONLY);
 847       }
 848     } else {  /* Empty range or range underflow: return no results. */
 849       emitir(IRTGI(IR_LE), trend, trstart);
 850       rd->nres = 0;
 851     }
 852   }
 853 }
 854 
 855 static void LJ_FASTCALL recff_string_char(jit_State *J, RecordFFData *rd)
 856 {
 857   TRef k255 = lj_ir_kint(J, 255);
 858   BCReg i;
 859   for (i = 0; J->base[i] != 0; i++) {  /* Convert char values to strings. */
 860     TRef tr = lj_opt_narrow_toint(J, J->base[i]);
 861     emitir(IRTGI(IR_ULE), tr, k255);
 862     J->base[i] = emitir(IRT(IR_TOSTR, IRT_STR), tr, IRTOSTR_CHAR);
 863   }
 864   if (i > 1) {  /* Concatenate the strings, if there's more than one. */
 865     TRef hdr = recff_bufhdr(J), tr = hdr;
 866     for (i = 0; J->base[i] != 0; i++)
 867       tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, J->base[i]);
 868     J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
 869   }
 870   UNUSED(rd);
 871 }
 872 
 873 static void LJ_FASTCALL recff_string_rep(jit_State *J, RecordFFData *rd)
 874 {
 875   TRef str = lj_ir_tostr(J, J->base[0]);
 876   TRef rep = lj_opt_narrow_toint(J, J->base[1]);
 877   TRef hdr, tr, str2 = 0;
 878   if (!tref_isnil(J->base[2])) {
 879     TRef sep = lj_ir_tostr(J, J->base[2]);
 880     int32_t vrep = argv2int(J, &rd->argv[1]);
 881     emitir(IRTGI(vrep > 1 ? IR_GT : IR_LE), rep, lj_ir_kint(J, 1));
 882     if (vrep > 1) {
 883       TRef hdr2 = recff_bufhdr(J);
 884       TRef tr2 = emitir(IRT(IR_BUFPUT, IRT_PGC), hdr2, sep);
 885       tr2 = emitir(IRT(IR_BUFPUT, IRT_PGC), tr2, str);
 886       str2 = emitir(IRT(IR_BUFSTR, IRT_STR), tr2, hdr2);
 887     }
 888   }
 889   tr = hdr = recff_bufhdr(J);
 890   if (str2) {
 891     tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, str);
 892     str = str2;
 893     rep = emitir(IRTI(IR_ADD), rep, lj_ir_kint(J, -1));
 894   }
 895   tr = lj_ir_call(J, IRCALL_lj_buf_putstr_rep, tr, str, rep);
 896   J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
 897 }
 898 
 899 static void LJ_FASTCALL recff_string_op(jit_State *J, RecordFFData *rd)
 900 {
 901   TRef str = lj_ir_tostr(J, J->base[0]);
 902   TRef hdr = recff_bufhdr(J);
 903   TRef tr = lj_ir_call(J, rd->data, hdr, str);
 904   J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
 905 }
 906 
 907 static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd)
 908 {
 909   TRef trstr = lj_ir_tostr(J, J->base[0]);
 910   TRef trpat = lj_ir_tostr(J, J->base[1]);
 911   TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN);
 912   TRef tr0 = lj_ir_kint(J, 0);
 913   TRef trstart;
 914   GCstr *str = argv2str(J, &rd->argv[0]);
 915   GCstr *pat = argv2str(J, &rd->argv[1]);
 916   int32_t start;
 917   J->needsnap = 1;
 918   if (tref_isnil(J->base[2])) {
 919     trstart = lj_ir_kint(J, 1);
 920     start = 1;
 921   } else {
 922     trstart = lj_opt_narrow_toint(J, J->base[2]);
 923     start = argv2int(J, &rd->argv[2]);
 924   }
 925   trstart = recff_string_start(J, str, &start, trstart, trlen, tr0);
 926   if ((MSize)start <= str->len) {
 927     emitir(IRTGI(IR_ULE), trstart, trlen);
 928   } else {
 929     emitir(IRTGI(IR_UGT), trstart, trlen);
 930 #if LJ_52
 931     J->base[0] = TREF_NIL;
 932     return;
 933 #else
 934     trstart = trlen;
 935     start = str->len;
 936 #endif
 937   }
 938   /* Fixed arg or no pattern matching chars? (Specialized to pattern string.) */
 939   if ((J->base[2] && tref_istruecond(J->base[3])) ||
 940       (emitir(IRTG(IR_EQ, IRT_STR), trpat, lj_ir_kstr(J, pat)),
 941        !lj_str_haspattern(pat))) {  /* Search for fixed string. */
 942     TRef trsptr = emitir(IRT(IR_STRREF, IRT_PGC), trstr, trstart);
 943     TRef trpptr = emitir(IRT(IR_STRREF, IRT_PGC), trpat, tr0);
 944     TRef trslen = emitir(IRTI(IR_SUB), trlen, trstart);
 945     TRef trplen = emitir(IRTI(IR_FLOAD), trpat, IRFL_STR_LEN);
 946     TRef tr = lj_ir_call(J, IRCALL_lj_str_find, trsptr, trpptr, trslen, trplen);
 947     TRef trp0 = lj_ir_kkptr(J, NULL);
 948     if (lj_str_find(strdata(str)+(MSize)start, strdata(pat),
 949                     str->len-(MSize)start, pat->len)) {
 950       TRef pos;
 951       emitir(IRTG(IR_NE, IRT_PGC), tr, trp0);
 952       pos = emitir(IRTI(IR_SUB), tr, emitir(IRT(IR_STRREF, IRT_PGC), trstr, tr0));
 953       J->base[0] = emitir(IRTI(IR_ADD), pos, lj_ir_kint(J, 1));
 954       J->base[1] = emitir(IRTI(IR_ADD), pos, trplen);
 955       rd->nres = 2;
 956     } else {
 957       emitir(IRTG(IR_EQ, IRT_PGC), tr, trp0);
 958       J->base[0] = TREF_NIL;
 959     }
 960   } else {  /* Search for pattern. */
 961     recff_nyiu(J, rd);
 962     return;
 963   }
 964 }
 965 
 966 static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
 967 {
 968   TRef trfmt = lj_ir_tostr(J, J->base[0]);
 969   GCstr *fmt = argv2str(J, &rd->argv[0]);
 970   int arg = 1;
 971   TRef hdr, tr;
 972   FormatState fs;
 973   SFormat sf;
 974   /* Specialize to the format string. */
 975   emitir(IRTG(IR_EQ, IRT_STR), trfmt, lj_ir_kstr(J, fmt));
 976   tr = hdr = recff_bufhdr(J);
 977   lj_strfmt_init(&fs, strdata(fmt), fmt->len);
 978   while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) {  /* Parse format. */
 979     TRef tra = sf == STRFMT_LIT ? 0 : J->base[arg++];
 980     TRef trsf = lj_ir_kint(J, (int32_t)sf);
 981     IRCallID id;
 982     switch (STRFMT_TYPE(sf)) {
 983     case STRFMT_LIT:
 984       tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr,
 985                   lj_ir_kstr(J, lj_str_new(J->L, fs.str, fs.len)));
 986       break;
 987     case STRFMT_INT:
 988       id = IRCALL_lj_strfmt_putfnum_int;
 989     handle_int:
 990       if (!tref_isinteger(tra))
 991         goto handle_num;
 992       if (sf == STRFMT_INT) { /* Shortcut for plain %d. */
 993         tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr,
 994                     emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_INT));
 995       } else {
 996 #if LJ_HASFFI
 997         tra = emitir(IRT(IR_CONV, IRT_U64), tra,
 998                      (IRT_INT|(IRT_U64<<5)|IRCONV_SEXT));
 999         tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra);
1000         lj_needsplit(J);
1001 #else
1002         recff_nyiu(J, rd);  /* Don't bother working around this NYI. */
1003         return;
1004 #endif
1005       }
1006       break;
1007     case STRFMT_UINT:
1008       id = IRCALL_lj_strfmt_putfnum_uint;
1009       goto handle_int;
1010     case STRFMT_NUM:
1011       id = IRCALL_lj_strfmt_putfnum;
1012     handle_num:
1013       tra = lj_ir_tonum(J, tra);
1014       tr = lj_ir_call(J, id, tr, trsf, tra);
1015       if (LJ_SOFTFP32) lj_needsplit(J);
1016       break;
1017     case STRFMT_STR:
1018       if (!tref_isstr(tra)) {
1019         recff_nyiu(J, rd);  /* NYI: __tostring and non-string types for %s. */
1020         return;
1021       }
1022       if (sf == STRFMT_STR)  /* Shortcut for plain %s. */
1023         tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, tra);
1024       else if ((sf & STRFMT_T_QUOTED))
1025         tr = lj_ir_call(J, IRCALL_lj_strfmt_putquoted, tr, tra);
1026       else
1027         tr = lj_ir_call(J, IRCALL_lj_strfmt_putfstr, tr, trsf, tra);
1028       break;
1029     case STRFMT_CHAR:
1030       tra = lj_opt_narrow_toint(J, tra);
1031       if (sf == STRFMT_CHAR)  /* Shortcut for plain %c. */
1032         tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr,
1033                     emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_CHAR));
1034       else
1035         tr = lj_ir_call(J, IRCALL_lj_strfmt_putfchar, tr, trsf, tra);
1036       break;
1037     case STRFMT_PTR:  /* NYI */
1038     case STRFMT_ERR:
1039     default:
1040       recff_nyiu(J, rd);
1041       return;
1042     }
1043   }
1044   J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
1045 }
1046 
1047 /* -- Table library fast functions ---------------------------------------- */
1048 
1049 static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
1050 {
1051   RecordIndex ix;
1052   ix.tab = J->base[0];
1053   ix.val = J->base[1];
1054   rd->nres = 0;
1055   if (tref_istab(ix.tab) && ix.val) {
1056     if (!J->base[2]) {  /* Simple push: t[#t+1] = v */
1057       TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, ix.tab);
1058       GCtab *t = tabV(&rd->argv[0]);
1059       ix.key = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1));
1060       settabV(J->L, &ix.tabv, t);
1061       setintV(&ix.keyv, lj_tab_len(t) + 1);
1062       ix.idxchain = 0;
1063       lj_record_idx(J, &ix);  /* Set new value. */
1064     } else {  /* Complex case: insert in the middle. */
1065       recff_nyiu(J, rd);
1066       return;
1067     }
1068   }  /* else: Interpreter will throw. */
1069 }
1070 
1071 static void LJ_FASTCALL recff_table_concat(jit_State *J, RecordFFData *rd)
1072 {
1073   TRef tab = J->base[0];
1074   if (tref_istab(tab)) {
1075     TRef sep = !tref_isnil(J->base[1]) ?
1076                lj_ir_tostr(J, J->base[1]) : lj_ir_knull(J, IRT_STR);
1077     TRef tri = (J->base[1] && !tref_isnil(J->base[2])) ?
1078                lj_opt_narrow_toint(J, J->base[2]) : lj_ir_kint(J, 1);
1079     TRef tre = (J->base[1] && J->base[2] && !tref_isnil(J->base[3])) ?
1080                lj_opt_narrow_toint(J, J->base[3]) :
1081                lj_ir_call(J, IRCALL_lj_tab_len, tab);
1082     TRef hdr = recff_bufhdr(J);
1083     TRef tr = lj_ir_call(J, IRCALL_lj_buf_puttab, hdr, tab, sep, tri, tre);
1084     emitir(IRTG(IR_NE, IRT_PTR), tr, lj_ir_kptr(J, NULL));
1085     J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
1086   }  /* else: Interpreter will throw. */
1087   UNUSED(rd);
1088 }
1089 
1090 static void LJ_FASTCALL recff_table_new(jit_State *J, RecordFFData *rd)
1091 {
1092   TRef tra = lj_opt_narrow_toint(J, J->base[0]);
1093   TRef trh = lj_opt_narrow_toint(J, J->base[1]);
1094   J->base[0] = lj_ir_call(J, IRCALL_lj_tab_new_ah, tra, trh);
1095   UNUSED(rd);
1096 }
1097 
1098 static void LJ_FASTCALL recff_table_clear(jit_State *J, RecordFFData *rd)
1099 {
1100   TRef tr = J->base[0];
1101   if (tref_istab(tr)) {
1102     rd->nres = 0;
1103     lj_ir_call(J, IRCALL_lj_tab_clear, tr);
1104     J->needsnap = 1;
1105   }  /* else: Interpreter will throw. */
1106 }
1107 
1108 /* -- I/O library fast functions ------------------------------------------ */
1109 
1110 /* Get FILE* for I/O function. Any I/O error aborts recording, so there's
1111 ** no need to encode the alternate cases for any of the guards.
1112 */
1113 static TRef recff_io_fp(jit_State *J, TRef *udp, int32_t id)
1114 {
1115   TRef tr, ud, fp;
1116   if (id) {  /* io.func() */
1117 #if LJ_GC64
1118     /* TODO: fix ARM32 asm_fload(), so we can use this for all archs. */
1119     ud = lj_ir_ggfload(J, IRT_UDATA, GG_OFS(g.gcroot[id]));
1120 #else
1121     tr = lj_ir_kptr(J, &J2G(J)->gcroot[id]);
1122     ud = emitir(IRT(IR_XLOAD, IRT_UDATA), tr, 0);
1123 #endif
1124   } else {  /* fp:method() */
1125     ud = J->base[0];
1126     if (!tref_isudata(ud))
1127       lj_trace_err(J, LJ_TRERR_BADTYPE);
1128     tr = emitir(IRT(IR_FLOAD, IRT_U8), ud, IRFL_UDATA_UDTYPE);
1129     emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, UDTYPE_IO_FILE));
1130   }
1131   *udp = ud;
1132   fp = emitir(IRT(IR_FLOAD, IRT_PTR), ud, IRFL_UDATA_FILE);
1133   emitir(IRTG(IR_NE, IRT_PTR), fp, lj_ir_knull(J, IRT_PTR));
1134   return fp;
1135 }
1136 
1137 static void LJ_FASTCALL recff_io_write(jit_State *J, RecordFFData *rd)
1138 {
1139   TRef ud, fp = recff_io_fp(J, &ud, rd->data);
1140   TRef zero = lj_ir_kint(J, 0);
1141   TRef one = lj_ir_kint(J, 1);
1142   ptrdiff_t i = rd->data == 0 ? 1 : 0;
1143   for (; J->base[i]; i++) {
1144     TRef str = lj_ir_tostr(J, J->base[i]);
1145     TRef buf = emitir(IRT(IR_STRREF, IRT_PGC), str, zero);
1146     TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN);
1147     if (tref_isk(len) && IR(tref_ref(len))->i == 1) {
1148       IRIns *irs = IR(tref_ref(str));
1149       TRef tr = (irs->o == IR_TOSTR && irs->op2 == IRTOSTR_CHAR) ?
1150                 irs->op1 :
1151                 emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY);
1152       tr = lj_ir_call(J, IRCALL_fputc, tr, fp);
1153       if (results_wanted(J) != 0)  /* Check result only if not ignored. */
1154         emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1));
1155     } else {
1156       TRef tr = lj_ir_call(J, IRCALL_fwrite, buf, one, len, fp);
1157       if (results_wanted(J) != 0)  /* Check result only if not ignored. */
1158         emitir(IRTGI(IR_EQ), tr, len);
1159     }
1160   }
1161   J->base[0] = LJ_52 ? ud : TREF_TRUE;
1162 }
1163 
1164 static void LJ_FASTCALL recff_io_flush(jit_State *J, RecordFFData *rd)
1165 {
1166   TRef ud, fp = recff_io_fp(J, &ud, rd->data);
1167   TRef tr = lj_ir_call(J, IRCALL_fflush, fp);
1168   if (results_wanted(J) != 0)  /* Check result only if not ignored. */
1169     emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, 0));
1170   J->base[0] = TREF_TRUE;
1171 }
1172 
1173 /* -- Debug library fast functions ---------------------------------------- */
1174 
1175 static void LJ_FASTCALL recff_debug_getmetatable(jit_State *J, RecordFFData *rd)
1176 {
1177   GCtab *mt;
1178   TRef mtref;
1179   TRef tr = J->base[0];
1180   if (tref_istab(tr)) {
1181     mt = tabref(tabV(&rd->argv[0])->metatable);
1182     mtref = emitir(IRT(IR_FLOAD, IRT_TAB), tr, IRFL_TAB_META);
1183   } else if (tref_isudata(tr)) {
1184     mt = tabref(udataV(&rd->argv[0])->metatable);
1185     mtref = emitir(IRT(IR_FLOAD, IRT_TAB), tr, IRFL_UDATA_META);
1186   } else {
1187     mt = tabref(basemt_obj(J2G(J), &rd->argv[0]));
1188     J->base[0] = mt ? lj_ir_ktab(J, mt) : TREF_NIL;
1189     return;
1190   }
1191   emitir(IRTG(mt ? IR_NE : IR_EQ, IRT_TAB), mtref, lj_ir_knull(J, IRT_TAB));
1192   J->base[0] = mt ? mtref : TREF_NIL;
1193 }
1194 
1195 /* -- Record calls to fast functions -------------------------------------- */
1196 
1197 #include "lj_recdef.h"
1198 
1199 static uint32_t recdef_lookup(GCfunc *fn)
1200 {
1201   if (fn->c.ffid < sizeof(recff_idmap)/sizeof(recff_idmap[0]))
1202     return recff_idmap[fn->c.ffid];
1203   else
1204     return 0;
1205 }
1206 
1207 /* Record entry to a fast function or C function. */
1208 void lj_ffrecord_func(jit_State *J)
1209 {
1210   RecordFFData rd;
1211   uint32_t m = recdef_lookup(J->fn);
1212   rd.data = m & 0xff;
1213   rd.nres = 1;  /* Default is one result. */
1214   rd.argv = J->L->base;
1215   J->base[J->maxslot] = 0;  /* Mark end of arguments. */
1216   (recff_func[m >> 8])(J, &rd);  /* Call recff_* handler. */
1217   if (rd.nres >= 0) {
1218     if (J->postproc == LJ_POST_NONE) J->postproc = LJ_POST_FFRETRY;
1219     lj_record_ret(J, 0, rd.nres);
1220   }
1221 }
1222 
1223 #undef IR
1224 #undef emitir
1225 
1226 #endif

/* [<][>][^][v][top][bottom][index][help] */