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.c345
1 files changed, 335 insertions, 10 deletions
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c
index 26af7d84..770b1586 100644
--- a/src/lj_ffrecord.c
+++ b/src/lj_ffrecord.c
@@ -11,6 +11,7 @@
11#if LJ_HASJIT 11#if LJ_HASJIT
12 12
13#include "lj_err.h" 13#include "lj_err.h"
14#include "lj_buf.h"
14#include "lj_str.h" 15#include "lj_str.h"
15#include "lj_tab.h" 16#include "lj_tab.h"
16#include "lj_frame.h" 17#include "lj_frame.h"
@@ -28,6 +29,7 @@
28#include "lj_vm.h" 29#include "lj_vm.h"
29#include "lj_strscan.h" 30#include "lj_strscan.h"
30#include "lj_strfmt.h" 31#include "lj_strfmt.h"
32#include "lj_serialize.h"
31 33
32/* Some local macros to save typing. Undef'd at the end. */ 34/* Some local macros to save typing. Undef'd at the end. */
33#define IR(ref) (&J->cur.ir[(ref)]) 35#define IR(ref) (&J->cur.ir[(ref)])
@@ -941,20 +943,18 @@ static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd)
941 } 943 }
942} 944}
943 945
944static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) 946static void recff_format(jit_State *J, RecordFFData *rd, TRef hdr, int sbufx)
945{ 947{
946 TRef trfmt = lj_ir_tostr(J, J->base[0]); 948 ptrdiff_t arg = sbufx;
947 GCstr *fmt = argv2str(J, &rd->argv[0]); 949 TRef tr = hdr, trfmt = lj_ir_tostr(J, J->base[arg]);
948 int arg = 1; 950 GCstr *fmt = argv2str(J, &rd->argv[arg]);
949 TRef hdr, tr;
950 FormatState fs; 951 FormatState fs;
951 SFormat sf; 952 SFormat sf;
952 /* Specialize to the format string. */ 953 /* Specialize to the format string. */
953 emitir(IRTG(IR_EQ, IRT_STR), trfmt, lj_ir_kstr(J, fmt)); 954 emitir(IRTG(IR_EQ, IRT_STR), trfmt, lj_ir_kstr(J, fmt));
954 tr = hdr = recff_bufhdr(J);
955 lj_strfmt_init(&fs, strdata(fmt), fmt->len); 955 lj_strfmt_init(&fs, strdata(fmt), fmt->len);
956 while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { /* Parse format. */ 956 while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { /* Parse format. */
957 TRef tra = sf == STRFMT_LIT ? 0 : J->base[arg++]; 957 TRef tra = sf == STRFMT_LIT ? 0 : J->base[++arg];
958 TRef trsf = lj_ir_kint(J, (int32_t)sf); 958 TRef trsf = lj_ir_kint(J, (int32_t)sf);
959 IRCallID id; 959 IRCallID id;
960 switch (STRFMT_TYPE(sf)) { 960 switch (STRFMT_TYPE(sf)) {
@@ -968,9 +968,8 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
968 if (!tref_isinteger(tra)) { 968 if (!tref_isinteger(tra)) {
969#if LJ_HASFFI 969#if LJ_HASFFI
970 if (tref_iscdata(tra)) { 970 if (tref_iscdata(tra)) {
971 tra = lj_crecord_loadiu64(J, tra, &rd->argv[arg-1]); 971 tra = lj_crecord_loadiu64(J, tra, &rd->argv[arg]);
972 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra); 972 tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra);
973 lj_needsplit(J);
974 break; 973 break;
975 } 974 }
976#endif 975#endif
@@ -1004,6 +1003,7 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
1004 case STRFMT_STR: 1003 case STRFMT_STR:
1005 if (!tref_isstr(tra)) { 1004 if (!tref_isstr(tra)) {
1006 recff_nyiu(J, rd); /* NYI: __tostring and non-string types for %s. */ 1005 recff_nyiu(J, rd); /* NYI: __tostring and non-string types for %s. */
1006 /* NYI: also buffers. */
1007 return; 1007 return;
1008 } 1008 }
1009 if (sf == STRFMT_STR) /* Shortcut for plain %s. */ 1009 if (sf == STRFMT_STR) /* Shortcut for plain %s. */
@@ -1028,9 +1028,334 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
1028 return; 1028 return;
1029 } 1029 }
1030 } 1030 }
1031 J->base[0] = emitir(IRTG(IR_BUFSTR, IRT_STR), tr, hdr); 1031 if (sbufx) {
1032 emitir(IRT(IR_USE, IRT_NIL), tr, 0);
1033 } else {
1034 J->base[0] = emitir(IRTG(IR_BUFSTR, IRT_STR), tr, hdr);
1035 }
1036}
1037
1038static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd)
1039{
1040 recff_format(J, rd, recff_bufhdr(J), 0);
1041}
1042
1043/* -- Buffer library fast functions --------------------------------------- */
1044
1045#if LJ_HASBUFFER
1046
1047static LJ_AINLINE TRef recff_sbufx_get_L(jit_State *J, TRef ud)
1048{
1049 return emitir(IRT(IR_FLOAD, IRT_PGC), ud, IRFL_SBUF_L);
1050}
1051
1052static LJ_AINLINE void recff_sbufx_set_L(jit_State *J, TRef ud, TRef val)
1053{
1054 TRef fref = emitir(IRT(IR_FREF, IRT_PGC), ud, IRFL_SBUF_L);
1055 emitir(IRT(IR_FSTORE, IRT_PGC), fref, val);
1056}
1057
1058static LJ_AINLINE TRef recff_sbufx_get_ptr(jit_State *J, TRef ud, IRFieldID fl)
1059{
1060 return emitir(IRT(IR_FLOAD, IRT_PTR), ud, fl);
1061}
1062
1063static LJ_AINLINE void recff_sbufx_set_ptr(jit_State *J, TRef ud, IRFieldID fl, TRef val)
1064{
1065 TRef fref = emitir(IRT(IR_FREF, IRT_PTR), ud, fl);
1066 emitir(IRT(IR_FSTORE, IRT_PTR), fref, val);
1067}
1068
1069static LJ_AINLINE TRef recff_sbufx_len(jit_State *J, TRef trr, TRef trw)
1070{
1071 TRef len = emitir(IRT(IR_SUB, IRT_INTP), trw, trr);
1072 if (LJ_64)
1073 len = emitir(IRTI(IR_CONV), len, (IRT_INT<<5)|IRT_INTP|IRCONV_NONE);
1074 return len;
1075}
1076
1077/* Emit typecheck for string buffer. */
1078static TRef recff_sbufx_check(jit_State *J, RecordFFData *rd, int arg)
1079{
1080 TRef trtype, ud = J->base[arg];
1081 if (!tvisbuf(&rd->argv[arg])) lj_trace_err(J, LJ_TRERR_BADTYPE);
1082 trtype = emitir(IRT(IR_FLOAD, IRT_U8), ud, IRFL_UDATA_UDTYPE);
1083 emitir(IRTGI(IR_EQ), trtype, lj_ir_kint(J, UDTYPE_BUFFER));
1084 return ud;
1085}
1086
1087/* Emit BUFHDR for write to extended string buffer. */
1088static TRef recff_sbufx_write(jit_State *J, TRef ud)
1089{
1090 TRef trbuf = emitir(IRT(IR_ADD, IRT_PGC), ud, lj_ir_kint(J, sizeof(GCudata)));
1091 return emitir(IRT(IR_BUFHDR, IRT_PGC), trbuf, IRBUFHDR_WRITE);
1092}
1093
1094/* Check for integer in range for the buffer API. */
1095static TRef recff_sbufx_checkint(jit_State *J, RecordFFData *rd, int arg)
1096{
1097 TRef tr = J->base[arg];
1098 TRef trlim = lj_ir_kint(J, LJ_MAX_BUF);
1099 if (tref_isinteger(tr)) {
1100 emitir(IRTGI(IR_ULE), tr, trlim);
1101 } else if (tref_isnum(tr)) {
1102 tr = emitir(IRTI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_ANY);
1103 emitir(IRTGI(IR_ULE), tr, trlim);
1104#if LJ_HASFFI
1105 } else if (tref_iscdata(tr)) {
1106 tr = lj_crecord_loadiu64(J, tr, &rd->argv[arg]);
1107 emitir(IRTG(IR_ULE, IRT_U64), tr, lj_ir_kint64(J, LJ_MAX_BUF));
1108 tr = emitir(IRTI(IR_CONV), tr, (IRT_INT<<5)|IRT_I64|IRCONV_NONE);
1109#else
1110 UNUSED(rd);
1111#endif
1112 } else {
1113 lj_trace_err(J, LJ_TRERR_BADTYPE);
1114 }
1115 return tr;
1116}
1117
1118static void LJ_FASTCALL recff_buffer_method_reset(jit_State *J, RecordFFData *rd)
1119{
1120 TRef ud = recff_sbufx_check(J, rd, 0);
1121 SBufExt *sbx = bufV(&rd->argv[0]);
1122 int iscow = (int)sbufiscow(sbx);
1123 TRef trl = recff_sbufx_get_L(J, ud);
1124 TRef trcow = emitir(IRT(IR_BAND, IRT_IGC), trl, lj_ir_kint(J, SBUF_FLAG_COW));
1125 TRef zero = lj_ir_kint(J, 0);
1126 emitir(IRTG(iscow ? IR_NE : IR_EQ, IRT_IGC), trcow, zero);
1127 if (iscow) {
1128 trl = emitir(IRT(IR_BXOR, IRT_IGC), trl,
1129 LJ_GC64 ? lj_ir_kint64(J, SBUF_FLAG_COW) :
1130 lj_ir_kint(J, SBUF_FLAG_COW));
1131 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, zero);
1132 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_E, zero);
1133 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_B, zero);
1134 recff_sbufx_set_L(J, ud, trl);
1135 emitir(IRT(IR_FSTORE, IRT_PGC),
1136 emitir(IRT(IR_FREF, IRT_PGC), ud, IRFL_SBUF_REF), zero);
1137 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, zero);
1138 } else {
1139 TRef trb = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_B);
1140 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, trb);
1141 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, trb);
1142 }
1143}
1144
1145static void LJ_FASTCALL recff_buffer_method_skip(jit_State *J, RecordFFData *rd)
1146{
1147 TRef ud = recff_sbufx_check(J, rd, 0);
1148 TRef trr = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_R);
1149 TRef trw = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_W);
1150 TRef len = recff_sbufx_len(J, trr, trw);
1151 TRef trn = recff_sbufx_checkint(J, rd, 1);
1152 len = emitir(IRTI(IR_MIN), len, trn);
1153 trr = emitir(IRT(IR_ADD, IRT_PTR), trr, len);
1154 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, trr);
1155}
1156
1157static void LJ_FASTCALL recff_buffer_method_set(jit_State *J, RecordFFData *rd)
1158{
1159 TRef ud = recff_sbufx_check(J, rd, 0);
1160 TRef trbuf = recff_sbufx_write(J, ud);
1161 TRef tr = J->base[1];
1162 if (tref_isstr(tr)) {
1163 TRef trp = emitir(IRT(IR_STRREF, IRT_PGC), tr, lj_ir_kint(J, 0));
1164 TRef len = emitir(IRTI(IR_FLOAD), tr, IRFL_STR_LEN);
1165 lj_ir_call(J, IRCALL_lj_bufx_set, trbuf, trp, len, tr);
1166#if LJ_HASFFI
1167 } else if (tref_iscdata(tr)) {
1168 TRef trp = lj_crecord_topcvoid(J, tr, &rd->argv[1]);
1169 TRef len = recff_sbufx_checkint(J, rd, 2);
1170 lj_ir_call(J, IRCALL_lj_bufx_set, trbuf, trp, len, tr);
1171#endif
1172 } /* else: Interpreter will throw. */
1173}
1174
1175static void LJ_FASTCALL recff_buffer_method_put(jit_State *J, RecordFFData *rd)
1176{
1177 TRef ud = recff_sbufx_check(J, rd, 0);
1178 TRef trbuf = recff_sbufx_write(J, ud);
1179 TRef tr;
1180 ptrdiff_t arg;
1181 if (!J->base[1]) return;
1182 for (arg = 1; (tr = J->base[arg]); arg++) {
1183 if (tref_isstr(tr)) {
1184 trbuf = emitir(IRTG(IR_BUFPUT, IRT_PGC), trbuf, tr);
1185 } else if (tref_isnumber(tr)) {
1186 trbuf = emitir(IRTG(IR_BUFPUT, IRT_PGC), trbuf,
1187 emitir(IRT(IR_TOSTR, IRT_STR), tr,
1188 tref_isnum(tr) ? IRTOSTR_NUM : IRTOSTR_INT));
1189 } else if (tref_isudata(tr)) {
1190 TRef ud2 = recff_sbufx_check(J, rd, arg);
1191 TRef trr = recff_sbufx_get_ptr(J, ud2, IRFL_SBUF_R);
1192 TRef trw = recff_sbufx_get_ptr(J, ud2, IRFL_SBUF_W);
1193 TRef len = recff_sbufx_len(J, trr, trw);
1194 emitir(IRTG(IR_NE, IRT_PGC), ud, ud2);
1195 trbuf = lj_ir_call(J, IRCALL_lj_buf_putmem, trbuf, trr, len);
1196 } else {
1197 recff_nyiu(J, rd);
1198 }
1199 }
1200 emitir(IRT(IR_USE, IRT_NIL), trbuf, 0);
1201}
1202
1203static void LJ_FASTCALL recff_buffer_method_putf(jit_State *J, RecordFFData *rd)
1204{
1205 TRef ud = recff_sbufx_check(J, rd, 0);
1206 TRef trbuf = recff_sbufx_write(J, ud);
1207 recff_format(J, rd, trbuf, 1);
1032} 1208}
1033 1209
1210static void LJ_FASTCALL recff_buffer_method_get(jit_State *J, RecordFFData *rd)
1211{
1212 TRef ud = recff_sbufx_check(J, rd, 0);
1213 TRef trr = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_R);
1214 TRef trw = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_W);
1215 TRef tr;
1216 ptrdiff_t arg;
1217 if (!J->base[1]) { J->base[1] = TREF_NIL; J->base[2] = 0; }
1218 for (arg = 0; (tr = J->base[arg+1]); arg++) {
1219 TRef len = recff_sbufx_len(J, trr, trw);
1220 if (tref_isnil(tr)) {
1221 J->base[arg] = emitir(IRT(IR_XSNEW, IRT_STR), trr, len);
1222 trr = trw;
1223 } else {
1224 TRef trn = recff_sbufx_checkint(J, rd, arg+1);
1225 TRef tru;
1226 len = emitir(IRTI(IR_MIN), len, trn);
1227 tru = emitir(IRT(IR_ADD, IRT_PTR), trr, len);
1228 J->base[arg] = emitir(IRT(IR_XSNEW, IRT_STR), trr, len);
1229 trr = tru; /* Doing the ADD before the SNEW generates better code. */
1230 }
1231 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, trr);
1232 }
1233 rd->nres = arg;
1234}
1235
1236static void LJ_FASTCALL recff_buffer_method___tostring(jit_State *J, RecordFFData *rd)
1237{
1238 TRef ud = recff_sbufx_check(J, rd, 0);
1239 TRef trr = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_R);
1240 TRef trw = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_W);
1241 J->base[0] = emitir(IRT(IR_XSNEW, IRT_STR), trr, recff_sbufx_len(J, trr, trw));
1242}
1243
1244static void LJ_FASTCALL recff_buffer_method___len(jit_State *J, RecordFFData *rd)
1245{
1246 TRef ud = recff_sbufx_check(J, rd, 0);
1247 TRef trr = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_R);
1248 TRef trw = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_W);
1249 J->base[0] = recff_sbufx_len(J, trr, trw);
1250}
1251
1252#if LJ_HASFFI
1253static void LJ_FASTCALL recff_buffer_method_putcdata(jit_State *J, RecordFFData *rd)
1254{
1255 TRef ud = recff_sbufx_check(J, rd, 0);
1256 TRef trbuf = recff_sbufx_write(J, ud);
1257 TRef tr = lj_crecord_topcvoid(J, J->base[1], &rd->argv[1]);
1258 TRef len = recff_sbufx_checkint(J, rd, 2);
1259 trbuf = lj_ir_call(J, IRCALL_lj_buf_putmem, trbuf, tr, len);
1260 emitir(IRT(IR_USE, IRT_NIL), trbuf, 0);
1261}
1262
1263static void LJ_FASTCALL recff_buffer_method_reserve(jit_State *J, RecordFFData *rd)
1264{
1265 TRef ud = recff_sbufx_check(J, rd, 0);
1266 TRef trbuf = recff_sbufx_write(J, ud);
1267 TRef trsz = recff_sbufx_checkint(J, rd, 1);
1268 J->base[1] = lj_ir_call(J, IRCALL_lj_bufx_more, trbuf, trsz);
1269 J->base[0] = lj_crecord_topuint8(J, recff_sbufx_get_ptr(J, ud, IRFL_SBUF_W));
1270 rd->nres = 2;
1271}
1272
1273static void LJ_FASTCALL recff_buffer_method_commit(jit_State *J, RecordFFData *rd)
1274{
1275 TRef ud = recff_sbufx_check(J, rd, 0);
1276 TRef len = recff_sbufx_checkint(J, rd, 1);
1277 TRef trw = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_W);
1278 TRef tre = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_E);
1279 TRef left = emitir(IRT(IR_SUB, IRT_INTP), tre, trw);
1280 if (LJ_64)
1281 left = emitir(IRTI(IR_CONV), left, (IRT_INT<<5)|IRT_INTP|IRCONV_NONE);
1282 emitir(IRTGI(IR_ULE), len, left);
1283 trw = emitir(IRT(IR_ADD, IRT_PTR), trw, len);
1284 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, trw);
1285}
1286
1287static void LJ_FASTCALL recff_buffer_method_ref(jit_State *J, RecordFFData *rd)
1288{
1289 TRef ud = recff_sbufx_check(J, rd, 0);
1290 TRef trr = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_R);
1291 TRef trw = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_W);
1292 J->base[0] = lj_crecord_topuint8(J, trr);
1293 J->base[1] = recff_sbufx_len(J, trr, trw);
1294 rd->nres = 2;
1295}
1296#endif
1297
1298static void LJ_FASTCALL recff_buffer_method_encode(jit_State *J, RecordFFData *rd)
1299{
1300 TRef ud = recff_sbufx_check(J, rd, 0);
1301 TRef trbuf = recff_sbufx_write(J, ud);
1302 TRef tmp, tr = J->base[1];
1303 if (!LJ_DUALNUM && tref_isinteger(tr))
1304 tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT);
1305 tmp = emitir(IRT(IR_TMPREF, IRT_PGC), tr, IRTMPREF_IN1);
1306 lj_ir_call(J, IRCALL_lj_serialize_put, trbuf, tmp);
1307 /* No IR_USE needed, since the call is a store. */
1308}
1309
1310static void LJ_FASTCALL recff_buffer_method_decode(jit_State *J, RecordFFData *rd)
1311{
1312 TRef ud = recff_sbufx_check(J, rd, 0);
1313 TRef trbuf = recff_sbufx_write(J, ud);
1314 TRef trr, tmp;
1315 IRType t;
1316 tmp = emitir(IRT(IR_TMPREF, IRT_PGC), REF_NIL, IRTMPREF_OUT1);
1317 trr = lj_ir_call(J, IRCALL_lj_serialize_get, trbuf, tmp);
1318 /* No IR_USE needed, since the call is a store. */
1319 t = (IRType)lj_serialize_peektype(bufV(&rd->argv[0]));
1320 J->base[0] = lj_record_vload(J, tmp, t);
1321 /* The sbx->r store must be after the VLOAD type check, in case it fails. */
1322 recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, trr);
1323}
1324
1325static void LJ_FASTCALL recff_buffer_encode(jit_State *J, RecordFFData *rd)
1326{
1327 TRef tmp, tr = J->base[0];
1328 if (!LJ_DUALNUM && tref_isinteger(tr))
1329 tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT);
1330 tmp = emitir(IRT(IR_TMPREF, IRT_PGC), tr, IRTMPREF_IN1);
1331 J->base[0] = lj_ir_call(J, IRCALL_lj_serialize_encode, tmp);
1332 /* IR_USE needed for IR_CALLA, because the encoder may throw non-OOM. */
1333 emitir(IRT(IR_USE, IRT_NIL), J->base[0], 0);
1334 UNUSED(rd);
1335}
1336
1337static void LJ_FASTCALL recff_buffer_decode(jit_State *J, RecordFFData *rd)
1338{
1339 if (tvisstr(&rd->argv[0])) {
1340 GCstr *str = strV(&rd->argv[0]);
1341 SBufExt sbx;
1342 TRef tr, tmp;
1343 IRType t;
1344 tmp = emitir(IRT(IR_TMPREF, IRT_PGC), REF_NIL, IRTMPREF_OUT1);
1345 tr = lj_ir_call(J, IRCALL_lj_serialize_decode, tmp, J->base[0]);
1346 /* IR_USE needed for IR_CALLA, because the decoder may throw non-OOM.
1347 ** That's why IRCALL_lj_serialize_decode needs a fake INT result.
1348 */
1349 emitir(IRT(IR_USE, IRT_NIL), tr, 0);
1350 memset(&sbx, 0, sizeof(SBufExt));
1351 lj_bufx_set_cow(J->L, &sbx, strdata(str), str->len);
1352 t = (IRType)lj_serialize_peektype(&sbx);
1353 J->base[0] = lj_record_vload(J, tmp, t);
1354 } /* else: Interpreter will throw. */
1355}
1356
1357#endif
1358
1034/* -- Table library fast functions ---------------------------------------- */ 1359/* -- Table library fast functions ---------------------------------------- */
1035 1360
1036static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) 1361static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd)