diff options
author | Mike Pall <mike> | 2021-07-19 16:53:30 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2021-07-19 16:53:30 +0200 |
commit | 29bc1f04ace7e466437ebb08ac73c86b8a11cfda (patch) | |
tree | 3202613210b07790f19cc148c6249d5dc32de164 | |
parent | 21826309035979e17973c5ee2761f430adc6b7a6 (diff) | |
download | luajit-29bc1f04ace7e466437ebb08ac73c86b8a11cfda.tar.gz luajit-29bc1f04ace7e466437ebb08ac73c86b8a11cfda.tar.bz2 luajit-29bc1f04ace7e466437ebb08ac73c86b8a11cfda.zip |
String buffers, part 3d: Compile string buffer methods and functions.
Sponsored by fmad.io.
-rw-r--r-- | src/Makefile.dep | 12 | ||||
-rw-r--r-- | src/host/buildvm_lib.c | 2 | ||||
-rw-r--r-- | src/lib_buffer.c | 52 | ||||
-rw-r--r-- | src/lj_buf.c | 36 | ||||
-rw-r--r-- | src/lj_buf.h | 12 | ||||
-rw-r--r-- | src/lj_crecord.c | 17 | ||||
-rw-r--r-- | src/lj_crecord.h | 4 | ||||
-rw-r--r-- | src/lj_err.c | 36 | ||||
-rw-r--r-- | src/lj_ffrecord.c | 345 | ||||
-rw-r--r-- | src/lj_ir.c | 1 | ||||
-rw-r--r-- | src/lj_ir.h | 9 | ||||
-rw-r--r-- | src/lj_ircall.h | 18 | ||||
-rw-r--r-- | src/lj_iropt.h | 1 | ||||
-rw-r--r-- | src/lj_opt_fold.c | 57 | ||||
-rw-r--r-- | src/lj_opt_mem.c | 28 | ||||
-rw-r--r-- | src/lj_record.c | 10 | ||||
-rw-r--r-- | src/lj_serialize.c | 65 | ||||
-rw-r--r-- | src/lj_serialize.h | 7 |
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 |
116 | lj_ffrecord.o: lj_ffrecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 116 | lj_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 |
121 | lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | 121 | lj_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 \ | |||
131 | lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | 131 | lj_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 |
135 | lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | 135 | lj_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 |
186 | lj_serialize.o: lj_serialize.c lj_obj.h lua.h luaconf.h lj_def.h \ | 186 | lj_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 |
189 | lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | 189 | lj_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 | ||
64 | LJLIB_CF(buffer_method_reset) | 64 | LJLIB_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 | ||
72 | LJLIB_CF(buffer_method_skip) | 72 | LJLIB_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 | ||
86 | LJLIB_CF(buffer_method_set) | 86 | LJLIB_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 | ||
114 | LJLIB_CF(buffer_method_put) | 114 | LJLIB_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 | ||
150 | LJLIB_CF(buffer_method_putf) | 150 | LJLIB_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 | ||
159 | LJLIB_CF(buffer_method_get) | 159 | LJLIB_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 |
182 | LJLIB_CF(buffer_method_putcdata) | 182 | LJLIB_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 | ||
200 | LJLIB_CF(buffer_method_reserve) | 200 | LJLIB_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 | ||
214 | LJLIB_CF(buffer_method_commit) | 214 | LJLIB_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 | ||
224 | LJLIB_CF(buffer_method_ref) | 224 | LJLIB_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 | ||
237 | LJLIB_CF(buffer_method_encode) | 237 | LJLIB_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 | ||
247 | LJLIB_CF(buffer_method_decode) | 247 | LJLIB_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 | ||
263 | LJLIB_CF(buffer_method___tostring) | 263 | LJLIB_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 | ||
271 | LJLIB_CF(buffer_method___len) | 271 | LJLIB_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 | ||
320 | LJLIB_CF(buffer_encode) | 320 | LJLIB_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 | ||
332 | LJLIB_CF(buffer_decode) | 328 | LJLIB_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 | ||
112 | void 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 | ||
122 | MSize 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 | ||
113 | SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len) | 132 | SBuf *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 | ||
121 | SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c) | 140 | #if LJ_HASJIT || LJ_HASFFI |
141 | static 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 | ||
149 | SBuf * 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 | |||
129 | SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s) | 161 | SBuf * 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 | ||
144 | static LJ_AINLINE void lj_bufx_free(lua_State *L, SBufExt *sbx) | 145 | static 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 | ||
154 | LJ_FUNC void lj_bufx_set(SBufExt *sbx, const char *p, MSize len, GCobj *o); | ||
155 | #if LJ_HASFFI | ||
156 | LJ_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 */ |
153 | LJ_FUNC SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len); | 161 | LJ_FUNC SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len); |
162 | #if LJ_HASJIT || LJ_HASFFI | ||
154 | LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c); | 163 | LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c); |
164 | #endif | ||
155 | LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s); | 165 | LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s); |
156 | 166 | ||
157 | static LJ_AINLINE char *lj_buf_wmem(char *p, const void *q, MSize len) | 167 | static 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 | ||
1927 | TRef 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 | |||
1934 | TRef 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 | ||
35 | LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd); | 35 | LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd); |
36 | LJ_FUNC TRef lj_crecord_loadiu64(jit_State *J, TRef tr, cTValue *o); | 36 | LJ_FUNC TRef lj_crecord_loadiu64(jit_State *J, TRef tr, cTValue *o); |
37 | #if LJ_HASBUFFER | ||
38 | LJ_FUNC TRef lj_crecord_topcvoid(jit_State *J, TRef tr, cTValue *o); | ||
39 | LJ_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. */ |
942 | LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg) | 942 | LJ_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 | ||
944 | static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) | 946 | static 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 | |||
1038 | static 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 | |||
1047 | static 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 | |||
1052 | static 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 | |||
1058 | static 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 | |||
1063 | static 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 | |||
1069 | static 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. */ | ||
1078 | static 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. */ | ||
1088 | static 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. */ | ||
1095 | static 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 | |||
1118 | static 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 | |||
1145 | static 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 | |||
1157 | static 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 | |||
1175 | static 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 | |||
1203 | static 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 | ||
1210 | static 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 | |||
1236 | static 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 | |||
1244 | static 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 | ||
1253 | static 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 | |||
1263 | static 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 | |||
1273 | static 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 | |||
1287 | static 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 | |||
1298 | static 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 | |||
1310 | static 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 | |||
1325 | static 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 | |||
1337 | static 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 | ||
1036 | static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) | 1361 | static 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); | |||
124 | LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_hrefk(jit_State *J); | 124 | LJ_FUNC TRef LJ_FASTCALL lj_opt_fwd_hrefk(jit_State *J); |
125 | LJ_FUNC int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J); | 125 | LJ_FUNC int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J); |
126 | LJ_FUNC int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim); | 126 | LJ_FUNC int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim); |
127 | LJ_FUNC int LJ_FASTCALL lj_opt_fwd_sbuf(jit_State *J, IRRef lim); | ||
127 | LJ_FUNC int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref); | 128 | LJ_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 | ||
583 | LJFOLD(BUFHDR any any) | 586 | LJFOLD(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 | ||
589 | LJFOLD(BUFPUT BUFHDR BUFSTR) | 592 | LJFOLD(BUFPUT any BUFSTR) |
590 | LJFOLDF(bufput_append) | 593 | LJFOLDF(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 | ||
2311 | LJFOLD(FLOAD any IRFL_SBUF_W) | ||
2312 | LJFOLD(FLOAD any IRFL_SBUF_E) | ||
2313 | LJFOLD(FLOAD any IRFL_SBUF_B) | ||
2314 | LJFOLD(FLOAD any IRFL_SBUF_L) | ||
2315 | LJFOLD(FLOAD any IRFL_SBUF_REF) | ||
2316 | LJFOLD(FLOAD any IRFL_SBUF_R) | ||
2317 | LJFOLDF(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. */ |
2289 | LJFOLD(FLOAD KGC IRFL_CDATA_CTYPEID) | 2324 | LJFOLD(FLOAD KGC IRFL_CDATA_CTYPEID) |
2290 | LJFOLDF(fload_cdata_typeid_kgc) | 2325 | LJFOLDF(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_*. */ | ||
647 | int 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. */ | ||
403 | SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o) | 409 | SBufExt * 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 | ||
410 | SBufExt * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o) | 416 | /* Decode from buffer. */ |
417 | char * 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. */ | ||
423 | GCstr * 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. */ | ||
435 | void 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. */ | ||
448 | LJ_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 | ||
16 | LJ_FUNC void LJ_FASTCALL lj_serialize_dict_prep(lua_State *L, GCtab *dict); | 16 | LJ_FUNC void LJ_FASTCALL lj_serialize_dict_prep(lua_State *L, GCtab *dict); |
17 | LJ_FUNC SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o); | 17 | LJ_FUNC SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o); |
18 | LJ_FUNC SBufExt * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o); | 18 | LJ_FUNC char * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o); |
19 | LJ_FUNC GCstr * LJ_FASTCALL lj_serialize_encode(lua_State *L, cTValue *o); | ||
20 | LJ_FUNC void lj_serialize_decode(lua_State *L, TValue *o, GCstr *str); | ||
21 | #if LJ_HASJIT | ||
22 | LJ_FUNC MSize LJ_FASTCALL lj_serialize_peektype(SBufExt *sbx); | ||
23 | #endif | ||
19 | 24 | ||
20 | #endif | 25 | #endif |
21 | 26 | ||