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.c389
1 files changed, 298 insertions, 91 deletions
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c
index 35e2e88e..fcc46319 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 }
@@ -121,6 +119,13 @@ static void LJ_FASTCALL recff_c(jit_State *J, RecordFFData *rd)
121 UNUSED(rd); 119 UNUSED(rd);
122} 120}
123 121
122/* Emit BUFHDR for the global temporary buffer. */
123static TRef recff_bufhdr(jit_State *J)
124{
125 return emitir(IRT(IR_BUFHDR, IRT_P32),
126 lj_ir_kptr(J, &J2G(J)->tmpbuf), IRBUFHDR_RESET);
127}
128
124/* -- Base library fast functions ----------------------------------------- */ 129/* -- Base library fast functions ----------------------------------------- */
125 130
126static void LJ_FASTCALL recff_assert(jit_State *J, RecordFFData *rd) 131static void LJ_FASTCALL recff_assert(jit_State *J, RecordFFData *rd)
@@ -336,11 +341,12 @@ static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd)
336 if (tref_isstr(tr)) { 341 if (tref_isstr(tr)) {
337 /* Ignore __tostring in the string base metatable. */ 342 /* Ignore __tostring in the string base metatable. */
338 /* Pass on result in J->base[0]. */ 343 /* Pass on result in J->base[0]. */
339 } else if (!recff_metacall(J, rd, MM_tostring)) { 344 } else if (tr && !recff_metacall(J, rd, MM_tostring)) {
340 if (tref_isnumber(tr)) { 345 if (tref_isnumber(tr)) {
341 J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0); 346 J->base[0] = emitir(IRT(IR_TOSTR, IRT_STR), tr,
347 tref_isnum(tr) ? IRTOSTR_NUM : IRTOSTR_INT);
342 } else if (tref_ispri(tr)) { 348 } else if (tref_ispri(tr)) {
343 J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[tref_type(tr)])); 349 J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0]));
344 } else { 350 } else {
345 recff_nyiu(J); 351 recff_nyiu(J);
346 } 352 }
@@ -528,14 +534,6 @@ static void LJ_FASTCALL recff_math_modf(jit_State *J, RecordFFData *rd)
528 rd->nres = 2; 534 rd->nres = 2;
529} 535}
530 536
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) 537static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd)
540{ 538{
541 TRef tr = lj_ir_tonum(J, J->base[0]); 539 TRef tr = lj_ir_tonum(J, J->base[0]);
@@ -592,48 +590,105 @@ static void LJ_FASTCALL recff_math_random(jit_State *J, RecordFFData *rd)
592 590
593/* -- Bit library fast functions ------------------------------------------ */ 591/* -- Bit library fast functions ------------------------------------------ */
594 592
595/* Record unary bit.tobit, bit.bnot, bit.bswap. */ 593/* Record bit.tobit. */
594static void LJ_FASTCALL recff_bit_tobit(jit_State *J, RecordFFData *rd)
595{
596 TRef tr = J->base[0];
597#if LJ_HASFFI
598 if (tref_iscdata(tr)) { recff_bit64_tobit(J, rd); return; }
599#endif
600 J->base[0] = lj_opt_narrow_tobit(J, tr);
601 UNUSED(rd);
602}
603
604/* Record unary bit.bnot, bit.bswap. */
596static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd) 605static void LJ_FASTCALL recff_bit_unary(jit_State *J, RecordFFData *rd)
597{ 606{
598 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 607#if LJ_HASFFI
599 J->base[0] = (rd->data == IR_TOBIT) ? tr : emitir(IRTI(rd->data), tr, 0); 608 if (recff_bit64_unary(J, rd))
609 return;
610#endif
611 J->base[0] = emitir(IRTI(rd->data), lj_opt_narrow_tobit(J, J->base[0]), 0);
600} 612}
601 613
602/* Record N-ary bit.band, bit.bor, bit.bxor. */ 614/* Record N-ary bit.band, bit.bor, bit.bxor. */
603static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd) 615static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd)
604{ 616{
605 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 617#if LJ_HASFFI
606 uint32_t op = rd->data; 618 if (recff_bit64_nary(J, rd))
607 BCReg i; 619 return;
608 for (i = 1; J->base[i] != 0; i++) 620#endif
609 tr = emitir(IRTI(op), tr, lj_opt_narrow_tobit(J, J->base[i])); 621 {
610 J->base[0] = tr; 622 TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
623 uint32_t ot = IRTI(rd->data);
624 BCReg i;
625 for (i = 1; J->base[i] != 0; i++)
626 tr = emitir(ot, tr, lj_opt_narrow_tobit(J, J->base[i]));
627 J->base[0] = tr;
628 }
611} 629}
612 630
613/* Record bit shifts. */ 631/* Record bit shifts. */
614static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) 632static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd)
615{ 633{
616 TRef tr = lj_opt_narrow_tobit(J, J->base[0]); 634#if LJ_HASFFI
617 TRef tsh = lj_opt_narrow_tobit(J, J->base[1]); 635 if (recff_bit64_shift(J, rd))
618 IROp op = (IROp)rd->data; 636 return;
619 if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && 637#endif
620 !tref_isk(tsh)) 638 {
621 tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31)); 639 TRef tr = lj_opt_narrow_tobit(J, J->base[0]);
640 TRef tsh = lj_opt_narrow_tobit(J, J->base[1]);
641 IROp op = (IROp)rd->data;
642 if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) &&
643 !tref_isk(tsh))
644 tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 31));
622#ifdef LJ_TARGET_UNIFYROT 645#ifdef LJ_TARGET_UNIFYROT
623 if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) { 646 if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) {
624 op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR; 647 op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR;
625 tsh = emitir(IRTI(IR_NEG), tsh, tsh); 648 tsh = emitir(IRTI(IR_NEG), tsh, tsh);
649 }
650#endif
651 J->base[0] = emitir(IRTI(op), tr, tsh);
626 } 652 }
653}
654
655static void LJ_FASTCALL recff_bit_tohex(jit_State *J, RecordFFData *rd)
656{
657#if LJ_HASFFI
658 TRef hdr = recff_bufhdr(J);
659 TRef tr = recff_bit64_tohex(J, rd, hdr);
660 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
661#else
662 recff_nyiu(J); /* Don't bother working around this NYI. */
627#endif 663#endif
628 J->base[0] = emitir(IRTI(op), tr, tsh);
629} 664}
630 665
631/* -- String library fast functions --------------------------------------- */ 666/* -- String library fast functions --------------------------------------- */
632 667
633static void LJ_FASTCALL recff_string_len(jit_State *J, RecordFFData *rd) 668/* Specialize to relative starting position for string. */
669static TRef recff_string_start(jit_State *J, GCstr *s, int32_t *st, TRef tr,
670 TRef trlen, TRef tr0)
634{ 671{
635 J->base[0] = emitir(IRTI(IR_FLOAD), lj_ir_tostr(J, J->base[0]), IRFL_STR_LEN); 672 int32_t start = *st;
636 UNUSED(rd); 673 if (start < 0) {
674 emitir(IRTGI(IR_LT), tr, tr0);
675 tr = emitir(IRTI(IR_ADD), trlen, tr);
676 start = start + (int32_t)s->len;
677 emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), tr, tr0);
678 if (start < 0) {
679 tr = tr0;
680 start = 0;
681 }
682 } else if (start == 0) {
683 emitir(IRTGI(IR_EQ), tr, tr0);
684 tr = tr0;
685 } else {
686 tr = emitir(IRTI(IR_ADD), tr, lj_ir_kint(J, -1));
687 emitir(IRTGI(IR_GE), tr, tr0);
688 start--;
689 }
690 *st = start;
691 return tr;
637} 692}
638 693
639/* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */ 694/* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */
@@ -681,29 +736,11 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
681 } else if ((MSize)end <= str->len) { 736 } else if ((MSize)end <= str->len) {
682 emitir(IRTGI(IR_ULE), trend, trlen); 737 emitir(IRTGI(IR_ULE), trend, trlen);
683 } else { 738 } else {
684 emitir(IRTGI(IR_GT), trend, trlen); 739 emitir(IRTGI(IR_UGT), trend, trlen);
685 end = (int32_t)str->len; 740 end = (int32_t)str->len;
686 trend = trlen; 741 trend = trlen;
687 } 742 }
688 if (start < 0) { 743 trstart = recff_string_start(J, str, &start, trstart, trlen, tr0);
689 emitir(IRTGI(IR_LT), trstart, tr0);
690 trstart = emitir(IRTI(IR_ADD), trlen, trstart);
691 start = start+(int32_t)str->len;
692 emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), trstart, tr0);
693 if (start < 0) {
694 trstart = tr0;
695 start = 0;
696 }
697 } else {
698 if (start == 0) {
699 emitir(IRTGI(IR_EQ), trstart, tr0);
700 trstart = tr0;
701 } else {
702 trstart = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, -1));
703 emitir(IRTGI(IR_GE), trstart, tr0);
704 start--;
705 }
706 }
707 if (rd->data) { /* Return string.sub result. */ 744 if (rd->data) { /* Return string.sub result. */
708 if (end - start >= 0) { 745 if (end - start >= 0) {
709 /* Also handle empty range here, to avoid extra traces. */ 746 /* Also handle empty range here, to avoid extra traces. */
@@ -713,7 +750,7 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
713 J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen); 750 J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen);
714 } else { /* Range underflow: return empty string. */ 751 } else { /* Range underflow: return empty string. */
715 emitir(IRTGI(IR_LT), trend, trstart); 752 emitir(IRTGI(IR_LT), trend, trstart);
716 J->base[0] = lj_ir_kstr(J, lj_str_new(J->L, strdata(str), 0)); 753 J->base[0] = lj_ir_kstr(J, &J2G(J)->strempty);
717 } 754 }
718 } else { /* Return string.byte result(s). */ 755 } else { /* Return string.byte result(s). */
719 ptrdiff_t i, len = end - start; 756 ptrdiff_t i, len = end - start;
@@ -735,48 +772,196 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd)
735 } 772 }
736} 773}
737 774
738/* -- Table library fast functions ---------------------------------------- */ 775static void LJ_FASTCALL recff_string_char(jit_State *J, RecordFFData *rd)
739
740static void LJ_FASTCALL recff_table_getn(jit_State *J, RecordFFData *rd)
741{ 776{
742 if (tref_istab(J->base[0])) 777 TRef k255 = lj_ir_kint(J, 255);
743 J->base[0] = lj_ir_call(J, IRCALL_lj_tab_len, J->base[0]); 778 BCReg i;
744 /* else: Interpreter will throw. */ 779 for (i = 0; J->base[i] != 0; i++) { /* Convert char values to strings. */
780 TRef tr = lj_opt_narrow_toint(J, J->base[i]);
781 emitir(IRTGI(IR_ULE), tr, k255);
782 J->base[i] = emitir(IRT(IR_TOSTR, IRT_STR), tr, IRTOSTR_CHAR);
783 }
784 if (i > 1) { /* Concatenate the strings, if there's more than one. */
785 TRef hdr = recff_bufhdr(J), tr = hdr;
786 for (i = 0; J->base[i] != 0; i++)
787 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, J->base[i]);
788 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
789 }
745 UNUSED(rd); 790 UNUSED(rd);
746} 791}
747 792
748static void LJ_FASTCALL recff_table_remove(jit_State *J, RecordFFData *rd) 793static void LJ_FASTCALL recff_string_rep(jit_State *J, RecordFFData *rd)
749{ 794{
750 TRef tab = J->base[0]; 795 TRef str = lj_ir_tostr(J, J->base[0]);
751 rd->nres = 0; 796 TRef rep = lj_opt_narrow_toint(J, J->base[1]);
752 if (tref_istab(tab)) { 797 TRef hdr, tr, str2 = 0;
753 if (tref_isnil(J->base[1])) { /* Simple pop: t[#t] = nil */ 798 if (!tref_isnil(J->base[2])) {
754 TRef trlen = lj_ir_call(J, IRCALL_lj_tab_len, tab); 799 TRef sep = lj_ir_tostr(J, J->base[2]);
755 GCtab *t = tabV(&rd->argv[0]); 800 int32_t vrep = argv2int(J, &rd->argv[1]);
756 MSize len = lj_tab_len(t); 801 emitir(IRTGI(vrep > 1 ? IR_GT : IR_LE), rep, lj_ir_kint(J, 1));
757 emitir(IRTGI(len ? IR_NE : IR_EQ), trlen, lj_ir_kint(J, 0)); 802 if (vrep > 1) {
758 if (len) { 803 TRef hdr2 = recff_bufhdr(J);
759 RecordIndex ix; 804 TRef tr2 = emitir(IRT(IR_BUFPUT, IRT_P32), hdr2, sep);
760 ix.tab = tab; 805 tr2 = emitir(IRT(IR_BUFPUT, IRT_P32), tr2, str);
761 ix.key = trlen; 806 str2 = emitir(IRT(IR_BUFSTR, IRT_STR), tr2, hdr2);
762 settabV(J->L, &ix.tabv, t); 807 }
763 setintV(&ix.keyv, len); 808 }
764 ix.idxchain = 0; 809 tr = hdr = recff_bufhdr(J);
765 if (results_wanted(J) != 0) { /* Specialize load only if needed. */ 810 if (str2) {
766 ix.val = 0; 811 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, str);
767 J->base[0] = lj_record_idx(J, &ix); /* Load previous value. */ 812 str = str2;
768 rd->nres = 1; 813 rep = emitir(IRTI(IR_ADD), rep, lj_ir_kint(J, -1));
769 /* Assumes ix.key/ix.tab is not modified for raw lj_record_idx(). */ 814 }
770 } 815 tr = lj_ir_call(J, IRCALL_lj_buf_putstr_rep, tr, str, rep);
771 ix.val = TREF_NIL; 816 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
772 lj_record_idx(J, &ix); /* Remove value. */ 817}
818
819static void LJ_FASTCALL recff_string_op(jit_State *J, RecordFFData *rd)
820{
821 TRef str = lj_ir_tostr(J, J->base[0]);
822 TRef hdr = recff_bufhdr(J);
823 TRef tr = lj_ir_call(J, rd->data, hdr, str);
824 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
825}
826
827static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd)
828{
829 TRef trstr = lj_ir_tostr(J, J->base[0]);
830 TRef trpat = lj_ir_tostr(J, J->base[1]);
831 TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN);
832 TRef tr0 = lj_ir_kint(J, 0);
833 TRef trstart;
834 GCstr *str = argv2str(J, &rd->argv[0]);
835 GCstr *pat = argv2str(J, &rd->argv[1]);
836 int32_t start;
837 J->needsnap = 1;
838 if (tref_isnil(J->base[2])) {
839 trstart = lj_ir_kint(J, 1);
840 start = 1;
841 } else {
842 trstart = lj_opt_narrow_toint(J, J->base[2]);
843 start = argv2int(J, &rd->argv[2]);
844 }
845 trstart = recff_string_start(J, str, &start, trstart, trlen, tr0);
846 if ((MSize)start <= str->len) {
847 emitir(IRTGI(IR_ULE), trstart, trlen);
848 } else {
849 emitir(IRTGI(IR_UGT), trstart, trlen);
850#if LJ_52
851 J->base[0] = TREF_NIL;
852 return;
853#else
854 trstart = trlen;
855 start = str->len;
856#endif
857 }
858 /* Fixed arg or no pattern matching chars? (Specialized to pattern string.) */
859 if ((J->base[2] && tref_istruecond(J->base[3])) ||
860 (emitir(IRTG(IR_EQ, IRT_STR), trpat, lj_ir_kstr(J, pat)),
861 !lj_str_haspattern(pat))) { /* Search for fixed string. */
862 TRef trsptr = emitir(IRT(IR_STRREF, IRT_P32), trstr, trstart);
863 TRef trpptr = emitir(IRT(IR_STRREF, IRT_P32), trpat, tr0);
864 TRef trslen = emitir(IRTI(IR_SUB), trlen, trstart);
865 TRef trplen = emitir(IRTI(IR_FLOAD), trpat, IRFL_STR_LEN);
866 TRef tr = lj_ir_call(J, IRCALL_lj_str_find, trsptr, trpptr, trslen, trplen);
867 TRef trp0 = lj_ir_kkptr(J, NULL);
868 if (lj_str_find(strdata(str)+(MSize)start, strdata(pat),
869 str->len-(MSize)start, pat->len)) {
870 TRef pos;
871 emitir(IRTG(IR_NE, IRT_P32), tr, trp0);
872 pos = emitir(IRTI(IR_SUB), tr, emitir(IRT(IR_STRREF, IRT_P32), trstr, tr0));
873 J->base[0] = emitir(IRTI(IR_ADD), pos, lj_ir_kint(J, 1));
874 J->base[1] = emitir(IRTI(IR_ADD), pos, trplen);
875 rd->nres = 2;
876 } else {
877 emitir(IRTG(IR_EQ, IRT_P32), tr, trp0);
878 J->base[0] = TREF_NIL;
879 }
880 } else { /* Search for pattern. */
881 recff_nyiu(J);
882 }
883}
884
885static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
886{
887 TRef trfmt = lj_ir_tostr(J, J->base[0]);
888 GCstr *fmt = argv2str(J, &rd->argv[0]);
889 int arg = 1;
890 TRef hdr, tr;
891 FormatState fs;
892 SFormat sf;
893 /* Specialize to the format string. */
894 emitir(IRTG(IR_EQ, IRT_STR), trfmt, lj_ir_kstr(J, fmt));
895 tr = hdr = recff_bufhdr(J);
896 lj_strfmt_init(&fs, strdata(fmt), fmt->len);
897 while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { /* Parse format. */
898 TRef tra = sf == STRFMT_LIT ? 0 : J->base[arg++];
899 TRef trsf = lj_ir_kint(J, (int32_t)sf);
900 IRCallID id;
901 switch (STRFMT_TYPE(sf)) {
902 case STRFMT_LIT:
903 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr,
904 lj_ir_kstr(J, lj_str_new(J->L, fs.str, fs.len)));
905 break;
906 case STRFMT_INT:
907 id = IRCALL_lj_strfmt_putfnum_int;
908 handle_int:
909 if (!tref_isinteger(tra))
910 goto handle_num;
911 if (sf == STRFMT_INT) { /* Shortcut for plain %d. */
912 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr,
913 emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_INT));
914 } else {
915#if LJ_HASFFI
916 tra = emitir(IRT(IR_CONV, IRT_U64), tra,
917 (IRT_INT|(IRT_U64<<5)|IRCONV_SEXT));
918 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra);
919 lj_needsplit(J);
920#else
921 recff_nyiu(J); /* Don't bother working around this NYI. */
922#endif
773 } 923 }
774 } else { /* Complex case: remove in the middle. */ 924 break;
925 case STRFMT_UINT:
926 id = IRCALL_lj_strfmt_putfnum_uint;
927 goto handle_int;
928 case STRFMT_NUM:
929 id = IRCALL_lj_strfmt_putfnum;
930 handle_num:
931 tra = lj_ir_tonum(J, tra);
932 tr = lj_ir_call(J, id, tr, trsf, tra);
933 if (LJ_SOFTFP) lj_needsplit(J);
934 break;
935 case STRFMT_STR:
936 if (!tref_isstr(tra))
937 recff_nyiu(J); /* NYI: __tostring and non-string types for %s. */
938 if (sf == STRFMT_STR) /* Shortcut for plain %s. */
939 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, tra);
940 else if ((sf & STRFMT_T_QUOTED))
941 tr = lj_ir_call(J, IRCALL_lj_strfmt_putquoted, tr, tra);
942 else
943 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfstr, tr, trsf, tra);
944 break;
945 case STRFMT_CHAR:
946 tra = lj_opt_narrow_toint(J, tra);
947 if (sf == STRFMT_CHAR) /* Shortcut for plain %c. */
948 tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr,
949 emitir(IRT(IR_TOSTR, IRT_STR), tra, IRTOSTR_CHAR));
950 else
951 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfchar, tr, trsf, tra);
952 break;
953 case STRFMT_PTR: /* NYI */
954 case STRFMT_ERR:
955 default:
775 recff_nyiu(J); 956 recff_nyiu(J);
957 break;
776 } 958 }
777 } /* else: Interpreter will throw. */ 959 }
960 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
778} 961}
779 962
963/* -- Table library fast functions ---------------------------------------- */
964
780static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) 965static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
781{ 966{
782 RecordIndex ix; 967 RecordIndex ix;
@@ -798,6 +983,25 @@ static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)
798 } /* else: Interpreter will throw. */ 983 } /* else: Interpreter will throw. */
799} 984}
800 985
986static void LJ_FASTCALL recff_table_concat(jit_State *J, RecordFFData *rd)
987{
988 TRef tab = J->base[0];
989 if (tref_istab(tab)) {
990 TRef sep = !tref_isnil(J->base[1]) ?
991 lj_ir_tostr(J, J->base[1]) : lj_ir_knull(J, IRT_STR);
992 TRef tri = (J->base[1] && !tref_isnil(J->base[2])) ?
993 lj_opt_narrow_toint(J, J->base[2]) : lj_ir_kint(J, 1);
994 TRef tre = (J->base[1] && J->base[2] && !tref_isnil(J->base[3])) ?
995 lj_opt_narrow_toint(J, J->base[3]) :
996 lj_ir_call(J, IRCALL_lj_tab_len, tab);
997 TRef hdr = recff_bufhdr(J);
998 TRef tr = lj_ir_call(J, IRCALL_lj_buf_puttab, hdr, tab, sep, tri, tre);
999 emitir(IRTG(IR_NE, IRT_PTR), tr, lj_ir_kptr(J, NULL));
1000 J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
1001 } /* else: Interpreter will throw. */
1002 UNUSED(rd);
1003}
1004
801/* -- I/O library fast functions ------------------------------------------ */ 1005/* -- I/O library fast functions ------------------------------------------ */
802 1006
803/* Get FILE* for I/O function. Any I/O error aborts recording, so there's 1007/* Get FILE* for I/O function. Any I/O error aborts recording, so there's
@@ -833,7 +1037,10 @@ static void LJ_FASTCALL recff_io_write(jit_State *J, RecordFFData *rd)
833 TRef buf = emitir(IRT(IR_STRREF, IRT_P32), str, zero); 1037 TRef buf = emitir(IRT(IR_STRREF, IRT_P32), str, zero);
834 TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN); 1038 TRef len = emitir(IRTI(IR_FLOAD), str, IRFL_STR_LEN);
835 if (tref_isk(len) && IR(tref_ref(len))->i == 1) { 1039 if (tref_isk(len) && IR(tref_ref(len))->i == 1) {
836 TRef tr = emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY); 1040 IRIns *irs = IR(tref_ref(str));
1041 TRef tr = (irs->o == IR_TOSTR && irs->op2 == IRTOSTR_CHAR) ?
1042 irs->op1 :
1043 emitir(IRT(IR_XLOAD, IRT_U8), buf, IRXLOAD_READONLY);
837 tr = lj_ir_call(J, IRCALL_fputc, tr, fp); 1044 tr = lj_ir_call(J, IRCALL_fputc, tr, fp);
838 if (results_wanted(J) != 0) /* Check result only if not ignored. */ 1045 if (results_wanted(J) != 0) /* Check result only if not ignored. */
839 emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1)); 1046 emitir(IRTGI(IR_NE), tr, lj_ir_kint(J, -1));