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.c531
1 files changed, 417 insertions, 114 deletions
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c
index 794bbd43..8470dd8c 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,89 @@ 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 TraceNo traceno = J->cur.traceno;
104 lua_State *L = J->L;
105 TValue *base = L->base;
106 const BCIns *pc = frame_pc(base-1);
107 TValue *pframe = frame_prevl(base-1);
108 TRef trcont;
109
110 /* Move func + args up in Lua stack and insert continuation. */
111 memmove(&base[1], &base[-1], sizeof(TValue)*(J->maxslot+1));
112 setframe_ftsz(base+1, (int)((char *)(base+1) - (char *)pframe) + FRAME_CONT);
113 setcont(base, cont);
114 setframe_pc(base, pc);
115 if (LJ_DUALNUM) setintV(base-1, traceno); else base[-1].u64 = traceno;
116 L->base += 2;
117 L->top += 2;
118
119 /* Ditto for the IR. */
120 memmove(&J->base[1], &J->base[-1], sizeof(TRef)*(J->maxslot+1));
121#if LJ_64
122 trcont = lj_ir_kptr(J, (void *)((int64_t)cont-(int64_t)lj_vm_asm_begin));
123#else
124 trcont = lj_ir_kptr(J, (void *)cont);
125#endif
126 J->base[0] = trcont | TREF_CONT;
127 J->base[-1] = LJ_DUALNUM ? lj_ir_kint(J,traceno) : lj_ir_knum_u64(J,traceno);
128 J->base += 2;
129 J->baseslot += 2;
130 J->framedepth++;
131
132 lj_record_stop(J, LJ_TRLINK_STITCH, 0);
133
134 /* Undo Lua stack changes. */
135 memmove(&base[-1], &base[1], sizeof(TValue)*(J->maxslot+1));
136 setframe_pc(base-1, pc);
137 L->base -= 2;
138 L->top -= 2;
106} 139}
107 140
108/* Fallback handler for all fast functions that are not recorded (yet). */ 141/* Fallback handler for fast functions that are not recorded (yet). */
109static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd) 142static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd)
110{ 143{
111 setfuncV(J->L, &J->errinfo, J->fn); 144 if (J->cur.nins < (IRRef)J->param[JIT_P_minstitch] + REF_BASE) {
112 lj_trace_err_info(J, LJ_TRERR_NYIFF); 145 lj_trace_err_info(J, LJ_TRERR_TRACEUV);
113 UNUSED(rd); 146 } else {
147 /* Can only stitch from Lua call. */
148 if (J->framedepth && frame_islua(J->L->base-1)) {
149 BCOp op = bc_op(*frame_pc(J->L->base-1));
150 /* Stitched trace cannot start with *M op with variable # of args. */
151 if (!(op == BC_CALLM || op == BC_CALLMT ||
152 op == BC_RETM || op == BC_TSETM)) {
153 switch (J->fn->c.ffid) {
154 case FF_error:
155 case FF_debug_sethook:
156 case FF_jit_flush:
157 break; /* Don't stitch across special builtins. */
158 default:
159 recff_stitch(J); /* Use trace stitching. */
160 rd->nres = -1;
161 return;
162 }
163 }
164 }
165 /* Otherwise stop trace and return to interpreter. */
166 lj_record_stop(J, LJ_TRLINK_RETURN, 0);
167 rd->nres = -1;
168 }
114} 169}
115 170
116/* C functions can have arbitrary side-effects and are not recorded (yet). */ 171/* Fallback handler for unsupported variants of fast functions. */
117static void LJ_FASTCALL recff_c(jit_State *J, RecordFFData *rd) 172#define recff_nyiu recff_nyi
173
174/* Must stop the trace for classic C functions with arbitrary side-effects. */
175#define recff_c recff_nyi
176
177/* Emit BUFHDR for the global temporary buffer. */
178static TRef recff_bufhdr(jit_State *J)
118{ 179{
119 setfuncV(J->L, &J->errinfo, J->fn); 180 return emitir(IRT(IR_BUFHDR, IRT_P32),
120 lj_trace_err_info(J, LJ_TRERR_NYICF); 181 lj_ir_kptr(J, &J2G(J)->tmpbuf), IRBUFHDR_RESET);
121 UNUSED(rd);
122} 182}
123 183
124/* -- Base library fast functions ----------------------------------------- */ 184/* -- Base library fast functions ----------------------------------------- */
@@ -263,7 +323,8 @@ static void LJ_FASTCALL recff_select(jit_State *J, RecordFFData *rd)
263 J->base[i] = J->base[start+i]; 323 J->base[i] = J->base[start+i];
264 } /* else: Interpreter will throw. */ 324 } /* else: Interpreter will throw. */
265 } else { 325 } else {
266 recff_nyiu(J); 326 recff_nyiu(J, rd);
327 return;
267 } 328 }
268 } /* else: Interpreter will throw. */ 329 } /* else: Interpreter will throw. */
269} 330}
@@ -274,14 +335,18 @@ static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd)
274 TRef base = J->base[1]; 335 TRef base = J->base[1];
275 if (tr && !tref_isnil(base)) { 336 if (tr && !tref_isnil(base)) {
276 base = lj_opt_narrow_toint(J, base); 337 base = lj_opt_narrow_toint(J, base);
277 if (!tref_isk(base) || IR(tref_ref(base))->i != 10) 338 if (!tref_isk(base) || IR(tref_ref(base))->i != 10) {
278 recff_nyiu(J); 339 recff_nyiu(J, rd);
340 return;
341 }
279 } 342 }
280 if (tref_isnumber_str(tr)) { 343 if (tref_isnumber_str(tr)) {
281 if (tref_isstr(tr)) { 344 if (tref_isstr(tr)) {
282 TValue tmp; 345 TValue tmp;
283 if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) 346 if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) {
284 recff_nyiu(J); /* Would need an inverted STRTO for this case. */ 347 recff_nyiu(J, rd); /* Would need an inverted STRTO for this case. */
348 return;
349 }
285 tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); 350 tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0);
286 } 351 }
287#if LJ_HASFFI 352#if LJ_HASFFI
@@ -336,13 +401,15 @@ static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd)
336 if (tref_isstr(tr)) { 401 if (tref_isstr(tr)) {
337 /* Ignore __tostring in the string base metatable. */ 402 /* Ignore __tostring in the string base metatable. */
338 /* Pass on result in J->base[0]. */ 403 /* Pass on result in J->base[0]. */
339 } else if (!recff_metacall(J, rd, MM_tostring)) { 404 } else if (tr && !recff_metacall(J, rd, MM_tostring)) {
340 if (tref_isnumber(tr)) { 405 if (tref_isnumber(tr)) {
341 J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); 406 J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr,
407 tref_isnum(tr) ? IRTOSTR_NUM : IRTOSTR_INT);
342 } else if (tref_ispri(tr)) { 408 } else if (tref_ispri(tr)) {
343 J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)])); 409 J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0]));
344 } else { 410 } else {
345 recff_nyiu(J); 411 recff_nyiu(J, rd);
412 return;
346 } 413 }
347 } 414 }
348} 415}
@@ -364,14 +431,14 @@ static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd)
364 } /* else: Interpreter will throw. */ 431 } /* else: Interpreter will throw. */
365} 432}
366 433
367static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd) 434static void LJ_FASTCALL recff_xpairs(jit_State *J, RecordFFData *rd)
368{ 435{
369 if (!(LJ_52 && recff_metacall(J, rd, MM_ipairs))) { 436 if (!(LJ_52 && recff_metacall(J, rd, MM_ipairs))) {
370 TRef tab = J->base[0]; 437 TRef tab = J->base[0];
371 if (tref_istab(tab)) { 438 if (tref_istab(tab)) {
372 J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); 439 J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0]));
373 J->base[1] = tab; 440 J->base[1] = tab;
374 J->base[2] = lj_ir_kint(J, 0); 441 J->base[2] = rd->data ? lj_ir_kint(J, 0) : TREF_NIL;
375 rd->nres = 3; 442 rd->nres = 3;
376 } /* else: Interpreter will throw. */ 443 } /* else: Interpreter will throw. */
377 } 444 }
@@ -416,6 +483,18 @@ static void LJ_FASTCALL recff_xpcall(jit_State *J, RecordFFData *rd)
416 } /* else: Interpreter will throw. */ 483 } /* else: Interpreter will throw. */
417} 484}
418 485
486static void LJ_FASTCALL recff_getfenv(jit_State *J, RecordFFData *rd)
487{
488 TRef tr = J->base[0];
489 /* Only support getfenv(0) for now. */
490 if (tref_isint(tr) && tref_isk(tr) && IR(tref_ref(tr))->i == 0) {
491 TRef trl = emitir(IRT(IR_LREF, IRT_THREAD), 0, 0);
492 J->base[0] = emitir(IRT(IR_FLOAD, IRT_TAB), trl, IRFL_THREAD_ENV);
493 return;
494 }
495 recff_nyiu(J, rd);
496}
497
419/* -- Math library fast functions ----------------------------------------- */ 498/* -- Math library fast functions ----------------------------------------- */
420 499
421static void LJ_FASTCALL recff_math_abs(jit_State *J, RecordFFData *rd) 500static void LJ_FASTCALL recff_math_abs(jit_State *J, RecordFFData *rd)
@@ -528,14 +607,6 @@ static void LJ_FASTCALL recff_math_modf(jit_State *J, RecordFFData *rd)
528 rd->nres = 2; 607 rd->nres = 2;
529} 608}
530 609
531static void LJ_FASTCALL recff_math_degrad(jit_State *J, RecordFFData *rd)
532{
533 TRef tr = lj_ir_tonum(J, J->base[0]);
534 TRef trm = lj_ir_knum(J, numV(&J->fn->c.upvalue[0]));
535 J->base[0] = emitir(IRTN(IR_MUL), tr, trm);
536 UNUSED(rd);
537}
538
539static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd) 610static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd)
540{ 611{
541 TRef tr = lj_ir_tonum(J, J->base[0]); 612 TRef tr = lj_ir_tonum(J, J->base[0]);
@@ -592,48 +663,105 @@ static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd)
592 663
593/* -- Bit library fast functions ------------------------------------------ */ 664/* -- Bit library fast functions ------------------------------------------ */
594 665
595/* Record unary bit.tobit, bit.bnot, bit.bswap. */ 666/* Record bit.tobit. */
667static void LJ_FASTCALL recff_bit_tobit(jit_State *J, RecordFFData *rd)
668{
669 TRef tr = J->base[0];
670#if LJ_HASFFI
671 if (tref_iscdata(tr)) { recff_bit64_tobit(J, rd); return; }
672#endif
673 J->base[0] = lj_opt_narrow_tobit(J, tr);
674 UNUSED(rd);
675}
676
677/* Record unary bit.bnot, bit.bswap. */
596static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd) 678static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd)
597{ 679{
598 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 680#if LJ_HASFFI
599 J->base[0] = (rd->data == IR_TOBIT) ? tr : emitir(IRTI(rd->data), tr, 0); 681 if (recff_bit64_unary(J, rd))
682 return;
683#endif
684 J->base[0] = emitir(IRTI(rd->data), lj_opt_narrow_tobit(J, J->base[0]), 0);
600} 685}
601 686
602/* Record N-ary bit.band, bit.bor, bit.bxor. */ 687/* Record N-ary bit.band, bit.bor, bit.bxor. */
603static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd) 688static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd)
604{ 689{
605 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 690#if LJ_HASFFI
606 uint32_t op = rd->data; 691 if (recff_bit64_nary(J, rd))
607 BCReg i; 692 return;
608 for (i = 1; J->base[i] != 0; i++) 693#endif
609 tr = emitir(IRTI(op), tr, lj_opt_narrow_tobit(J, J->base[i])); 694 {
610 J->base[0] = tr; 695 TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
696 uint32_t ot = IRTI(rd->data);
697 BCReg i;
698 for (i = 1; J->base[i] != 0; i++)
699 tr = emitir(ot, tr, lj_opt_narrow_tobit(J, J->base[i]));
700 J->base[0] = tr;
701 }
611} 702}
612 703
613/* Record bit shifts. */ 704/* Record bit shifts. */
614static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) 705static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd)
615{ 706{
616 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 707#if LJ_HASFFI
617 TRef tsh = lj_opt_narrow_tobit(J, J->base[1]); 708 if (recff_bit64_shift(J, rd))
618 IROp op = (IROp)rd->data; 709 return;
619 if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && 710#endif
620 !tref_isk(tsh)) 711 {
621 tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31)); 712 TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
713 TRef tsh = lj_opt_narrow_tobit(J, J->base[1]);
714 IROp op = (IROp)rd->data;
715 if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) &&
716 !tref_isk(tsh))
717 tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31));
622#ifdef LJ_TARGET_UNIFYROT 718#ifdef LJ_TARGET_UNIFYROT
623 if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) { 719 if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) {
624 op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR; 720 op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR;
625 tsh = emitir(IRTI(IR_NEG), tsh, tsh); 721 tsh = emitir(IRTI(IR_NEG), tsh, tsh);
722 }
723#endif
724 J->base[0] = emitir(IRTI(op), tr, tsh);
626 } 725 }
726}
727
728static void LJ_FASTCALL recff_bit_tohex(jit_State *J, RecordFFData *rd)
729{
730#if LJ_HASFFI
731 TRef hdr = recff_bufhdr(J);
732 TRef tr = recff_bit64_tohex(J, rd, hdr);
733 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
734#else
735 recff_nyiu(J, rd); /* Don't bother working around this NYI. */
627#endif 736#endif
628 J->base[0] = emitir(IRTI(op), tr, tsh);
629} 737}
630 738
631/* -- String library fast functions --------------------------------------- */ 739/* -- String library fast functions --------------------------------------- */
632 740
633static void LJ_FASTCALL recff_string_len(jit_State *J, RecordFFData *rd) 741/* Specialize to relative starting position for string. */
742static TRef recff_string_start(jit_State *J, GCstr *s, int32_t *st, TRef tr,
743 TRef trlen, TRef tr0)
634{ 744{
635 J->base[0] = emitir(IRTI(IR_FLOAD), lj_ir_tostr(J, J->base[0]), IRFL_STR_LEN); 745 int32_t start = *st;
636 UNUSED(rd); 746 if (start < 0) {
747 emitir(IRTGI(IR_LT), tr, tr0);
748 tr = emitir(IRTI(IR_ADD), trlen, tr);
749 start = start + (int32_t)s->len;
750 emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), tr, tr0);
751 if (start < 0) {
752 tr = tr0;
753 start = 0;
754 }
755 } else if (start == 0) {
756 emitir(IRTGI(IR_EQ), tr, tr0);
757 tr = tr0;
758 } else {
759 tr = emitir(IRTI(IR_ADD), tr, lj_ir_kint(J, -1));
760 emitir(IRTGI(IR_GE), tr, tr0);
761 start--;
762 }
763 *st = start;
764 return tr;
637} 765}
638 766
639/* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */ 767/* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */
@@ -680,29 +808,11 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
680 } else if ((MSize)end <= str->len) { 808 } else if ((MSize)end <= str->len) {
681 emitir(IRTGI(IR_ULE), trend, trlen); 809 emitir(IRTGI(IR_ULE), trend, trlen);
682 } else { 810 } else {
683 emitir(IRTGI(IR_GT), trend, trlen); 811 emitir(IRTGI(IR_UGT), trend, trlen);
684 end = (int32_t)str->len; 812 end = (int32_t)str->len;
685 trend = trlen; 813 trend = trlen;
686 } 814 }
687 if (start < 0) { 815 trstart = recff_string_start(J, str, &start, trstart, trlen, tr0);
688 emitir(IRTGI(IR_LT), trstart, tr0);
689 trstart = emitir(IRTI(IR_ADD), trlen, trstart);
690 start = start+(int32_t)str->len;
691 emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), trstart, tr0);
692 if (start < 0) {
693 trstart = tr0;
694 start = 0;
695 }
696 } else {
697 if (start == 0) {
698 emitir(IRTGI(IR_EQ), trstart, tr0);
699 trstart = tr0;
700 } else {
701 trstart = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, -1));
702 emitir(IRTGI(IR_GE), trstart, tr0);
703 start--;
704 }
705 }
706 if (rd->data) { /* Return string.sub result. */ 816 if (rd->data) { /* Return string.sub result. */
707 if (end - start >= 0) { 817 if (end - start >= 0) {
708 /* Also handle empty range here, to avoid extra traces. */ 818 /* Also handle empty range here, to avoid extra traces. */
@@ -712,7 +822,7 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
712 J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen); 822 J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen);
713 } else { /* Range underflow: return empty string. */ 823 } else { /* Range underflow: return empty string. */
714 emitir(IRTGI(IR_LT), trend, trstart); 824 emitir(IRTGI(IR_LT), trend, trstart);
715 J->base[0] = lj_ir_kstr(J, lj_str_new(J->L, strdata(str), 0)); 825 J->base[0] = lj_ir_kstr(J, &J2G(J)->strempty);
716 } 826 }
717 } else { /* Return string.byte result(s). */ 827 } else { /* Return string.byte result(s). */
718 ptrdiff_t i, len = end - start; 828 ptrdiff_t i, len = end - start;
@@ -734,48 +844,200 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
734 } 844 }
735} 845}
736 846
737/* -- Table library fast functions ---------------------------------------- */ 847static void LJ_FASTCALL recff_string_char(jit_State *J, RecordFFData *rd)
738
739static void LJ_FASTCALL recff_table_getn(jit_State *J, RecordFFData *rd)
740{ 848{
741 if (tref_istab(J->base[0])) 849 TRef k255 = lj_ir_kint(J, 255);
742 J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, J->base[0]); 850 BCReg i;
743 /* else: Interpreter will throw. */ 851 for (i = 0; J->base[i] != 0; i++) { /* Convert char values to strings. */
852 TRef tr = lj_opt_narrow_toint(J, J->base[i]);
853 emitir(IRTGI(IR_ULE), tr, k255);
854 J->base[i] = emitir(IRT(IR_TOSTR, IRT_STR), tr, IRTOSTR_CHAR);
855 }
856 if (i > 1) { /* Concatenate the strings, if there's more than one. */
857 TRef hdr = recff_bufhdr(J), tr = hdr;
858 for (i = 0; J->base[i] != 0; i++)
859 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, J->base[i]);
860 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
861 }
744 UNUSED(rd); 862 UNUSED(rd);
745} 863}
746 864
747static void LJ_FASTCALL recff_table_remove(jit_State *J, RecordFFData *rd) 865static void LJ_FASTCALL recff_string_rep(jit_State *J, RecordFFData *rd)
748{ 866{
749 TRef tab = J->base[0]; 867 TRef str = lj_ir_tostr(J, J->base[0]);
750 rd->nres = 0; 868 TRef rep = lj_opt_narrow_toint(J, J->base[1]);
751 if (tref_istab(tab)) { 869 TRef hdr, tr, str2 = 0;
752 if (tref_isnil(J->base[1])) { /* Simple pop: t[#t] = nil */ 870 if (!tref_isnil(J->base[2])) {
753 TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, tab); 871 TRef sep = lj_ir_tostr(J, J->base[2]);
754 GCtab *t = tabV(&rd->argv[0]); 872 int32_t vrep = argv2int(J, &rd->argv[1]);
755 MSize len = lj_tab_len(t); 873 emitir(IRTGI(vrep > 1 ? IR_GT : IR_LE), rep, lj_ir_kint(J, 1));
756 emitir(IRTGI(len ? IR_NE : IR_EQ), trlen, lj_ir_kint(J, 0)); 874 if (vrep > 1) {
757 if (len) { 875 TRef hdr2 = recff_bufhdr(J);
758 RecordIndex ix; 876 TRef tr2 = emitir(IRT(IR_BUFPUT, IRT_P32), hdr2, sep);
759 ix.tab = tab; 877 tr2 = emitir(IRT(IR_BUFPUT, IRT_P32), tr2, str);
760 ix.key = trlen; 878 str2 = emitir(IRT(IR_BUFSTR, IRT_STR), tr2, hdr2);
761 settabV(J->L, &ix.tabv, t); 879 }
762 setintV(&ix.keyv, len); 880 }
763 ix.idxchain = 0; 881 tr = hdr = recff_bufhdr(J);
764 if (results_wanted(J) != 0) { /* Specialize load only if needed. */ 882 if (str2) {
765 ix.val = 0; 883 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, str);
766 J->base[0] = lj_record_idx(J, &ix); /* Load previous value. */ 884 str = str2;
767 rd->nres = 1; 885 rep = emitir(IRTI(IR_ADD), rep, lj_ir_kint(J, -1));
768 /* Assumes ix.key/ix.tab is not modified for raw lj_record_idx(). */ 886 }
769 } 887 tr = lj_ir_call(J, IRCALL_lj_buf_putstr_rep, tr, str, rep);
770 ix.val = TREF_NIL; 888 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
771 lj_record_idx(J, &ix); /* Remove value. */ 889}
890
891static void LJ_FASTCALL recff_string_op(jit_State *J, RecordFFData *rd)
892{
893 TRef str = lj_ir_tostr(J, J->base[0]);
894 TRef hdr = recff_bufhdr(J);
895 TRef tr = lj_ir_call(J, rd->data, hdr, str);
896 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
897}
898
899static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd)
900{
901 TRef trstr = lj_ir_tostr(J, J->base[0]);
902 TRef trpat = lj_ir_tostr(J, J->base[1]);
903 TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN);
904 TRef tr0 = lj_ir_kint(J, 0);
905 TRef trstart;
906 GCstr *str = argv2str(J, &rd->argv[0]);
907 GCstr *pat = argv2str(J, &rd->argv[1]);
908 int32_t start;
909 J->needsnap = 1;
910 if (tref_isnil(J->base[2])) {
911 trstart = lj_ir_kint(J, 1);
912 start = 1;
913 } else {
914 trstart = lj_opt_narrow_toint(J, J->base[2]);
915 start = argv2int(J, &rd->argv[2]);
916 }
917 trstart = recff_string_start(J, str, &start, trstart, trlen, tr0);
918 if ((MSize)start <= str->len) {
919 emitir(IRTGI(IR_ULE), trstart, trlen);
920 } else {
921 emitir(IRTGI(IR_UGT), trstart, trlen);
922#if LJ_52
923 J->base[0] = TREF_NIL;
924 return;
925#else
926 trstart = trlen;
927 start = str->len;
928#endif
929 }
930 /* Fixed arg or no pattern matching chars? (Specialized to pattern string.) */
931 if ((J->base[2] && tref_istruecond(J->base[3])) ||
932 (emitir(IRTG(IR_EQ, IRT_STR), trpat, lj_ir_kstr(J, pat)),
933 !lj_str_haspattern(pat))) { /* Search for fixed string. */
934 TRef trsptr = emitir(IRT(IR_STRREF, IRT_P32), trstr, trstart);
935 TRef trpptr = emitir(IRT(IR_STRREF, IRT_P32), trpat, tr0);
936 TRef trslen = emitir(IRTI(IR_SUB), trlen, trstart);
937 TRef trplen = emitir(IRTI(IR_FLOAD), trpat, IRFL_STR_LEN);
938 TRef tr = lj_ir_call(J, IRCALL_lj_str_find, trsptr, trpptr, trslen, trplen);
939 TRef trp0 = lj_ir_kkptr(J, NULL);
940 if (lj_str_find(strdata(str)+(MSize)start, strdata(pat),
941 str->len-(MSize)start, pat->len)) {
942 TRef pos;
943 emitir(IRTG(IR_NE, IRT_P32), tr, trp0);
944 pos = emitir(IRTI(IR_SUB), tr, emitir(IRT(IR_STRREF, IRT_P32), trstr, tr0));
945 J->base[0] = emitir(IRTI(IR_ADD), pos, lj_ir_kint(J, 1));
946 J->base[1] = emitir(IRTI(IR_ADD), pos, trplen);
947 rd->nres = 2;
948 } else {
949 emitir(IRTG(IR_EQ, IRT_P32), tr, trp0);
950 J->base[0] = TREF_NIL;
951 }
952 } else { /* Search for pattern. */
953 recff_nyiu(J, rd);
954 return;
955 }
956}
957
958static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
959{
960 TRef trfmt = lj_ir_tostr(J, J->base[0]);
961 GCstr *fmt = argv2str(J, &rd->argv[0]);
962 int arg = 1;
963 TRef hdr, tr;
964 FormatState fs;
965 SFormat sf;
966 /* Specialize to the format string. */
967 emitir(IRTG(IR_EQ, IRT_STR), trfmt, lj_ir_kstr(J, fmt));
968 tr = hdr = recff_bufhdr(J);
969 lj_strfmt_init(&fs, strdata(fmt), fmt->len);
970 while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { /* Parse format. */
971 TRef tra = sf == STRFMT_LIT ? 0 : J->base[arg++];
972 TRef trsf = lj_ir_kint(J, (int32_t)sf);
973 IRCallID id;
974 switch (STRFMT_TYPE(sf)) {
975 case STRFMT_LIT:
976 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr,
977 lj_ir_kstr(J, lj_str_new(J->L, fs.str, fs.len)));
978 break;
979 case STRFMT_INT:
980 id = IRCALL_lj_strfmt_putfnum_int;
981 handle_int:
982 if (!tref_isinteger(tra))
983 goto handle_num;
984 if (sf == STRFMT_INT) { /* Shortcut for plain %d. */
985 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr,
986 emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_INT));
987 } else {
988#if LJ_HASFFI
989 tra = emitir(IRT(IR_CONV, IRT_U64), tra,
990 (IRT_INT|(IRT_U64<<5)|IRCONV_SEXT));
991 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra);
992 lj_needsplit(J);
993#else
994 recff_nyiu(J, rd); /* Don't bother working around this NYI. */
995 return;
996#endif
772 } 997 }
773 } else { /* Complex case: remove in the middle. */ 998 break;
774 recff_nyiu(J); 999 case STRFMT_UINT:
1000 id = IRCALL_lj_strfmt_putfnum_uint;
1001 goto handle_int;
1002 case STRFMT_NUM:
1003 id = IRCALL_lj_strfmt_putfnum;
1004 handle_num:
1005 tra = lj_ir_tonum(J, tra);
1006 tr = lj_ir_call(J, id, tr, trsf, tra);
1007 if (LJ_SOFTFP) lj_needsplit(J);
1008 break;
1009 case STRFMT_STR:
1010 if (!tref_isstr(tra)) {
1011 recff_nyiu(J, rd); /* NYI: __tostring and non-string types for %s. */
1012 return;
1013 }
1014 if (sf == STRFMT_STR) /* Shortcut for plain %s. */
1015 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, tra);
1016 else if ((sf & STRFMT_T_QUOTED))
1017 tr = lj_ir_call(J, IRCALL_lj_strfmt_putquoted, tr, tra);
1018 else
1019 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfstr, tr, trsf, tra);
1020 break;
1021 case STRFMT_CHAR:
1022 tra = lj_opt_narrow_toint(J, tra);
1023 if (sf == STRFMT_CHAR) /* Shortcut for plain %c. */
1024 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr,
1025 emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_CHAR));
1026 else
1027 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfchar, tr, trsf, tra);
1028 break;
1029 case STRFMT_PTR: /* NYI */
1030 case STRFMT_ERR:
1031 default:
1032 recff_nyiu(J, rd);
1033 return;
775 } 1034 }
776 } /* else: Interpreter will throw. */ 1035 }
1036 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
777} 1037}
778 1038
1039/* -- Table library fast functions ---------------------------------------- */
1040
779static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) 1041static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
780{ 1042{
781 RecordIndex ix; 1043 RecordIndex ix;
@@ -792,11 +1054,49 @@ static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
792 ix.idxchain = 0; 1054 ix.idxchain = 0;
793 lj_record_idx(J, &ix); /* Set new value. */ 1055 lj_record_idx(J, &ix); /* Set new value. */
794 } else { /* Complex case: insert in the middle. */ 1056 } else { /* Complex case: insert in the middle. */
795 recff_nyiu(J); 1057 recff_nyiu(J, rd);
1058 return;
796 } 1059 }
797 } /* else: Interpreter will throw. */ 1060 } /* else: Interpreter will throw. */
798} 1061}
799 1062
1063static void LJ_FASTCALL recff_table_concat(jit_State *J, RecordFFData *rd)
1064{
1065 TRef tab = J->base[0];
1066 if (tref_istab(tab)) {
1067 TRef sep = !tref_isnil(J->base[1]) ?
1068 lj_ir_tostr(J, J->base[1]) : lj_ir_knull(J, IRT_STR);
1069 TRef tri = (J->base[1] && !tref_isnil(J->base[2])) ?
1070 lj_opt_narrow_toint(J, J->base[2]) : lj_ir_kint(J, 1);
1071 TRef tre = (J->base[1] && J->base[2] && !tref_isnil(J->base[3])) ?
1072 lj_opt_narrow_toint(J, J->base[3]) :
1073 lj_ir_call(J, IRCALL_lj_tab_len, tab);
1074 TRef hdr = recff_bufhdr(J);
1075 TRef tr = lj_ir_call(J, IRCALL_lj_buf_puttab, hdr, tab, sep, tri, tre);
1076 emitir(IRTG(IR_NE, IRT_PTR), tr, lj_ir_kptr(J, NULL));
1077 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
1078 } /* else: Interpreter will throw. */
1079 UNUSED(rd);
1080}
1081
1082static void LJ_FASTCALL recff_table_new(jit_State *J, RecordFFData *rd)
1083{
1084 TRef tra = lj_opt_narrow_toint(J, J->base[0]);
1085 TRef trh = lj_opt_narrow_toint(J, J->base[1]);
1086 J->base[0] = lj_ir_call(J, IRCALL_lj_tab_new_ah, tra, trh);
1087 UNUSED(rd);
1088}
1089
1090static void LJ_FASTCALL recff_table_clear(jit_State *J, RecordFFData *rd)
1091{
1092 TRef tr = J->base[0];
1093 if (tref_istab(tr)) {
1094 rd->nres = 0;
1095 lj_ir_call(J, IRCALL_lj_tab_clear, tr);
1096 J->needsnap = 1;
1097 } /* else: Interpreter will throw. */
1098}
1099
800/* -- I/O library fast functions ------------------------------------------ */ 1100/* -- I/O library fast functions ------------------------------------------ */
801 1101
802/* Get FILE* for I/O function. Any I/O error aborts recording, so there's 1102/* Get FILE* for I/O function. Any I/O error aborts recording, so there's
@@ -832,7 +1132,10 @@ static void LJ_FASTCALL recff_io_write(jit_State *J, RecordFFData *rd)
832 TRef buf = emitir(IRT(IR_STRREF, IRT_P32), str, zero); 1132 TRef buf = emitir(IRT(IR_STRREF, IRT_P32), str, zero);
833 TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN); 1133 TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN);
834 if (tref_isk(len) && IR(tref_ref(len))->i == 1) { 1134 if (tref_isk(len) && IR(tref_ref(len))->i == 1) {
835 TRef tr = emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY); 1135 IRIns *irs = IR(tref_ref(str));
1136 TRef tr = (irs->o == IR_TOSTR && irs->op2 == IRTOSTR_CHAR) ?
1137 irs->op1 :
1138 emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY);
836 tr = lj_ir_call(J, IRCALL_fputc, tr, fp); 1139 tr = lj_ir_call(J, IRCALL_fputc, tr, fp);
837 if (results_wanted(J) != 0) /* Check result only if not ignored. */ 1140 if (results_wanted(J) != 0) /* Check result only if not ignored. */
838 emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1)); 1141 emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1));