aboutsummaryrefslogtreecommitdiff
path: root/src/lj_ffrecord.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_ffrecord.c')
-rw-r--r--src/lj_ffrecord.c590
1 files changed, 466 insertions, 124 deletions
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c
index 1d428590..5282217f 100644
--- a/src/lj_ffrecord.c
+++ b/src/lj_ffrecord.c
@@ -27,6 +27,7 @@
27#include "lj_dispatch.h" 27#include "lj_dispatch.h"
28#include "lj_vm.h" 28#include "lj_vm.h"
29#include "lj_strscan.h" 29#include "lj_strscan.h"
30#include "lj_strfmt.h"
30 31
31/* Some local macros to save typing. Undef'd at the end. */ 32/* Some local macros to save typing. Undef'd at the end. */
32#define IR(ref) (&J->cur.ir[(ref)]) 33#define IR(ref) (&J->cur.ir[(ref)])
@@ -79,10 +80,7 @@ static GCstr *argv2str(jit_State *J, TValue *o)
79 GCstr *s; 80 GCstr *s;
80 if (!tvisnumber(o)) 81 if (!tvisnumber(o))
81 lj_trace_err(J, LJ_TRERR_BADTYPE); 82 lj_trace_err(J, LJ_TRERR_BADTYPE);
82 if (tvisint(o)) 83 s = lj_strfmt_number(J->L, o);
83 s = lj_str_fromint(J->L, intV(o));
84 else
85 s = lj_str_fromnum(J->L, &o->n);
86 setstrV(J->L, o, s); 84 setstrV(J->L, o, s);
87 return s; 85 return s;
88 } 86 }
@@ -98,27 +96,90 @@ static ptrdiff_t results_wanted(jit_State *J)
98 return -1; 96 return -1;
99} 97}
100 98
101/* Throw error for unsupported variant of fast function. */ 99/* Trace stitching: add continuation below frame to start a new trace. */
102LJ_NORET static void recff_nyiu(jit_State *J) 100static void recff_stitch(jit_State *J)
103{ 101{
104 setfuncV(J->L, &J->errinfo, J->fn); 102 ASMFunction cont = lj_cont_stitch;
105 lj_trace_err_info(J, LJ_TRERR_NYIFFU); 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;
106} 140}
107 141
108/* Fallback handler for all fast functions that are not recorded (yet). */ 142/* Fallback handler for fast functions that are not recorded (yet). */
109static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd) 143static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd)
110{ 144{
111 setfuncV(J->L, &J->errinfo, J->fn); 145 if (J->cur.nins < (IRRef)J->param[JIT_P_minstitch] + REF_BASE) {
112 lj_trace_err_info(J, LJ_TRERR_NYIFF); 146 lj_trace_err_info(J, LJ_TRERR_TRACEUV);
113 UNUSED(rd); 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 }
114} 170}
115 171
116/* C functions can have arbitrary side-effects and are not recorded (yet). */ 172/* Fallback handler for unsupported variants of fast functions. */
117static void LJ_FASTCALL recff_c(jit_State *J, RecordFFData *rd) 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. */
179static TRef recff_bufhdr(jit_State *J)
118{ 180{
119 setfuncV(J->L, &J->errinfo, J->fn); 181 return emitir(IRT(IR_BUFHDR, IRT_PGC),
120 lj_trace_err_info(J, LJ_TRERR_NYICF); 182 lj_ir_kptr(J, &J2G(J)->tmpbuf), IRBUFHDR_RESET);
121 UNUSED(rd);
122} 183}
123 184
124/* -- Base library fast functions ----------------------------------------- */ 185/* -- Base library fast functions ----------------------------------------- */
@@ -135,7 +196,7 @@ static void LJ_FASTCALL recff_type(jit_State *J, RecordFFData *rd)
135 uint32_t t; 196 uint32_t t;
136 if (tvisnumber(&rd->argv[0])) 197 if (tvisnumber(&rd->argv[0]))
137 t = ~LJ_TNUMX; 198 t = ~LJ_TNUMX;
138 else if (LJ_64 && tvislightud(&rd->argv[0])) 199 else if (LJ_64 && !LJ_GC64 && tvislightud(&rd->argv[0]))
139 t = ~LJ_TLIGHTUD; 200 t = ~LJ_TLIGHTUD;
140 else 201 else
141 t = ~itype(&rd->argv[0]); 202 t = ~itype(&rd->argv[0]);
@@ -167,7 +228,7 @@ static void LJ_FASTCALL recff_setmetatable(jit_State *J, RecordFFData *rd)
167 ix.tab = tr; 228 ix.tab = tr;
168 copyTV(J->L, &ix.tabv, &rd->argv[0]); 229 copyTV(J->L, &ix.tabv, &rd->argv[0]);
169 lj_record_mm_lookup(J, &ix, MM_metatable); /* Guard for no __metatable. */ 230 lj_record_mm_lookup(J, &ix, MM_metatable); /* Guard for no __metatable. */
170 fref = emitir(IRT(IR_FREF, IRT_P32), tr, IRFL_TAB_META); 231 fref = emitir(IRT(IR_FREF, IRT_PGC), tr, IRFL_TAB_META);
171 mtref = tref_isnil(mt) ? lj_ir_knull(J, IRT_TAB) : mt; 232 mtref = tref_isnil(mt) ? lj_ir_knull(J, IRT_TAB) : mt;
172 emitir(IRT(IR_FSTORE, IRT_TAB), fref, mtref); 233 emitir(IRT(IR_FSTORE, IRT_TAB), fref, mtref);
173 if (!tref_isnil(mt)) 234 if (!tref_isnil(mt))
@@ -233,7 +294,7 @@ int32_t lj_ffrecord_select_mode(jit_State *J, TRef tr, TValue *tv)
233 if (strV(tv)->len == 1) { 294 if (strV(tv)->len == 1) {
234 emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, strV(tv))); 295 emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, strV(tv)));
235 } else { 296 } else {
236 TRef trptr = emitir(IRT(IR_STRREF, IRT_P32), tr, lj_ir_kint(J, 0)); 297 TRef trptr = emitir(IRT(IR_STRREF, IRT_PGC), tr, lj_ir_kint(J, 0));
237 TRef trchar = emitir(IRT(IR_XLOAD, IRT_U8), trptr, IRXLOAD_READONLY); 298 TRef trchar = emitir(IRT(IR_XLOAD, IRT_U8), trptr, IRXLOAD_READONLY);
238 emitir(IRTG(IR_EQ, IRT_INT), trchar, lj_ir_kint(J, '#')); 299 emitir(IRTG(IR_EQ, IRT_INT), trchar, lj_ir_kint(J, '#'));
239 } 300 }
@@ -263,7 +324,8 @@ static void LJ_FASTCALL recff_select(jit_State *J, RecordFFData *rd)
263 J->base[i] = J->base[start+i]; 324 J->base[i] = J->base[start+i];
264 } /* else: Interpreter will throw. */ 325 } /* else: Interpreter will throw. */
265 } else { 326 } else {
266 recff_nyiu(J); 327 recff_nyiu(J, rd);
328 return;
267 } 329 }
268 } /* else: Interpreter will throw. */ 330 } /* else: Interpreter will throw. */
269} 331}
@@ -274,14 +336,18 @@ static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd)
274 TRef base = J->base[1]; 336 TRef base = J->base[1];
275 if (tr && !tref_isnil(base)) { 337 if (tr && !tref_isnil(base)) {
276 base = lj_opt_narrow_toint(J, base); 338 base = lj_opt_narrow_toint(J, base);
277 if (!tref_isk(base) || IR(tref_ref(base))->i != 10) 339 if (!tref_isk(base) || IR(tref_ref(base))->i != 10) {
278 recff_nyiu(J); 340 recff_nyiu(J, rd);
341 return;
342 }
279 } 343 }
280 if (tref_isnumber_str(tr)) { 344 if (tref_isnumber_str(tr)) {
281 if (tref_isstr(tr)) { 345 if (tref_isstr(tr)) {
282 TValue tmp; 346 TValue tmp;
283 if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) 347 if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) {
284 recff_nyiu(J); /* Would need an inverted STRTO for this case. */ 348 recff_nyiu(J, rd); /* Would need an inverted STRTO for this case. */
349 return;
350 }
285 tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); 351 tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0);
286 } 352 }
287#if LJ_HASFFI 353#if LJ_HASFFI
@@ -313,10 +379,10 @@ static int recff_metacall(jit_State *J, RecordFFData *rd, MMS mm)
313 int errcode; 379 int errcode;
314 TValue argv0; 380 TValue argv0;
315 /* Temporarily insert metamethod below object. */ 381 /* Temporarily insert metamethod below object. */
316 J->base[1] = J->base[0]; 382 J->base[1+LJ_FR2] = J->base[0];
317 J->base[0] = ix.mobj; 383 J->base[0] = ix.mobj;
318 copyTV(J->L, &argv0, &rd->argv[0]); 384 copyTV(J->L, &argv0, &rd->argv[0]);
319 copyTV(J->L, &rd->argv[1], &rd->argv[0]); 385 copyTV(J->L, &rd->argv[1+LJ_FR2], &rd->argv[0]);
320 copyTV(J->L, &rd->argv[0], &ix.mobjv); 386 copyTV(J->L, &rd->argv[0], &ix.mobjv);
321 /* Need to protect lj_record_tailcall because it may throw. */ 387 /* Need to protect lj_record_tailcall because it may throw. */
322 errcode = lj_vm_cpcall(J->L, NULL, J, recff_metacall_cp); 388 errcode = lj_vm_cpcall(J->L, NULL, J, recff_metacall_cp);
@@ -336,13 +402,15 @@ static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd)
336 if (tref_isstr(tr)) { 402 if (tref_isstr(tr)) {
337 /* Ignore __tostring in the string base metatable. */ 403 /* Ignore __tostring in the string base metatable. */
338 /* Pass on result in J->base[0]. */ 404 /* Pass on result in J->base[0]. */
339 } else if (!recff_metacall(J, rd, MM_tostring)) { 405 } else if (tr && !recff_metacall(J, rd, MM_tostring)) {
340 if (tref_isnumber(tr)) { 406 if (tref_isnumber(tr)) {
341 J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); 407 J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr,
408 tref_isnum(tr) ? IRTOSTR_NUM : IRTOSTR_INT);
342 } else if (tref_ispri(tr)) { 409 } else if (tref_ispri(tr)) {
343 J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)])); 410 J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0]));
344 } else { 411 } else {
345 recff_nyiu(J); 412 recff_nyiu(J, rd);
413 return;
346 } 414 }
347 } 415 }
348} 416}
@@ -364,15 +432,15 @@ static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd)
364 } /* else: Interpreter will throw. */ 432 } /* else: Interpreter will throw. */
365} 433}
366 434
367static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd) 435static void LJ_FASTCALL recff_xpairs(jit_State *J, RecordFFData *rd)
368{ 436{
369 TRef tr = J->base[0]; 437 TRef tr = J->base[0];
370 if (!((LJ_52 || (LJ_HASFFI && tref_iscdata(tr))) && 438 if (!((LJ_52 || (LJ_HASFFI && tref_iscdata(tr))) &&
371 recff_metacall(J, rd, MM_ipairs))) { 439 recff_metacall(J, rd, MM_pairs + rd->data))) {
372 if (tref_istab(tr)) { 440 if (tref_istab(tr)) {
373 J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); 441 J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0]));
374 J->base[1] = tr; 442 J->base[1] = tr;
375 J->base[2] = lj_ir_kint(J, 0); 443 J->base[2] = rd->data ? lj_ir_kint(J, 0) : TREF_NIL;
376 rd->nres = 3; 444 rd->nres = 3;
377 } /* else: Interpreter will throw. */ 445 } /* else: Interpreter will throw. */
378 } 446 }
@@ -381,6 +449,10 @@ static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd)
381static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd) 449static void LJ_FASTCALL recff_pcall(jit_State *J, RecordFFData *rd)
382{ 450{
383 if (J->maxslot >= 1) { 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
384 lj_record_call(J, 0, J->maxslot - 1); 456 lj_record_call(J, 0, J->maxslot - 1);
385 rd->nres = -1; /* Pending call. */ 457 rd->nres = -1; /* Pending call. */
386 } /* else: Interpreter will throw. */ 458 } /* else: Interpreter will throw. */
@@ -406,6 +478,10 @@ static void LJ_FASTCALL recff_xpcall(jit_State *J, RecordFFData *rd)
406 copyTV(J->L, &argv1, &rd->argv[1]); 478 copyTV(J->L, &argv1, &rd->argv[1]);
407 copyTV(J->L, &rd->argv[0], &argv1); 479 copyTV(J->L, &rd->argv[0], &argv1);
408 copyTV(J->L, &rd->argv[1], &argv0); 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
409 /* Need to protect lj_record_call because it may throw. */ 485 /* Need to protect lj_record_call because it may throw. */
410 errcode = lj_vm_cpcall(J->L, NULL, J, recff_xpcall_cp); 486 errcode = lj_vm_cpcall(J->L, NULL, J, recff_xpcall_cp);
411 /* Always undo Lua stack swap to avoid confusing the interpreter. */ 487 /* Always undo Lua stack swap to avoid confusing the interpreter. */
@@ -417,12 +493,24 @@ static void LJ_FASTCALL recff_xpcall(jit_State *J, RecordFFData *rd)
417 } /* else: Interpreter will throw. */ 493 } /* else: Interpreter will throw. */
418} 494}
419 495
496static 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
420/* -- Math library fast functions ----------------------------------------- */ 508/* -- Math library fast functions ----------------------------------------- */
421 509
422static void LJ_FASTCALL recff_math_abs(jit_State *J, RecordFFData *rd) 510static void LJ_FASTCALL recff_math_abs(jit_State *J, RecordFFData *rd)
423{ 511{
424 TRef tr = lj_ir_tonum(J, J->base[0]); 512 TRef tr = lj_ir_tonum(J, J->base[0]);
425 J->base[0] = emitir(IRTN(IR_ABS), tr, lj_ir_knum_abs(J)); 513 J->base[0] = emitir(IRTN(IR_ABS), tr, lj_ir_ksimd(J, LJ_KSIMD_ABS));
426 UNUSED(rd); 514 UNUSED(rd);
427} 515}
428 516
@@ -529,14 +617,6 @@ static void LJ_FASTCALL recff_math_modf(jit_State *J, RecordFFData *rd)
529 rd->nres = 2; 617 rd->nres = 2;
530} 618}
531 619
532static void LJ_FASTCALL recff_math_degrad(jit_State *J, RecordFFData *rd)
533{
534 TRef tr = lj_ir_tonum(J, J->base[0]);
535 TRef trm = lj_ir_knum(J, numV(&J->fn->c.upvalue[0]));
536 J->base[0] = emitir(IRTN(IR_MUL), tr, trm);
537 UNUSED(rd);
538}
539
540static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd) 620static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd)
541{ 621{
542 J->base[0] = lj_opt_narrow_pow(J, J->base[0], J->base[1], 622 J->base[0] = lj_opt_narrow_pow(J, J->base[0], J->base[1],
@@ -591,48 +671,105 @@ static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd)
591 671
592/* -- Bit library fast functions ------------------------------------------ */ 672/* -- Bit library fast functions ------------------------------------------ */
593 673
594/* Record unary bit.tobit, bit.bnot, bit.bswap. */ 674/* Record bit.tobit. */
675static 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. */
595static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd) 686static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd)
596{ 687{
597 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 688#if LJ_HASFFI
598 J->base[0] = (rd->data == IR_TOBIT) ? tr : emitir(IRTI(rd->data), tr, 0); 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);
599} 693}
600 694
601/* Record N-ary bit.band, bit.bor, bit.bxor. */ 695/* Record N-ary bit.band, bit.bor, bit.bxor. */
602static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd) 696static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd)
603{ 697{
604 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 698#if LJ_HASFFI
605 uint32_t op = rd->data; 699 if (recff_bit64_nary(J, rd))
606 BCReg i; 700 return;
607 for (i = 1; J->base[i] != 0; i++) 701#endif
608 tr = emitir(IRTI(op), tr, lj_opt_narrow_tobit(J, J->base[i])); 702 {
609 J->base[0] = tr; 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 }
610} 710}
611 711
612/* Record bit shifts. */ 712/* Record bit shifts. */
613static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) 713static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd)
614{ 714{
615 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 715#if LJ_HASFFI
616 TRef tsh = lj_opt_narrow_tobit(J, J->base[1]); 716 if (recff_bit64_shift(J, rd))
617 IROp op = (IROp)rd->data; 717 return;
618 if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && 718#endif
619 !tref_isk(tsh)) 719 {
620 tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31)); 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));
621#ifdef LJ_TARGET_UNIFYROT 726#ifdef LJ_TARGET_UNIFYROT
622 if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) { 727 if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) {
623 op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR; 728 op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR;
624 tsh = emitir(IRTI(IR_NEG), tsh, tsh); 729 tsh = emitir(IRTI(IR_NEG), tsh, tsh);
730 }
731#endif
732 J->base[0] = emitir(IRTI(op), tr, tsh);
625 } 733 }
734}
735
736static 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. */
626#endif 744#endif
627 J->base[0] = emitir(IRTI(op), tr, tsh);
628} 745}
629 746
630/* -- String library fast functions --------------------------------------- */ 747/* -- String library fast functions --------------------------------------- */
631 748
632static void LJ_FASTCALL recff_string_len(jit_State *J, RecordFFData *rd) 749/* Specialize to relative starting position for string. */
750static TRef recff_string_start(jit_State *J, GCstr *s, int32_t *st, TRef tr,
751 TRef trlen, TRef tr0)
633{ 752{
634 J->base[0] = emitir(IRTI(IR_FLOAD), lj_ir_tostr(J, J->base[0]), IRFL_STR_LEN); 753 int32_t start = *st;
635 UNUSED(rd); 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;
636} 773}
637 774
638/* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */ 775/* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */
@@ -679,39 +816,21 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
679 } else if ((MSize)end <= str->len) { 816 } else if ((MSize)end <= str->len) {
680 emitir(IRTGI(IR_ULE), trend, trlen); 817 emitir(IRTGI(IR_ULE), trend, trlen);
681 } else { 818 } else {
682 emitir(IRTGI(IR_GT), trend, trlen); 819 emitir(IRTGI(IR_UGT), trend, trlen);
683 end = (int32_t)str->len; 820 end = (int32_t)str->len;
684 trend = trlen; 821 trend = trlen;
685 } 822 }
686 if (start < 0) { 823 trstart = recff_string_start(J, str, &start, trstart, trlen, tr0);
687 emitir(IRTGI(IR_LT), trstart, tr0);
688 trstart = emitir(IRTI(IR_ADD), trlen, trstart);
689 start = start+(int32_t)str->len;
690 emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), trstart, tr0);
691 if (start < 0) {
692 trstart = tr0;
693 start = 0;
694 }
695 } else {
696 if (start == 0) {
697 emitir(IRTGI(IR_EQ), trstart, tr0);
698 trstart = tr0;
699 } else {
700 trstart = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, -1));
701 emitir(IRTGI(IR_GE), trstart, tr0);
702 start--;
703 }
704 }
705 if (rd->data) { /* Return string.sub result. */ 824 if (rd->data) { /* Return string.sub result. */
706 if (end - start >= 0) { 825 if (end - start >= 0) {
707 /* Also handle empty range here, to avoid extra traces. */ 826 /* Also handle empty range here, to avoid extra traces. */
708 TRef trptr, trslen = emitir(IRTI(IR_SUB), trend, trstart); 827 TRef trptr, trslen = emitir(IRTI(IR_SUB), trend, trstart);
709 emitir(IRTGI(IR_GE), trslen, tr0); 828 emitir(IRTGI(IR_GE), trslen, tr0);
710 trptr = emitir(IRT(IR_STRREF, IRT_P32), trstr, trstart); 829 trptr = emitir(IRT(IR_STRREF, IRT_PGC), trstr, trstart);
711 J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen); 830 J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen);
712 } else { /* Range underflow: return empty string. */ 831 } else { /* Range underflow: return empty string. */
713 emitir(IRTGI(IR_LT), trend, trstart); 832 emitir(IRTGI(IR_LT), trend, trstart);
714 J->base[0] = lj_ir_kstr(J, lj_str_new(J->L, strdata(str), 0)); 833 J->base[0] = lj_ir_kstr(J, &J2G(J)->strempty);
715 } 834 }
716 } else { /* Return string.byte result(s). */ 835 } else { /* Return string.byte result(s). */
717 ptrdiff_t i, len = end - start; 836 ptrdiff_t i, len = end - start;
@@ -723,7 +842,7 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
723 rd->nres = len; 842 rd->nres = len;
724 for (i = 0; i < len; i++) { 843 for (i = 0; i < len; i++) {
725 TRef tmp = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, (int32_t)i)); 844 TRef tmp = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, (int32_t)i));
726 tmp = emitir(IRT(IR_STRREF, IRT_P32), trstr, tmp); 845 tmp = emitir(IRT(IR_STRREF, IRT_PGC), trstr, tmp);
727 J->base[i] = emitir(IRT(IR_XLOAD, IRT_U8), tmp, IRXLOAD_READONLY); 846 J->base[i] = emitir(IRT(IR_XLOAD, IRT_U8), tmp, IRXLOAD_READONLY);
728 } 847 }
729 } else { /* Empty range or range underflow: return no results. */ 848 } else { /* Empty range or range underflow: return no results. */
@@ -733,48 +852,203 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
733 } 852 }
734} 853}
735 854
736/* -- Table library fast functions ---------------------------------------- */ 855static void LJ_FASTCALL recff_string_char(jit_State *J, RecordFFData *rd)
737
738static void LJ_FASTCALL recff_table_getn(jit_State *J, RecordFFData *rd)
739{ 856{
740 if (tref_istab(J->base[0])) 857 TRef k255 = lj_ir_kint(J, 255);
741 J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, J->base[0]); 858 BCReg i;
742 /* else: Interpreter will throw. */ 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 } else if (i == 0) {
870 J->base[0] = lj_ir_kstr(J, &J2G(J)->strempty);
871 }
743 UNUSED(rd); 872 UNUSED(rd);
744} 873}
745 874
746static void LJ_FASTCALL recff_table_remove(jit_State *J, RecordFFData *rd) 875static void LJ_FASTCALL recff_string_rep(jit_State *J, RecordFFData *rd)
747{ 876{
748 TRef tab = J->base[0]; 877 TRef str = lj_ir_tostr(J, J->base[0]);
749 rd->nres = 0; 878 TRef rep = lj_opt_narrow_toint(J, J->base[1]);
750 if (tref_istab(tab)) { 879 TRef hdr, tr, str2 = 0;
751 if (tref_isnil(J->base[1])) { /* Simple pop: t[#t] = nil */ 880 if (!tref_isnil(J->base[2])) {
752 TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, tab); 881 TRef sep = lj_ir_tostr(J, J->base[2]);
753 GCtab *t = tabV(&rd->argv[0]); 882 int32_t vrep = argv2int(J, &rd->argv[1]);
754 MSize len = lj_tab_len(t); 883 emitir(IRTGI(vrep > 1 ? IR_GT : IR_LE), rep, lj_ir_kint(J, 1));
755 emitir(IRTGI(len ? IR_NE : IR_EQ), trlen, lj_ir_kint(J, 0)); 884 if (vrep > 1) {
756 if (len) { 885 TRef hdr2 = recff_bufhdr(J);
757 RecordIndex ix; 886 TRef tr2 = emitir(IRT(IR_BUFPUT, IRT_PGC), hdr2, sep);
758 ix.tab = tab; 887 tr2 = emitir(IRT(IR_BUFPUT, IRT_PGC), tr2, str);
759 ix.key = trlen; 888 str2 = emitir(IRT(IR_BUFSTR, IRT_STR), tr2, hdr2);
760 settabV(J->L, &ix.tabv, t); 889 }
761 setintV(&ix.keyv, len); 890 }
762 ix.idxchain = 0; 891 tr = hdr = recff_bufhdr(J);
763 if (results_wanted(J) != 0) { /* Specialize load only if needed. */ 892 if (str2) {
764 ix.val = 0; 893 tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, str);
765 J->base[0] = lj_record_idx(J, &ix); /* Load previous value. */ 894 str = str2;
766 rd->nres = 1; 895 rep = emitir(IRTI(IR_ADD), rep, lj_ir_kint(J, -1));
767 /* Assumes ix.key/ix.tab is not modified for raw lj_record_idx(). */ 896 }
768 } 897 tr = lj_ir_call(J, IRCALL_lj_buf_putstr_rep, tr, str, rep);
769 ix.val = TREF_NIL; 898 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
770 lj_record_idx(J, &ix); /* Remove value. */ 899}
900
901static void LJ_FASTCALL recff_string_op(jit_State *J, RecordFFData *rd)
902{
903 TRef str = lj_ir_tostr(J, J->base[0]);
904 TRef hdr = recff_bufhdr(J);
905 TRef tr = lj_ir_call(J, rd->data, hdr, str);
906 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
907}
908
909static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd)
910{
911 TRef trstr = lj_ir_tostr(J, J->base[0]);
912 TRef trpat = lj_ir_tostr(J, J->base[1]);
913 TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN);
914 TRef tr0 = lj_ir_kint(J, 0);
915 TRef trstart;
916 GCstr *str = argv2str(J, &rd->argv[0]);
917 GCstr *pat = argv2str(J, &rd->argv[1]);
918 int32_t start;
919 J->needsnap = 1;
920 if (tref_isnil(J->base[2])) {
921 trstart = lj_ir_kint(J, 1);
922 start = 1;
923 } else {
924 trstart = lj_opt_narrow_toint(J, J->base[2]);
925 start = argv2int(J, &rd->argv[2]);
926 }
927 trstart = recff_string_start(J, str, &start, trstart, trlen, tr0);
928 if ((MSize)start <= str->len) {
929 emitir(IRTGI(IR_ULE), trstart, trlen);
930 } else {
931 emitir(IRTGI(IR_UGT), trstart, trlen);
932#if LJ_52
933 J->base[0] = TREF_NIL;
934 return;
935#else
936 trstart = trlen;
937 start = str->len;
938#endif
939 }
940 /* Fixed arg or no pattern matching chars? (Specialized to pattern string.) */
941 if ((J->base[2] && tref_istruecond(J->base[3])) ||
942 (emitir(IRTG(IR_EQ, IRT_STR), trpat, lj_ir_kstr(J, pat)),
943 !lj_str_haspattern(pat))) { /* Search for fixed string. */
944 TRef trsptr = emitir(IRT(IR_STRREF, IRT_PGC), trstr, trstart);
945 TRef trpptr = emitir(IRT(IR_STRREF, IRT_PGC), trpat, tr0);
946 TRef trslen = emitir(IRTI(IR_SUB), trlen, trstart);
947 TRef trplen = emitir(IRTI(IR_FLOAD), trpat, IRFL_STR_LEN);
948 TRef tr = lj_ir_call(J, IRCALL_lj_str_find, trsptr, trpptr, trslen, trplen);
949 TRef trp0 = lj_ir_kkptr(J, NULL);
950 if (lj_str_find(strdata(str)+(MSize)start, strdata(pat),
951 str->len-(MSize)start, pat->len)) {
952 TRef pos;
953 emitir(IRTG(IR_NE, IRT_PGC), tr, trp0);
954 /* Recompute offset. trsptr may not point into trstr after folding. */
955 pos = emitir(IRTI(IR_ADD), emitir(IRTI(IR_SUB), tr, trsptr), trstart);
956 J->base[0] = emitir(IRTI(IR_ADD), pos, lj_ir_kint(J, 1));
957 J->base[1] = emitir(IRTI(IR_ADD), pos, trplen);
958 rd->nres = 2;
959 } else {
960 emitir(IRTG(IR_EQ, IRT_PGC), tr, trp0);
961 J->base[0] = TREF_NIL;
962 }
963 } else { /* Search for pattern. */
964 recff_nyiu(J, rd);
965 return;
966 }
967}
968
969static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
970{
971 TRef trfmt = lj_ir_tostr(J, J->base[0]);
972 GCstr *fmt = argv2str(J, &rd->argv[0]);
973 int arg = 1;
974 TRef hdr, tr;
975 FormatState fs;
976 SFormat sf;
977 /* Specialize to the format string. */
978 emitir(IRTG(IR_EQ, IRT_STR), trfmt, lj_ir_kstr(J, fmt));
979 tr = hdr = recff_bufhdr(J);
980 lj_strfmt_init(&fs, strdata(fmt), fmt->len);
981 while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { /* Parse format. */
982 TRef tra = sf == STRFMT_LIT ? 0 : J->base[arg++];
983 TRef trsf = lj_ir_kint(J, (int32_t)sf);
984 IRCallID id;
985 switch (STRFMT_TYPE(sf)) {
986 case STRFMT_LIT:
987 tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr,
988 lj_ir_kstr(J, lj_str_new(J->L, fs.str, fs.len)));
989 break;
990 case STRFMT_INT:
991 id = IRCALL_lj_strfmt_putfnum_int;
992 handle_int:
993 if (!tref_isinteger(tra))
994 goto handle_num;
995 if (sf == STRFMT_INT) { /* Shortcut for plain %d. */
996 tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr,
997 emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_INT));
998 } else {
999#if LJ_HASFFI
1000 tra = emitir(IRT(IR_CONV, IRT_U64), tra,
1001 (IRT_INT|(IRT_U64<<5)|IRCONV_SEXT));
1002 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra);
1003 lj_needsplit(J);
1004#else
1005 recff_nyiu(J, rd); /* Don't bother working around this NYI. */
1006 return;
1007#endif
1008 }
1009 break;
1010 case STRFMT_UINT:
1011 id = IRCALL_lj_strfmt_putfnum_uint;
1012 goto handle_int;
1013 case STRFMT_NUM:
1014 id = IRCALL_lj_strfmt_putfnum;
1015 handle_num:
1016 tra = lj_ir_tonum(J, tra);
1017 tr = lj_ir_call(J, id, tr, trsf, tra);
1018 if (LJ_SOFTFP32) lj_needsplit(J);
1019 break;
1020 case STRFMT_STR:
1021 if (!tref_isstr(tra)) {
1022 recff_nyiu(J, rd); /* NYI: __tostring and non-string types for %s. */
1023 return;
771 } 1024 }
772 } else { /* Complex case: remove in the middle. */ 1025 if (sf == STRFMT_STR) /* Shortcut for plain %s. */
773 recff_nyiu(J); 1026 tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, tra);
1027 else if ((sf & STRFMT_T_QUOTED))
1028 tr = lj_ir_call(J, IRCALL_lj_strfmt_putquoted, tr, tra);
1029 else
1030 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfstr, tr, trsf, tra);
1031 break;
1032 case STRFMT_CHAR:
1033 tra = lj_opt_narrow_toint(J, tra);
1034 if (sf == STRFMT_CHAR) /* Shortcut for plain %c. */
1035 tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr,
1036 emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_CHAR));
1037 else
1038 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfchar, tr, trsf, tra);
1039 break;
1040 case STRFMT_PTR: /* NYI */
1041 case STRFMT_ERR:
1042 default:
1043 recff_nyiu(J, rd);
1044 return;
774 } 1045 }
775 } /* else: Interpreter will throw. */ 1046 }
1047 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
776} 1048}
777 1049
1050/* -- Table library fast functions ---------------------------------------- */
1051
778static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) 1052static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
779{ 1053{
780 RecordIndex ix; 1054 RecordIndex ix;
@@ -791,11 +1065,49 @@ static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
791 ix.idxchain = 0; 1065 ix.idxchain = 0;
792 lj_record_idx(J, &ix); /* Set new value. */ 1066 lj_record_idx(J, &ix); /* Set new value. */
793 } else { /* Complex case: insert in the middle. */ 1067 } else { /* Complex case: insert in the middle. */
794 recff_nyiu(J); 1068 recff_nyiu(J, rd);
1069 return;
795 } 1070 }
796 } /* else: Interpreter will throw. */ 1071 } /* else: Interpreter will throw. */
797} 1072}
798 1073
1074static void LJ_FASTCALL recff_table_concat(jit_State *J, RecordFFData *rd)
1075{
1076 TRef tab = J->base[0];
1077 if (tref_istab(tab)) {
1078 TRef sep = !tref_isnil(J->base[1]) ?
1079 lj_ir_tostr(J, J->base[1]) : lj_ir_knull(J, IRT_STR);
1080 TRef tri = (J->base[1] && !tref_isnil(J->base[2])) ?
1081 lj_opt_narrow_toint(J, J->base[2]) : lj_ir_kint(J, 1);
1082 TRef tre = (J->base[1] && J->base[2] && !tref_isnil(J->base[3])) ?
1083 lj_opt_narrow_toint(J, J->base[3]) :
1084 lj_ir_call(J, IRCALL_lj_tab_len, tab);
1085 TRef hdr = recff_bufhdr(J);
1086 TRef tr = lj_ir_call(J, IRCALL_lj_buf_puttab, hdr, tab, sep, tri, tre);
1087 emitir(IRTG(IR_NE, IRT_PTR), tr, lj_ir_kptr(J, NULL));
1088 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
1089 } /* else: Interpreter will throw. */
1090 UNUSED(rd);
1091}
1092
1093static void LJ_FASTCALL recff_table_new(jit_State *J, RecordFFData *rd)
1094{
1095 TRef tra = lj_opt_narrow_toint(J, J->base[0]);
1096 TRef trh = lj_opt_narrow_toint(J, J->base[1]);
1097 J->base[0] = lj_ir_call(J, IRCALL_lj_tab_new_ah, tra, trh);
1098 UNUSED(rd);
1099}
1100
1101static void LJ_FASTCALL recff_table_clear(jit_State *J, RecordFFData *rd)
1102{
1103 TRef tr = J->base[0];
1104 if (tref_istab(tr)) {
1105 rd->nres = 0;
1106 lj_ir_call(J, IRCALL_lj_tab_clear, tr);
1107 J->needsnap = 1;
1108 } /* else: Interpreter will throw. */
1109}
1110
799/* -- I/O library fast functions ------------------------------------------ */ 1111/* -- I/O library fast functions ------------------------------------------ */
800 1112
801/* Get FILE* for I/O function. Any I/O error aborts recording, so there's 1113/* Get FILE* for I/O function. Any I/O error aborts recording, so there's
@@ -805,8 +1117,13 @@ static TRef recff_io_fp(jit_State *J, TRef *udp, int32_t id)
805{ 1117{
806 TRef tr, ud, fp; 1118 TRef tr, ud, fp;
807 if (id) { /* io.func() */ 1119 if (id) { /* io.func() */
1120#if LJ_GC64
1121 /* TODO: fix ARM32 asm_fload(), so we can use this for all archs. */
1122 ud = lj_ir_ggfload(J, IRT_UDATA, GG_OFS(g.gcroot[id]));
1123#else
808 tr = lj_ir_kptr(J, &J2G(J)->gcroot[id]); 1124 tr = lj_ir_kptr(J, &J2G(J)->gcroot[id]);
809 ud = emitir(IRT(IR_XLOAD, IRT_UDATA), tr, 0); 1125 ud = emitir(IRT(IR_XLOAD, IRT_UDATA), tr, 0);
1126#endif
810 } else { /* fp:method() */ 1127 } else { /* fp:method() */
811 ud = J->base[0]; 1128 ud = J->base[0];
812 if (!tref_isudata(ud)) 1129 if (!tref_isudata(ud))
@@ -828,10 +1145,13 @@ static void LJ_FASTCALL recff_io_write(jit_State *J, RecordFFData *rd)
828 ptrdiff_t i = rd->data == 0 ? 1 : 0; 1145 ptrdiff_t i = rd->data == 0 ? 1 : 0;
829 for (; J->base[i]; i++) { 1146 for (; J->base[i]; i++) {
830 TRef str = lj_ir_tostr(J, J->base[i]); 1147 TRef str = lj_ir_tostr(J, J->base[i]);
831 TRef buf = emitir(IRT(IR_STRREF, IRT_P32), str, zero); 1148 TRef buf = emitir(IRT(IR_STRREF, IRT_PGC), str, zero);
832 TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN); 1149 TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN);
833 if (tref_isk(len) && IR(tref_ref(len))->i == 1) { 1150 if (tref_isk(len) && IR(tref_ref(len))->i == 1) {
834 TRef tr = emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY); 1151 IRIns *irs = IR(tref_ref(str));
1152 TRef tr = (irs->o == IR_TOSTR && irs->op2 == IRTOSTR_CHAR) ?
1153 irs->op1 :
1154 emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY);
835 tr = lj_ir_call(J, IRCALL_fputc, tr, fp); 1155 tr = lj_ir_call(J, IRCALL_fputc, tr, fp);
836 if (results_wanted(J) != 0) /* Check result only if not ignored. */ 1156 if (results_wanted(J) != 0) /* Check result only if not ignored. */
837 emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1)); 1157 emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1));
@@ -853,6 +1173,28 @@ static void LJ_FASTCALL recff_io_flush(jit_State *J, RecordFFData *rd)
853 J->base[0] = TREF_TRUE; 1173 J->base[0] = TREF_TRUE;
854} 1174}
855 1175
1176/* -- Debug library fast functions ---------------------------------------- */
1177
1178static void LJ_FASTCALL recff_debug_getmetatable(jit_State *J, RecordFFData *rd)
1179{
1180 GCtab *mt;
1181 TRef mtref;
1182 TRef tr = J->base[0];
1183 if (tref_istab(tr)) {
1184 mt = tabref(tabV(&rd->argv[0])->metatable);
1185 mtref = emitir(IRT(IR_FLOAD, IRT_TAB), tr, IRFL_TAB_META);
1186 } else if (tref_isudata(tr)) {
1187 mt = tabref(udataV(&rd->argv[0])->metatable);
1188 mtref = emitir(IRT(IR_FLOAD, IRT_TAB), tr, IRFL_UDATA_META);
1189 } else {
1190 mt = tabref(basemt_obj(J2G(J), &rd->argv[0]));
1191 J->base[0] = mt ? lj_ir_ktab(J, mt) : TREF_NIL;
1192 return;
1193 }
1194 emitir(IRTG(mt ? IR_NE : IR_EQ, IRT_TAB), mtref, lj_ir_knull(J, IRT_TAB));
1195 J->base[0] = mt ? mtref : TREF_NIL;
1196}
1197
856/* -- Record calls to fast functions -------------------------------------- */ 1198/* -- Record calls to fast functions -------------------------------------- */
857 1199
858#include "lj_recdef.h" 1200#include "lj_recdef.h"