aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.dep12
-rw-r--r--src/host/buildvm_lib.c2
-rw-r--r--src/lib_buffer.c52
-rw-r--r--src/lj_buf.c36
-rw-r--r--src/lj_buf.h12
-rw-r--r--src/lj_crecord.c17
-rw-r--r--src/lj_crecord.h4
-rw-r--r--src/lj_err.c36
-rw-r--r--src/lj_ffrecord.c345
-rw-r--r--src/lj_ir.c1
-rw-r--r--src/lj_ir.h9
-rw-r--r--src/lj_ircall.h18
-rw-r--r--src/lj_iropt.h1
-rw-r--r--src/lj_opt_fold.c57
-rw-r--r--src/lj_opt_mem.c28
-rw-r--r--src/lj_record.c10
-rw-r--r--src/lj_serialize.c65
-rw-r--r--src/lj_serialize.h7
18 files changed, 625 insertions, 87 deletions
diff --git a/src/Makefile.dep b/src/Makefile.dep
index dd74c677..1ad6701a 100644
--- a/src/Makefile.dep
+++ b/src/Makefile.dep
@@ -114,10 +114,10 @@ lj_err.o: lj_err.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_err.h \
114 lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \ 114 lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \
115 lj_traceerr.h lj_vm.h lj_strfmt.h 115 lj_traceerr.h lj_vm.h lj_strfmt.h
116lj_ffrecord.o: lj_ffrecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 116lj_ffrecord.o: lj_ffrecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
117 lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ff.h \ 117 lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h lj_frame.h \
118 lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \ 118 lj_bc.h lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
119 lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_crecord.h \ 119 lj_trace.h lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h \
120 lj_vm.h lj_strscan.h lj_strfmt.h lj_recdef.h 120 lj_crecord.h lj_vm.h lj_strscan.h lj_strfmt.h lj_serialize.h lj_recdef.h
121lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 121lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
122 lj_func.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \ 122 lj_func.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
123 lj_traceerr.h lj_vm.h 123 lj_traceerr.h lj_vm.h
@@ -131,7 +131,7 @@ lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
131lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 131lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
132 lj_buf.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \ 132 lj_buf.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
133 lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h \ 133 lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h \
134 lj_carith.h lj_vm.h lj_strscan.h lj_strfmt.h lj_prng.h 134 lj_carith.h lj_vm.h lj_strscan.h lj_serialize.h lj_strfmt.h lj_prng.h
135lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 135lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
136 lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h \ 136 lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h \
137 lualib.h lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h \ 137 lualib.h lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h \
@@ -185,7 +185,7 @@ lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
185 lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h lj_prng.h 185 lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h lj_prng.h
186lj_serialize.o: lj_serialize.c lj_obj.h lua.h luaconf.h lj_def.h \ 186lj_serialize.o: lj_serialize.c lj_obj.h lua.h luaconf.h lj_def.h \
187 lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \ 187 lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \
188 lj_udata.h lj_ctype.h lj_cdata.h lj_serialize.h 188 lj_udata.h lj_ctype.h lj_cdata.h lj_ir.h lj_serialize.h
189lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 189lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
190 lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \ 190 lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
191 lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \ 191 lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
diff --git a/src/host/buildvm_lib.c b/src/host/buildvm_lib.c
index 17e0111c..20bb77cd 100644
--- a/src/host/buildvm_lib.c
+++ b/src/host/buildvm_lib.c
@@ -385,6 +385,8 @@ void emit_lib(BuildCtx *ctx)
385 ok = LJ_HASJIT; 385 ok = LJ_HASJIT;
386 else if (!strcmp(buf, "#if LJ_HASFFI\n")) 386 else if (!strcmp(buf, "#if LJ_HASFFI\n"))
387 ok = LJ_HASFFI; 387 ok = LJ_HASFFI;
388 else if (!strcmp(buf, "#if LJ_HASBUFFER\n"))
389 ok = LJ_HASBUFFER;
388 if (!ok) { 390 if (!ok) {
389 int lvl = 1; 391 int lvl = 1;
390 while (fgets(buf, sizeof(buf), fp) != NULL) { 392 while (fgets(buf, sizeof(buf), fp) != NULL) {
diff --git a/src/lib_buffer.c b/src/lib_buffer.c
index cb7531a2..ae065759 100644
--- a/src/lib_buffer.c
+++ b/src/lib_buffer.c
@@ -61,7 +61,7 @@ LJLIB_CF(buffer_method_free)
61 return 1; 61 return 1;
62} 62}
63 63
64LJLIB_CF(buffer_method_reset) 64LJLIB_CF(buffer_method_reset) LJLIB_REC(.)
65{ 65{
66 SBufExt *sbx = buffer_tobuf(L); 66 SBufExt *sbx = buffer_tobuf(L);
67 lj_bufx_reset(sbx); 67 lj_bufx_reset(sbx);
@@ -69,7 +69,7 @@ LJLIB_CF(buffer_method_reset)
69 return 1; 69 return 1;
70} 70}
71 71
72LJLIB_CF(buffer_method_skip) 72LJLIB_CF(buffer_method_skip) LJLIB_REC(.)
73{ 73{
74 SBufExt *sbx = buffer_tobuf(L); 74 SBufExt *sbx = buffer_tobuf(L);
75 MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF); 75 MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
@@ -83,7 +83,7 @@ LJLIB_CF(buffer_method_skip)
83 return 1; 83 return 1;
84} 84}
85 85
86LJLIB_CF(buffer_method_set) 86LJLIB_CF(buffer_method_set) LJLIB_REC(.)
87{ 87{
88 SBufExt *sbx = buffer_tobuf(L); 88 SBufExt *sbx = buffer_tobuf(L);
89 GCobj *ref; 89 GCobj *ref;
@@ -111,7 +111,7 @@ LJLIB_CF(buffer_method_set)
111 return 1; 111 return 1;
112} 112}
113 113
114LJLIB_CF(buffer_method_put) 114LJLIB_CF(buffer_method_put) LJLIB_REC(.)
115{ 115{
116 SBufExt *sbx = buffer_tobufw(L); 116 SBufExt *sbx = buffer_tobufw(L);
117 ptrdiff_t arg, narg = L->top - L->base; 117 ptrdiff_t arg, narg = L->top - L->base;
@@ -147,7 +147,7 @@ LJLIB_CF(buffer_method_put)
147 return 1; 147 return 1;
148} 148}
149 149
150LJLIB_CF(buffer_method_putf) 150LJLIB_CF(buffer_method_putf) LJLIB_REC(.)
151{ 151{
152 SBufExt *sbx = buffer_tobufw(L); 152 SBufExt *sbx = buffer_tobufw(L);
153 lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2); 153 lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
@@ -156,7 +156,7 @@ LJLIB_CF(buffer_method_putf)
156 return 1; 156 return 1;
157} 157}
158 158
159LJLIB_CF(buffer_method_get) 159LJLIB_CF(buffer_method_get) LJLIB_REC(.)
160{ 160{
161 SBufExt *sbx = buffer_tobuf(L); 161 SBufExt *sbx = buffer_tobuf(L);
162 ptrdiff_t arg, narg = L->top - L->base; 162 ptrdiff_t arg, narg = L->top - L->base;
@@ -179,7 +179,7 @@ LJLIB_CF(buffer_method_get)
179} 179}
180 180
181#if LJ_HASFFI 181#if LJ_HASFFI
182LJLIB_CF(buffer_method_putcdata) 182LJLIB_CF(buffer_method_putcdata) LJLIB_REC(.)
183{ 183{
184 SBufExt *sbx = buffer_tobufw(L); 184 SBufExt *sbx = buffer_tobufw(L);
185 const char *p; 185 const char *p;
@@ -197,12 +197,12 @@ LJLIB_CF(buffer_method_putcdata)
197 return 1; 197 return 1;
198} 198}
199 199
200LJLIB_CF(buffer_method_reserve) 200LJLIB_CF(buffer_method_reserve) LJLIB_REC(.)
201{ 201{
202 SBufExt *sbx = buffer_tobufw(L); 202 SBufExt *sbx = buffer_tobufw(L);
203 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF); 203 MSize sz = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
204 GCcdata *cd; 204 GCcdata *cd;
205 lj_buf_more((SBuf *)sbx, len); 205 lj_buf_more((SBuf *)sbx, sz);
206 ctype_loadffi(L); 206 ctype_loadffi(L);
207 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR); 207 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
208 *(void **)cdataptr(cd) = sbx->w; 208 *(void **)cdataptr(cd) = sbx->w;
@@ -211,7 +211,7 @@ LJLIB_CF(buffer_method_reserve)
211 return 2; 211 return 2;
212} 212}
213 213
214LJLIB_CF(buffer_method_commit) 214LJLIB_CF(buffer_method_commit) LJLIB_REC(.)
215{ 215{
216 SBufExt *sbx = buffer_tobuf(L); 216 SBufExt *sbx = buffer_tobuf(L);
217 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF); 217 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
@@ -221,7 +221,7 @@ LJLIB_CF(buffer_method_commit)
221 return 1; 221 return 1;
222} 222}
223 223
224LJLIB_CF(buffer_method_ref) 224LJLIB_CF(buffer_method_ref) LJLIB_REC(.)
225{ 225{
226 SBufExt *sbx = buffer_tobuf(L); 226 SBufExt *sbx = buffer_tobuf(L);
227 GCcdata *cd; 227 GCcdata *cd;
@@ -234,7 +234,7 @@ LJLIB_CF(buffer_method_ref)
234} 234}
235#endif 235#endif
236 236
237LJLIB_CF(buffer_method_encode) 237LJLIB_CF(buffer_method_encode) LJLIB_REC(.)
238{ 238{
239 SBufExt *sbx = buffer_tobufw(L); 239 SBufExt *sbx = buffer_tobufw(L);
240 cTValue *o = lj_lib_checkany(L, 2); 240 cTValue *o = lj_lib_checkany(L, 2);
@@ -244,11 +244,11 @@ LJLIB_CF(buffer_method_encode)
244 return 1; 244 return 1;
245} 245}
246 246
247LJLIB_CF(buffer_method_decode) 247LJLIB_CF(buffer_method_decode) LJLIB_REC(.)
248{ 248{
249 SBufExt *sbx = buffer_tobufw(L); 249 SBufExt *sbx = buffer_tobufw(L);
250 setnilV(L->top++); 250 setnilV(L->top++);
251 lj_serialize_get(sbx, L->top-1); 251 sbx->r = lj_serialize_get(sbx, L->top-1);
252 lj_gc_check(L); 252 lj_gc_check(L);
253 return 1; 253 return 1;
254} 254}
@@ -260,7 +260,7 @@ LJLIB_CF(buffer_method___gc)
260 return 0; 260 return 0;
261} 261}
262 262
263LJLIB_CF(buffer_method___tostring) 263LJLIB_CF(buffer_method___tostring) LJLIB_REC(.)
264{ 264{
265 SBufExt *sbx = buffer_tobuf(L); 265 SBufExt *sbx = buffer_tobuf(L);
266 setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx))); 266 setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
@@ -268,7 +268,7 @@ LJLIB_CF(buffer_method___tostring)
268 return 1; 268 return 1;
269} 269}
270 270
271LJLIB_CF(buffer_method___len) 271LJLIB_CF(buffer_method___len) LJLIB_REC(.)
272{ 272{
273 SBufExt *sbx = buffer_tobuf(L); 273 SBufExt *sbx = buffer_tobuf(L);
274 setintV(L->top-1, (int32_t)sbufxlen(sbx)); 274 setintV(L->top-1, (int32_t)sbufxlen(sbx));
@@ -317,29 +317,19 @@ LJLIB_CF(buffer_new)
317 return 1; 317 return 1;
318} 318}
319 319
320LJLIB_CF(buffer_encode) 320LJLIB_CF(buffer_encode) LJLIB_REC(.)
321{ 321{
322 cTValue *o = lj_lib_checkany(L, 1); 322 cTValue *o = lj_lib_checkany(L, 1);
323 SBufExt sbx; 323 setstrV(L, L->top++, lj_serialize_encode(L, o));
324 memset(&sbx, 0, sizeof(SBufExt));
325 lj_bufx_set_borrow(L, &sbx, &G(L)->tmpbuf);
326 lj_serialize_put(&sbx, o);
327 setstrV(L, L->top++, lj_buf_str(L, (SBuf *)&sbx));
328 lj_gc_check(L); 324 lj_gc_check(L);
329 return 1; 325 return 1;
330} 326}
331 327
332LJLIB_CF(buffer_decode) 328LJLIB_CF(buffer_decode) LJLIB_REC(.)
333{ 329{
334 GCstr *str = lj_lib_checkstrx(L, 1); 330 GCstr *str = lj_lib_checkstrx(L, 1);
335 SBufExt sbx;
336 memset(&sbx, 0, sizeof(SBufExt));
337 lj_bufx_set_cow(L, &sbx, strdata(str), str->len);
338 /* No need to set sbx.cowref here. */
339 setnilV(L->top++); 331 setnilV(L->top++);
340 lj_serialize_get(&sbx, L->top-1); 332 lj_serialize_decode(L, L->top-1, str);
341 lj_gc_check(L);
342 if (sbx.r != sbx.w) lj_err_caller(L, LJ_ERR_BUFFER_LEFTOV);
343 return 1; 333 return 1;
344} 334}
345 335
diff --git a/src/lj_buf.c b/src/lj_buf.c
index 889ccbca..d31bd99e 100644
--- a/src/lj_buf.c
+++ b/src/lj_buf.c
@@ -108,6 +108,25 @@ char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz)
108 return lj_buf_need(sb, sz); 108 return lj_buf_need(sb, sz);
109} 109}
110 110
111#if LJ_HASBUFFER && LJ_HASJIT
112void lj_bufx_set(SBufExt *sbx, const char *p, MSize len, GCobj *ref)
113{
114 lua_State *L = sbufL(sbx);
115 lj_bufx_free(L, sbx);
116 lj_bufx_set_cow(L, sbx, p, len);
117 setgcref(sbx->cowref, ref);
118 lj_gc_objbarrier(L, (GCudata *)sbx - 1, ref);
119}
120
121#if LJ_HASFFI
122MSize LJ_FASTCALL lj_bufx_more(SBufExt *sbx, MSize sz)
123{
124 lj_buf_more((SBuf *)sbx, sz);
125 return sbufleft(sbx);
126}
127#endif
128#endif
129
111/* -- Low-level buffer put operations ------------------------------------- */ 130/* -- Low-level buffer put operations ------------------------------------- */
112 131
113SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len) 132SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len)
@@ -118,14 +137,27 @@ SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len)
118 return sb; 137 return sb;
119} 138}
120 139
121SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c) 140#if LJ_HASJIT || LJ_HASFFI
141static LJ_NOINLINE SBuf * LJ_FASTCALL lj_buf_putchar2(SBuf *sb, int c)
122{ 142{
123 char *w = lj_buf_more(sb, 1); 143 char *w = lj_buf_more2(sb, 1);
124 *w++ = (char)c; 144 *w++ = (char)c;
125 sb->w = w; 145 sb->w = w;
126 return sb; 146 return sb;
127} 147}
128 148
149SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c)
150{
151 char *w = sb->w;
152 if (LJ_LIKELY(w < sb->e)) {
153 *w++ = (char)c;
154 sb->w = w;
155 return sb;
156 }
157 return lj_buf_putchar2(sb, c);
158}
159#endif
160
129SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s) 161SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s)
130{ 162{
131 MSize len = s->len; 163 MSize len = s->len;
diff --git a/src/lj_buf.h b/src/lj_buf.h
index b97d55ef..4ace2685 100644
--- a/src/lj_buf.h
+++ b/src/lj_buf.h
@@ -55,6 +55,7 @@ typedef struct SBufExt {
55#define sbufisext(sb) (sbufflag((sb)) & SBUF_FLAG_EXT) 55#define sbufisext(sb) (sbufflag((sb)) & SBUF_FLAG_EXT)
56#define sbufiscow(sb) (sbufflag((sb)) & SBUF_FLAG_COW) 56#define sbufiscow(sb) (sbufflag((sb)) & SBUF_FLAG_COW)
57#define sbufisborrow(sb) (sbufflag((sb)) & SBUF_FLAG_BORROW) 57#define sbufisborrow(sb) (sbufflag((sb)) & SBUF_FLAG_BORROW)
58#define sbufiscoworborrow(sb) (sbufflag((sb)) & (SBUF_FLAG_COW|SBUF_FLAG_BORROW))
58#define sbufX(sb) \ 59#define sbufX(sb) \
59 (lj_assertG_(G(sbufL(sb)), sbufisext(sb), "not an SBufExt"), (SBufExt *)(sb)) 60 (lj_assertG_(G(sbufL(sb)), sbufisext(sb), "not an SBufExt"), (SBufExt *)(sb))
60#define setsbufflag(sb, flag) (setmrefu((sb)->L, (flag))) 61#define setsbufflag(sb, flag) (setmrefu((sb)->L, (flag)))
@@ -143,15 +144,24 @@ static LJ_AINLINE void lj_bufx_reset(SBufExt *sbx)
143 144
144static LJ_AINLINE void lj_bufx_free(lua_State *L, SBufExt *sbx) 145static LJ_AINLINE void lj_bufx_free(lua_State *L, SBufExt *sbx)
145{ 146{
146 if (!sbufiscow(sbx)) lj_mem_free(G(L), sbx->b, sbufsz(sbx)); 147 if (!sbufiscoworborrow(sbx)) lj_mem_free(G(L), sbx->b, sbufsz(sbx));
147 setsbufXL(sbx, L, SBUF_FLAG_EXT); 148 setsbufXL(sbx, L, SBUF_FLAG_EXT);
148 setgcrefnull(sbx->cowref); 149 setgcrefnull(sbx->cowref);
149 sbx->r = sbx->w = sbx->b = sbx->e = NULL; 150 sbx->r = sbx->w = sbx->b = sbx->e = NULL;
150} 151}
151 152
153#if LJ_HASBUFFER && LJ_HASJIT
154LJ_FUNC void lj_bufx_set(SBufExt *sbx, const char *p, MSize len, GCobj *o);
155#if LJ_HASFFI
156LJ_FUNC MSize LJ_FASTCALL lj_bufx_more(SBufExt *sbx, MSize sz);
157#endif
158#endif
159
152/* Low-level buffer put operations */ 160/* Low-level buffer put operations */
153LJ_FUNC SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len); 161LJ_FUNC SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len);
162#if LJ_HASJIT || LJ_HASFFI
154LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c); 163LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c);
164#endif
155LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s); 165LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s);
156 166
157static LJ_AINLINE char *lj_buf_wmem(char *p, const void *q, MSize len) 167static LJ_AINLINE char *lj_buf_wmem(char *p, const void *q, MSize len)
diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index aa4c5842..95850611 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -621,7 +621,7 @@ static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval)
621 emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, ud->udtype)); 621 emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, ud->udtype));
622 sp = emitir(IRT(IR_FLOAD, IRT_PTR), sp, 622 sp = emitir(IRT(IR_FLOAD, IRT_PTR), sp,
623 ud->udtype == UDTYPE_IO_FILE ? IRFL_UDATA_FILE : 623 ud->udtype == UDTYPE_IO_FILE ? IRFL_UDATA_FILE :
624 IRFL_UDATA_BUF_R); 624 IRFL_SBUF_R);
625 } else { 625 } else {
626 sp = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, sizeof(GCudata))); 626 sp = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, sizeof(GCudata)));
627 } 627 }
@@ -1918,10 +1918,25 @@ TRef lj_crecord_loadiu64(jit_State *J, TRef tr, cTValue *o)
1918 CTypeID id = argv2cdata(J, tr, o)->ctypeid; 1918 CTypeID id = argv2cdata(J, tr, o)->ctypeid;
1919 if (!(id == CTID_INT64 || id == CTID_UINT64)) 1919 if (!(id == CTID_INT64 || id == CTID_UINT64))
1920 lj_trace_err(J, LJ_TRERR_BADTYPE); 1920 lj_trace_err(J, LJ_TRERR_BADTYPE);
1921 lj_needsplit(J);
1921 return emitir(IRT(IR_FLOAD, id == CTID_INT64 ? IRT_I64 : IRT_U64), tr, 1922 return emitir(IRT(IR_FLOAD, id == CTID_INT64 ? IRT_I64 : IRT_U64), tr,
1922 IRFL_CDATA_INT64); 1923 IRFL_CDATA_INT64);
1923} 1924}
1924 1925
1926#if LJ_HASBUFFER
1927TRef lj_crecord_topcvoid(jit_State *J, TRef tr, cTValue *o)
1928{
1929 CTState *cts = ctype_ctsG(J2G(J));
1930 if (!tref_iscdata(tr)) lj_trace_err(J, LJ_TRERR_BADTYPE);
1931 return crec_ct_tv(J, ctype_get(cts, CTID_P_CVOID), 0, tr, o);
1932}
1933
1934TRef lj_crecord_topuint8(jit_State *J, TRef tr)
1935{
1936 return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, CTID_P_UINT8), tr);
1937}
1938#endif
1939
1925#undef IR 1940#undef IR
1926#undef emitir 1941#undef emitir
1927#undef emitconv 1942#undef emitconv
diff --git a/src/lj_crecord.h b/src/lj_crecord.h
index 1a3427bd..e1a2d9c0 100644
--- a/src/lj_crecord.h
+++ b/src/lj_crecord.h
@@ -34,6 +34,10 @@ LJ_FUNC TRef recff_bit64_tohex(jit_State *J, RecordFFData *rd, TRef hdr);
34 34
35LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd); 35LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd);
36LJ_FUNC TRef lj_crecord_loadiu64(jit_State *J, TRef tr, cTValue *o); 36LJ_FUNC TRef lj_crecord_loadiu64(jit_State *J, TRef tr, cTValue *o);
37#if LJ_HASBUFFER
38LJ_FUNC TRef lj_crecord_topcvoid(jit_State *J, TRef tr, cTValue *o);
39LJ_FUNC TRef lj_crecord_topuint8(jit_State *J, TRef tr);
40#endif
37#endif 41#endif
38 42
39#endif 43#endif
diff --git a/src/lj_err.c b/src/lj_err.c
index 1a518d9c..fda4a59c 100644
--- a/src/lj_err.c
+++ b/src/lj_err.c
@@ -941,25 +941,27 @@ LJ_NOINLINE void lj_err_optype_call(lua_State *L, TValue *o)
941/* Error in context of caller. */ 941/* Error in context of caller. */
942LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg) 942LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg)
943{ 943{
944 TValue *frame = L->base-1; 944 TValue *frame = NULL, *pframe = NULL;
945 TValue *pframe = NULL; 945 if (!(LJ_HASJIT && tvref(G(L)->jit_base))) {
946 if (frame_islua(frame)) { 946 frame = L->base-1;
947 pframe = frame_prevl(frame); 947 if (frame_islua(frame)) {
948 } else if (frame_iscont(frame)) { 948 pframe = frame_prevl(frame);
949 if (frame_iscont_fficb(frame)) { 949 } else if (frame_iscont(frame)) {
950 pframe = frame; 950 if (frame_iscont_fficb(frame)) {
951 frame = NULL; 951 pframe = frame;
952 } else { 952 frame = NULL;
953 pframe = frame_prevd(frame); 953 } else {
954 pframe = frame_prevd(frame);
954#if LJ_HASFFI 955#if LJ_HASFFI
955 /* Remove frame for FFI metamethods. */ 956 /* Remove frame for FFI metamethods. */
956 if (frame_func(frame)->c.ffid >= FF_ffi_meta___index && 957 if (frame_func(frame)->c.ffid >= FF_ffi_meta___index &&
957 frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) { 958 frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) {
958 L->base = pframe+1; 959 L->base = pframe+1;
959 L->top = frame; 960 L->top = frame;
960 setcframe_pc(cframe_raw(L->cframe), frame_contpc(frame)); 961 setcframe_pc(cframe_raw(L->cframe), frame_contpc(frame));
961 } 962 }
962#endif 963#endif
964 }
963 } 965 }
964 } 966 }
965 lj_debug_addloc(L, msg, pframe, frame); 967 lj_debug_addloc(L, msg, pframe, frame);
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)
diff --git a/src/lj_ir.c b/src/lj_ir.c
index 29d75d26..71bf8855 100644
--- a/src/lj_ir.c
+++ b/src/lj_ir.c
@@ -30,6 +30,7 @@
30#endif 30#endif
31#include "lj_vm.h" 31#include "lj_vm.h"
32#include "lj_strscan.h" 32#include "lj_strscan.h"
33#include "lj_serialize.h"
33#include "lj_strfmt.h" 34#include "lj_strfmt.h"
34#include "lj_prng.h" 35#include "lj_prng.h"
35 36
diff --git a/src/lj_ir.h b/src/lj_ir.h
index fa10f4bc..b3faaea8 100644
--- a/src/lj_ir.h
+++ b/src/lj_ir.h
@@ -205,10 +205,15 @@ IRFPMDEF(FPMENUM)
205 _(UDATA_META, offsetof(GCudata, metatable)) \ 205 _(UDATA_META, offsetof(GCudata, metatable)) \
206 _(UDATA_UDTYPE, offsetof(GCudata, udtype)) \ 206 _(UDATA_UDTYPE, offsetof(GCudata, udtype)) \
207 _(UDATA_FILE, sizeof(GCudata)) \ 207 _(UDATA_FILE, sizeof(GCudata)) \
208 _(UDATA_BUF_R, sizeof(GCudata) + offsetof(SBufExt, r)) \ 208 _(SBUF_W, sizeof(GCudata) + offsetof(SBufExt, w)) \
209 _(SBUF_E, sizeof(GCudata) + offsetof(SBufExt, e)) \
210 _(SBUF_B, sizeof(GCudata) + offsetof(SBufExt, b)) \
211 _(SBUF_L, sizeof(GCudata) + offsetof(SBufExt, L)) \
212 _(SBUF_REF, sizeof(GCudata) + offsetof(SBufExt, cowref)) \
213 _(SBUF_R, sizeof(GCudata) + offsetof(SBufExt, r)) \
209 _(CDATA_CTYPEID, offsetof(GCcdata, ctypeid)) \ 214 _(CDATA_CTYPEID, offsetof(GCcdata, ctypeid)) \
210 _(CDATA_PTR, sizeof(GCcdata)) \ 215 _(CDATA_PTR, sizeof(GCcdata)) \
211 _(CDATA_INT, sizeof(GCcdata)) \ 216 _(CDATA_INT, sizeof(GCcdata)) \
212 _(CDATA_INT64, sizeof(GCcdata)) \ 217 _(CDATA_INT64, sizeof(GCcdata)) \
213 _(CDATA_INT64_4, sizeof(GCcdata) + 4) 218 _(CDATA_INT64_4, sizeof(GCcdata) + 4)
214 219
diff --git a/src/lj_ircall.h b/src/lj_ircall.h
index 13501ba1..c837b18d 100644
--- a/src/lj_ircall.h
+++ b/src/lj_ircall.h
@@ -113,6 +113,18 @@ typedef struct CCallInfo {
113#define IRCALLCOND_FFI32(x) NULL 113#define IRCALLCOND_FFI32(x) NULL
114#endif 114#endif
115 115
116#if LJ_HASBUFFER
117#define IRCALLCOND_BUFFER(x) x
118#else
119#define IRCALLCOND_BUFFER(x) NULL
120#endif
121
122#if LJ_HASBUFFER && LJ_HASFFI
123#define IRCALLCOND_BUFFFI(x) x
124#else
125#define IRCALLCOND_BUFFFI(x) NULL
126#endif
127
116#if LJ_SOFTFP 128#if LJ_SOFTFP
117#define XA_FP CCI_XA 129#define XA_FP CCI_XA
118#define XA2_FP (CCI_XA+CCI_XA) 130#define XA2_FP (CCI_XA+CCI_XA)
@@ -163,6 +175,12 @@ typedef struct CCallInfo {
163 _(ANY, lj_buf_putstr_upper, 2, FL, PGC, CCI_T) \ 175 _(ANY, lj_buf_putstr_upper, 2, FL, PGC, CCI_T) \
164 _(ANY, lj_buf_putstr_rep, 3, L, PGC, CCI_T) \ 176 _(ANY, lj_buf_putstr_rep, 3, L, PGC, CCI_T) \
165 _(ANY, lj_buf_puttab, 5, L, PGC, CCI_T) \ 177 _(ANY, lj_buf_puttab, 5, L, PGC, CCI_T) \
178 _(BUFFER, lj_bufx_set, 4, S, NIL, 0) \
179 _(BUFFFI, lj_bufx_more, 2, FS, INT, CCI_T) \
180 _(BUFFER, lj_serialize_put, 2, FS, PGC, CCI_T) \
181 _(BUFFER, lj_serialize_get, 2, FS, PTR, CCI_T) \
182 _(BUFFER, lj_serialize_encode, 2, FA, STR, CCI_L|CCI_T) \
183 _(BUFFER, lj_serialize_decode, 3, A, INT, CCI_L|CCI_T) \
166 _(ANY, lj_buf_tostr, 1, FL, STR, CCI_T) \ 184 _(ANY, lj_buf_tostr, 1, FL, STR, CCI_T) \
167 _(ANY, lj_tab_new_ah, 3, A, TAB, CCI_L|CCI_T) \ 185 _(ANY, lj_tab_new_ah, 3, A, TAB, CCI_L|CCI_T) \
168 _(ANY, lj_tab_new1, 2, FA, TAB, CCI_L|CCI_T) \ 186 _(ANY, lj_tab_new1, 2, FA, TAB, CCI_L|CCI_T) \
diff --git a/src/lj_iropt.h b/src/lj_iropt.h
index 69835ee8..0541090d 100644
--- a/src/lj_iropt.h
+++ b/src/lj_iropt.h
@@ -124,6 +124,7 @@ LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_alen(jit_State *J);
124LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_hrefk(jit_State *J); 124LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_hrefk(jit_State *J);
125LJ_FUNC int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J); 125LJ_FUNC int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J);
126LJ_FUNC int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim); 126LJ_FUNC int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim);
127LJ_FUNC int LJ_FASTCALL lj_opt_fwd_sbuf(jit_State *J, IRRef lim);
127LJ_FUNC int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref); 128LJ_FUNC int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref);
128 129
129/* Dead-store elimination. */ 130/* Dead-store elimination. */
diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c
index 97dad4ff..41e0d1ca 100644
--- a/src/lj_opt_fold.c
+++ b/src/lj_opt_fold.c
@@ -578,6 +578,9 @@ LJFOLDF(kfold_strcmp)
578** The compromise is to declare them as loads, emit them like stores and 578** The compromise is to declare them as loads, emit them like stores and
579** CSE whole chains manually when the BUFSTR is to be emitted. Any chain 579** CSE whole chains manually when the BUFSTR is to be emitted. Any chain
580** fragments left over from CSE are eliminated by DCE. 580** fragments left over from CSE are eliminated by DCE.
581**
582** The string buffer methods emit a USE instead of a BUFSTR to keep the
583** chain alive.
581*/ 584*/
582 585
583LJFOLD(BUFHDR any any) 586LJFOLD(BUFHDR any any)
@@ -586,18 +589,38 @@ LJFOLDF(bufhdr_merge)
586 return fins->op2 == IRBUFHDR_WRITE ? CSEFOLD : EMITFOLD; 589 return fins->op2 == IRBUFHDR_WRITE ? CSEFOLD : EMITFOLD;
587} 590}
588 591
589LJFOLD(BUFPUT BUFHDR BUFSTR) 592LJFOLD(BUFPUT any BUFSTR)
590LJFOLDF(bufput_append) 593LJFOLDF(bufput_bufstr)
591{ 594{
592 /* New buffer, no other buffer op inbetween and same buffer? */ 595 if ((J->flags & JIT_F_OPT_FWD)) {
593 if ((J->flags & JIT_F_OPT_FWD) && 596 IRRef hdr = fright->op2;
594 fleft->op2 == IRBUFHDR_RESET && 597 /* New buffer, no other buffer op inbetween and same buffer? */
595 fleft->prev == fright->op2 && 598 if (fleft->o == IR_BUFHDR && fleft->op2 == IRBUFHDR_RESET &&
596 fleft->op1 == IR(fright->op2)->op1) { 599 fleft->prev == hdr &&
597 IRRef ref = fins->op1; 600 fleft->op1 == IR(hdr)->op1) {
598 IR(ref)->op2 = IRBUFHDR_APPEND; /* Modify BUFHDR. */ 601 IRRef ref = fins->op1;
599 IR(ref)->op1 = fright->op1; 602 IR(ref)->op2 = IRBUFHDR_APPEND; /* Modify BUFHDR. */
600 return ref; 603 IR(ref)->op1 = fright->op1;
604 return ref;
605 }
606 /* Replay puts to global temporary buffer. */
607 if (IR(hdr)->op2 == IRBUFHDR_RESET) {
608 IRIns *ir = IR(fright->op1);
609 /* For now only handle single string.reverse .lower .upper .rep. */
610 if (ir->o == IR_CALLL &&
611 ir->op2 >= IRCALL_lj_buf_putstr_reverse &&
612 ir->op2 <= IRCALL_lj_buf_putstr_rep) {
613 IRIns *carg1 = IR(ir->op1);
614 if (ir->op2 == IRCALL_lj_buf_putstr_rep) {
615 IRIns *carg2 = IR(carg1->op1);
616 if (carg2->op1 == hdr) {
617 return lj_ir_call(J, ir->op2, fins->op1, carg2->op2, carg1->op2);
618 }
619 } else if (carg1->op1 == hdr) {
620 return lj_ir_call(J, ir->op2, fins->op1, carg1->op2);
621 }
622 }
623 }
601 } 624 }
602 return EMITFOLD; /* Always emit, CSE later. */ 625 return EMITFOLD; /* Always emit, CSE later. */
603} 626}
@@ -2285,6 +2308,18 @@ LJFOLDF(fload_str_len_tostr)
2285 return NEXTFOLD; 2308 return NEXTFOLD;
2286} 2309}
2287 2310
2311LJFOLD(FLOAD any IRFL_SBUF_W)
2312LJFOLD(FLOAD any IRFL_SBUF_E)
2313LJFOLD(FLOAD any IRFL_SBUF_B)
2314LJFOLD(FLOAD any IRFL_SBUF_L)
2315LJFOLD(FLOAD any IRFL_SBUF_REF)
2316LJFOLD(FLOAD any IRFL_SBUF_R)
2317LJFOLDF(fload_sbuf)
2318{
2319 TRef tr = lj_opt_fwd_fload(J);
2320 return lj_opt_fwd_sbuf(J, tref_ref(tr)) ? tr : EMITFOLD;
2321}
2322
2288/* The C type ID of cdata objects is immutable. */ 2323/* The C type ID of cdata objects is immutable. */
2289LJFOLD(FLOAD KGC IRFL_CDATA_CTYPEID) 2324LJFOLD(FLOAD KGC IRFL_CDATA_CTYPEID)
2290LJFOLDF(fload_cdata_typeid_kgc) 2325LJFOLDF(fload_cdata_typeid_kgc)
diff --git a/src/lj_opt_mem.c b/src/lj_opt_mem.c
index f430fc37..81184f14 100644
--- a/src/lj_opt_mem.c
+++ b/src/lj_opt_mem.c
@@ -620,8 +620,9 @@ TRef LJ_FASTCALL lj_opt_dse_fstore(jit_State *J)
620 goto doemit; 620 goto doemit;
621 break; /* Otherwise continue searching. */ 621 break; /* Otherwise continue searching. */
622 case ALIAS_MUST: 622 case ALIAS_MUST:
623 if (store->op2 == val) /* Same value: drop the new store. */ 623 if (store->op2 == val &&
624 return DROPFOLD; 624 !(xr->op2 >= IRFL_SBUF_W && xr->op2 <= IRFL_SBUF_R))
625 return DROPFOLD; /* Same value: drop the new store. */
625 /* Different value: try to eliminate the redundant store. */ 626 /* Different value: try to eliminate the redundant store. */
626 if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */ 627 if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */
627 IRIns *ir; 628 IRIns *ir;
@@ -642,6 +643,29 @@ doemit:
642 return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ 643 return EMITFOLD; /* Otherwise we have a conflict or simply no match. */
643} 644}
644 645
646/* Check whether there's no aliasing buffer op between IRFL_SBUF_*. */
647int LJ_FASTCALL lj_opt_fwd_sbuf(jit_State *J, IRRef lim)
648{
649 IRRef ref;
650 if (J->chain[IR_BUFPUT] > lim)
651 return 0; /* Conflict. */
652 ref = J->chain[IR_CALLS];
653 while (ref > lim) {
654 IRIns *ir = IR(ref);
655 if (ir->op2 >= IRCALL_lj_strfmt_putint && ir->op2 < IRCALL_lj_buf_tostr)
656 return 0; /* Conflict. */
657 ref = ir->prev;
658 }
659 ref = J->chain[IR_CALLL];
660 while (ref > lim) {
661 IRIns *ir = IR(ref);
662 if (ir->op2 >= IRCALL_lj_strfmt_putint && ir->op2 < IRCALL_lj_buf_tostr)
663 return 0; /* Conflict. */
664 ref = ir->prev;
665 }
666 return 1; /* No conflict. Can safely FOLD/CSE. */
667}
668
645/* -- XLOAD forwarding and XSTORE elimination ----------------------------- */ 669/* -- XLOAD forwarding and XSTORE elimination ----------------------------- */
646 670
647/* Find cdata allocation for a reference (if any). */ 671/* Find cdata allocation for a reference (if any). */
diff --git a/src/lj_record.c b/src/lj_record.c
index c0aea106..ee62179b 100644
--- a/src/lj_record.c
+++ b/src/lj_record.c
@@ -1445,6 +1445,16 @@ TRef lj_record_idx(jit_State *J, RecordIndex *ix)
1445 return 0; /* No result yet. */ 1445 return 0; /* No result yet. */
1446 } 1446 }
1447 } 1447 }
1448#if LJ_HASBUFFER
1449 /* The index table of buffer objects is treated as immutable. */
1450 if (ix->mt == TREF_NIL && !ix->val &&
1451 tref_isudata(ix->tab) && udataV(&ix->tabv)->udtype == UDTYPE_BUFFER &&
1452 tref_istab(ix->mobj) && tref_isstr(ix->key) && tref_isk(ix->key)) {
1453 cTValue *val = lj_tab_getstr(tabV(&ix->mobjv), strV(&ix->keyv));
1454 TRef tr = lj_record_constify(J, val);
1455 if (tr) return tr; /* Specialize to the value, i.e. a method. */
1456 }
1457#endif
1448 /* Otherwise retry lookup with metaobject. */ 1458 /* Otherwise retry lookup with metaobject. */
1449 ix->tab = ix->mobj; 1459 ix->tab = ix->mobj;
1450 copyTV(J->L, &ix->tabv, &ix->mobjv); 1460 copyTV(J->L, &ix->tabv, &ix->mobjv);
diff --git a/src/lj_serialize.c b/src/lj_serialize.c
index d84ebcb8..70ff4796 100644
--- a/src/lj_serialize.c
+++ b/src/lj_serialize.c
@@ -18,6 +18,9 @@
18#include "lj_ctype.h" 18#include "lj_ctype.h"
19#include "lj_cdata.h" 19#include "lj_cdata.h"
20#endif 20#endif
21#if LJ_HASJIT
22#include "lj_ir.h"
23#endif
21#include "lj_serialize.h" 24#include "lj_serialize.h"
22 25
23/* Tags for internal serialization format. */ 26/* Tags for internal serialization format. */
@@ -400,6 +403,9 @@ eob:
400 return NULL; 403 return NULL;
401} 404}
402 405
406/* -- External serialization API ------------------------------------------ */
407
408/* Encode to buffer. */
403SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o) 409SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o)
404{ 410{
405 sbx->depth = LJ_SERIALIZE_DEPTH; 411 sbx->depth = LJ_SERIALIZE_DEPTH;
@@ -407,10 +413,63 @@ SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o)
407 return sbx; 413 return sbx;
408} 414}
409 415
410SBufExt * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o) 416/* Decode from buffer. */
417char * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o)
411{ 418{
412 sbx->r = serialize_get(sbx->r, sbx, o); 419 return serialize_get(sbx->r, sbx, o);
413 return sbx; 420}
421
422/* Stand-alone encoding, borrowing from global temporary buffer. */
423GCstr * LJ_FASTCALL lj_serialize_encode(lua_State *L, cTValue *o)
424{
425 SBufExt sbx;
426 char *w;
427 memset(&sbx, 0, sizeof(SBufExt));
428 lj_bufx_set_borrow(L, &sbx, &G(L)->tmpbuf);
429 sbx.depth = LJ_SERIALIZE_DEPTH;
430 w = serialize_put(sbx.w, &sbx, o);
431 return lj_str_new(L, sbx.b, (size_t)(w - sbx.b));
432}
433
434/* Stand-alone decoding, copy-on-write from string. */
435void lj_serialize_decode(lua_State *L, TValue *o, GCstr *str)
436{
437 SBufExt sbx;
438 char *r;
439 memset(&sbx, 0, sizeof(SBufExt));
440 lj_bufx_set_cow(L, &sbx, strdata(str), str->len);
441 /* No need to set sbx.cowref here. */
442 r = lj_serialize_get(&sbx, o);
443 if (r != sbx.w) lj_err_caller(L, LJ_ERR_BUFFER_LEFTOV);
444}
445
446#if LJ_HASJIT
447/* Peek into buffer to find the result IRType for specialization purposes. */
448LJ_FUNC MSize LJ_FASTCALL lj_serialize_peektype(SBufExt *sbx)
449{
450 uint32_t tp;
451 if (serialize_ru124(sbx->r, sbx->w, &tp)) {
452 /* This must match the handling of all tags in the decoder above. */
453 switch (tp) {
454 case SER_TAG_NIL: return IRT_NIL;
455 case SER_TAG_FALSE: return IRT_FALSE;
456 case SER_TAG_TRUE: return IRT_TRUE;
457 case SER_TAG_NULL: case SER_TAG_LIGHTUD32: case SER_TAG_LIGHTUD64:
458 return IRT_LIGHTUD;
459 case SER_TAG_INT: return LJ_DUALNUM ? IRT_INT : IRT_NUM;
460 case SER_TAG_NUM: return IRT_NUM;
461 case SER_TAG_TAB: case SER_TAG_TAB+1: case SER_TAG_TAB+2:
462 case SER_TAG_TAB+3: case SER_TAG_TAB+4: case SER_TAG_TAB+5:
463 return IRT_TAB;
464 case SER_TAG_INT64: case SER_TAG_UINT64: case SER_TAG_COMPLEX:
465 return IRT_CDATA;
466 case SER_TAG_DICT:
467 default:
468 return IRT_STR;
469 }
470 }
471 return IRT_NIL; /* Will fail on actual decode. */
414} 472}
473#endif
415 474
416#endif 475#endif
diff --git a/src/lj_serialize.h b/src/lj_serialize.h
index ccf1d63d..9bd780ca 100644
--- a/src/lj_serialize.h
+++ b/src/lj_serialize.h
@@ -15,7 +15,12 @@
15 15
16LJ_FUNC void LJ_FASTCALL lj_serialize_dict_prep(lua_State *L, GCtab *dict); 16LJ_FUNC void LJ_FASTCALL lj_serialize_dict_prep(lua_State *L, GCtab *dict);
17LJ_FUNC SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o); 17LJ_FUNC SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o);
18LJ_FUNC SBufExt * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o); 18LJ_FUNC char * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o);
19LJ_FUNC GCstr * LJ_FASTCALL lj_serialize_encode(lua_State *L, cTValue *o);
20LJ_FUNC void lj_serialize_decode(lua_State *L, TValue *o, GCstr *str);
21#if LJ_HASJIT
22LJ_FUNC MSize LJ_FASTCALL lj_serialize_peektype(SBufExt *sbx);
23#endif
19 24
20#endif 25#endif
21 26