aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.dep29
-rw-r--r--src/lib_base.c19
-rw-r--r--src/lib_buffer.c278
-rw-r--r--src/lj_asm.c1
-rw-r--r--src/lj_buf.h4
-rw-r--r--src/lj_cconv.c3
-rw-r--r--src/lj_crecord.c8
-rw-r--r--src/lj_ctype.h1
-rw-r--r--src/lj_errmsg.h1
-rw-r--r--src/lj_gc.c6
-rw-r--r--src/lj_ir.h1
-rw-r--r--src/lj_lib.c54
-rw-r--r--src/lj_lib.h6
-rw-r--r--src/lj_meta.c13
-rw-r--r--src/lj_obj.h1
-rw-r--r--src/lj_serialize.c5
-rw-r--r--src/lj_strfmt.c8
17 files changed, 409 insertions, 29 deletions
diff --git a/src/Makefile.dep b/src/Makefile.dep
index 0bf63391..a557d44f 100644
--- a/src/Makefile.dep
+++ b/src/Makefile.dep
@@ -2,17 +2,18 @@ lib_aux.o: lib_aux.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
2 lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \ 2 lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \
3 lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h 3 lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h
4lib_base.o: lib_base.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ 4lib_base.o: lib_base.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
5 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h \ 5 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h \
6 lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cconv.h \ 6 lj_str.h lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h \
7 lj_ff.h lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h lj_strscan.h \ 7 lj_cconv.h lj_ff.h lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h \
8 lj_strfmt.h lj_lib.h lj_libdef.h 8 lj_strscan.h lj_strfmt.h lj_lib.h lj_libdef.h
9lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ 9lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
10 lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_strscan.h \ 10 lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_strscan.h \
11 lj_strfmt.h lj_ctype.h lj_cdata.h lj_cconv.h lj_carith.h lj_ff.h \ 11 lj_strfmt.h lj_ctype.h lj_cdata.h lj_cconv.h lj_carith.h lj_ff.h \
12 lj_ffdef.h lj_lib.h lj_libdef.h 12 lj_ffdef.h lj_lib.h lj_libdef.h
13lib_buffer.o: lib_buffer.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ 13lib_buffer.o: lib_buffer.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
14 lj_def.h lj_arch.h lj_gc.h lj_buf.h lj_str.h lj_serialize.h lj_lib.h \ 14 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \
15 lj_libdef.h 15 lj_tab.h lj_udata.h lj_meta.h lj_ctype.h lj_cdata.h lj_cconv.h \
16 lj_strfmt.h lj_serialize.h lj_lib.h lj_libdef.h
16lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ 17lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
17 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_lib.h \ 18 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_lib.h \
18 lj_libdef.h 19 lj_libdef.h
@@ -51,10 +52,10 @@ lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
51 lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \ 52 lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
52 lj_dispatch.h lj_traceerr.h lj_vm.h lj_strscan.h lj_strfmt.h 53 lj_dispatch.h lj_traceerr.h lj_vm.h lj_strscan.h lj_strfmt.h
53lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 54lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
54 lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h \ 55 lj_buf.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h \
55 lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h lj_traceerr.h \ 56 lj_jit.h lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h \
56 lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h lj_emit_*.h \ 57 lj_traceerr.h lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h \
57 lj_asm_*.h 58 lj_emit_*.h lj_asm_*.h
58lj_assert.o: lj_assert.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h 59lj_assert.o: lj_assert.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
59lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ 60lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
60 lj_bcdef.h 61 lj_bcdef.h
@@ -80,8 +81,8 @@ lj_ccallback.o: lj_ccallback.c lj_obj.h lua.h luaconf.h lj_def.h \
80 lj_target_*.h lj_mcode.h lj_jit.h lj_ir.h lj_trace.h lj_dispatch.h \ 81 lj_target_*.h lj_mcode.h lj_jit.h lj_ir.h lj_trace.h lj_dispatch.h \
81 lj_traceerr.h lj_vm.h 82 lj_traceerr.h lj_vm.h
82lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 83lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
83 lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_gc.h lj_cdata.h lj_cconv.h \ 84 lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h lj_ctype.h \
84 lj_ccallback.h 85 lj_cdata.h lj_cconv.h lj_ccallback.h
85lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 86lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
86 lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h 87 lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h
87lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h 88lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h
@@ -137,8 +138,8 @@ lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
137 lj_strfmt.h 138 lj_strfmt.h
138lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \ 139lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \
139 lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \ 140 lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \
140 lj_dispatch.h lj_jit.h lj_ir.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lex.h \ 141 lj_dispatch.h lj_jit.h lj_ir.h lj_ctype.h lj_vm.h lj_strscan.h \
141 lj_bcdump.h lj_lib.h 142 lj_strfmt.h lj_lex.h lj_bcdump.h lj_lib.h
142lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \ 143lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
143 lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_func.h \ 144 lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_func.h \
144 lj_frame.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h 145 lj_frame.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
diff --git a/src/lib_base.c b/src/lib_base.c
index cb2e244e..1c8816f0 100644
--- a/src/lib_base.c
+++ b/src/lib_base.c
@@ -19,6 +19,7 @@
19#include "lj_gc.h" 19#include "lj_gc.h"
20#include "lj_err.h" 20#include "lj_err.h"
21#include "lj_debug.h" 21#include "lj_debug.h"
22#include "lj_buf.h"
22#include "lj_str.h" 23#include "lj_str.h"
23#include "lj_tab.h" 24#include "lj_tab.h"
24#include "lj_meta.h" 25#include "lj_meta.h"
@@ -406,10 +407,22 @@ LJLIB_CF(load)
406 GCstr *name = lj_lib_optstr(L, 2); 407 GCstr *name = lj_lib_optstr(L, 2);
407 GCstr *mode = lj_lib_optstr(L, 3); 408 GCstr *mode = lj_lib_optstr(L, 3);
408 int status; 409 int status;
409 if (L->base < L->top && (tvisstr(L->base) || tvisnumber(L->base))) { 410 if (L->base < L->top &&
410 GCstr *s = lj_lib_checkstr(L, 1); 411 (tvisstr(L->base) || tvisnumber(L->base) || tvisbuf(L->base))) {
412 const char *s;
413 MSize len;
414 if (tvisbuf(L->base)) {
415 SBufExt *sbx = bufV(L->base);
416 s = sbx->r;
417 len = sbufxlen(sbx);
418 if (!name) name = &G(L)->strempty; /* Buffers are not NUL-terminated. */
419 } else {
420 GCstr *str = lj_lib_checkstr(L, 1);
421 s = strdata(str);
422 len = str->len;
423 }
411 lua_settop(L, 4); /* Ensure env arg exists. */ 424 lua_settop(L, 4); /* Ensure env arg exists. */
412 status = luaL_loadbufferx(L, strdata(s), s->len, strdata(name ? name : s), 425 status = luaL_loadbufferx(L, s, len, name ? strdata(name) : s,
413 mode ? strdata(mode) : NULL); 426 mode ? strdata(mode) : NULL);
414 } else { 427 } else {
415 lj_lib_checkfunc(L, 1); 428 lj_lib_checkfunc(L, 1);
diff --git a/src/lib_buffer.c b/src/lib_buffer.c
index c9ef9510..78c4eeb9 100644
--- a/src/lib_buffer.c
+++ b/src/lib_buffer.c
@@ -14,14 +14,286 @@
14 14
15#if LJ_HASBUFFER 15#if LJ_HASBUFFER
16#include "lj_gc.h" 16#include "lj_gc.h"
17#include "lj_err.h"
17#include "lj_buf.h" 18#include "lj_buf.h"
19#include "lj_str.h"
20#include "lj_tab.h"
21#include "lj_udata.h"
22#include "lj_meta.h"
23#if LJ_HASFFI
24#include "lj_ctype.h"
25#include "lj_cdata.h"
26#include "lj_cconv.h"
27#endif
28#include "lj_strfmt.h"
18#include "lj_serialize.h" 29#include "lj_serialize.h"
19#include "lj_lib.h" 30#include "lj_lib.h"
20 31
21/* ------------------------------------------------------------------------ */ 32/* ------------------------------------------------------------------------ */
22 33
34#define LJLIB_MODULE_buffer_method
35
36/* Check that the first argument is a string buffer. */
37static SBufExt *buffer_tobuf(lua_State *L)
38{
39 if (!(L->base < L->top && tvisbuf(L->base)))
40 lj_err_argtype(L, 1, "buffer");
41 return bufV(L->base);
42}
43
44/* Ditto, but for writers. */
45static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
46{
47 SBufExt *sbx = buffer_tobuf(L);
48 setsbufXL_(sbx, L);
49 return sbx;
50}
51
52LJLIB_CF(buffer_method_free)
53{
54 SBufExt *sbx = buffer_tobuf(L);
55 lj_bufx_free(G(L), sbx);
56 lj_bufx_init(L, sbx);
57 L->top = L->base+1; /* Chain buffer object. */
58 return 1;
59}
60
61LJLIB_CF(buffer_method_reset)
62{
63 SBufExt *sbx = buffer_tobuf(L);
64 lj_bufx_reset(sbx);
65 L->top = L->base+1; /* Chain buffer object. */
66 return 1;
67}
68
69LJLIB_CF(buffer_method_skip)
70{
71 SBufExt *sbx = buffer_tobuf(L);
72 MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
73 MSize len = sbufxlen(sbx);
74 if (n < len) {
75 sbx->r += n;
76 } else {
77 sbx->r = sbx->w = sbx->b;
78 }
79 L->top = L->base+1; /* Chain buffer object. */
80 return 1;
81}
82
83LJLIB_CF(buffer_method_set)
84{
85 SBufExt *sbx = buffer_tobuf(L);
86 const char *p;
87 MSize len;
88#if LJ_HASFFI
89 if (tviscdata(L->base+1)) {
90 CTState *cts = ctype_cts(L);
91 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
92 L->base+1, CCF_ARG(2));
93 len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
94 } else
95#endif
96 {
97 GCstr *str = lj_lib_checkstrx(L, 2);
98 p = strdata(str);
99 len = str->len;
100 }
101 lj_bufx_free(G(L), sbx);
102 lj_bufx_init_cow(L, sbx, p, len);
103 setgcref(sbx->cowref, gcV(L->base+1));
104 L->top = L->base+1; /* Chain buffer object. */
105 return 1;
106}
107
108LJLIB_CF(buffer_method_put)
109{
110 SBufExt *sbx = buffer_tobufw(L);
111 ptrdiff_t arg, narg = L->top - L->base;
112 for (arg = 1; arg < narg; arg++) {
113 cTValue *o = &L->base[arg], *mo = NULL;
114 retry:
115 if (tvisstr(o)) {
116 lj_buf_putstr((SBuf *)sbx, strV(o));
117 } else if (tvisint(o)) {
118 lj_strfmt_putint((SBuf *)sbx, intV(o));
119 } else if (tvisnum(o)) {
120 lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
121 } else if (tvisbuf(o)) {
122 SBufExt *sbx2 = bufV(o);
123 lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
124 } else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
125 /* Call __tostring metamethod inline. */
126 copyTV(L, L->top++, mo);
127 copyTV(L, L->top++, o);
128 lua_call(L, 1, 1);
129 o = &L->base[arg]; /* The stack may have been reallocated. */
130 copyTV(L, &L->base[arg], L->top-1);
131 L->top = L->base + narg;
132 goto retry; /* Retry with the result. */
133 } else {
134 lj_err_argtype(L, arg+1, "string/number/__tostring");
135 }
136 /* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
137 }
138 L->top = L->base+1; /* Chain buffer object. */
139 lj_gc_check(L);
140 return 1;
141}
142
143LJLIB_CF(buffer_method_putf)
144{
145 SBufExt *sbx = buffer_tobufw(L);
146 lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
147 L->top = L->base+1; /* Chain buffer object. */
148 lj_gc_check(L);
149 return 1;
150}
151
152LJLIB_CF(buffer_method_get)
153{
154 SBufExt *sbx = buffer_tobuf(L);
155 ptrdiff_t arg, narg = L->top - L->base;
156 if (narg == 1) {
157 narg++;
158 setnilV(L->top++); /* get() is the same as get(nil). */
159 }
160 for (arg = 1; arg < narg; arg++) {
161 TValue *o = &L->base[arg];
162 MSize n = tvisnil(o) ? LJ_MAX_BUF :
163 (MSize) lj_lib_checkintrange(L, arg+1, 0, LJ_MAX_BUF);
164 MSize len = sbufxlen(sbx);
165 if (n > len) n = len;
166 setstrV(L, o, lj_str_new(L, sbx->r, n));
167 sbx->r += n;
168 }
169 if (sbx->r == sbx->w) sbx->r = sbx->w = sbx->b;
170 lj_gc_check(L);
171 return narg-1;
172}
173
174#if LJ_HASFFI
175LJLIB_CF(buffer_method_putcdata)
176{
177 SBufExt *sbx = buffer_tobufw(L);
178 const char *p;
179 MSize len;
180 if (tviscdata(L->base+1)) {
181 CTState *cts = ctype_cts(L);
182 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
183 L->base+1, CCF_ARG(2));
184 } else {
185 lj_err_argtype(L, 2, "cdata");
186 }
187 len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
188 lj_buf_putmem((SBuf *)sbx, p, len);
189 L->top = L->base+1; /* Chain buffer object. */
190 return 1;
191}
192
193LJLIB_CF(buffer_method_reserve)
194{
195 SBufExt *sbx = buffer_tobufw(L);
196 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
197 GCcdata *cd;
198 lj_buf_more((SBuf *)sbx, len);
199 ctype_loadffi(L);
200 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
201 *(void **)cdataptr(cd) = sbx->w;
202 setcdataV(L, L->top++, cd);
203 setintV(L->top++, sbufleft(sbx));
204 return 2;
205}
206
207LJLIB_CF(buffer_method_commit)
208{
209 SBufExt *sbx = buffer_tobuf(L);
210 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
211 if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
212 sbx->w += len;
213 L->top = L->base+1; /* Chain buffer object. */
214 return 1;
215}
216
217LJLIB_CF(buffer_method_ref)
218{
219 SBufExt *sbx = buffer_tobuf(L);
220 GCcdata *cd;
221 ctype_loadffi(L);
222 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
223 *(void **)cdataptr(cd) = sbx->r;
224 setcdataV(L, L->top++, cd);
225 setintV(L->top++, sbufxlen(sbx));
226 return 2;
227}
228#endif
229
230LJLIB_CF(buffer_method_encode)
231{
232 SBufExt *sbx = buffer_tobufw(L);
233 cTValue *o = lj_lib_checkany(L, 2);
234 lj_serialize_put(sbx, o);
235 lj_gc_check(L);
236 L->top = L->base+1; /* Chain buffer object. */
237 return 1;
238}
239
240LJLIB_CF(buffer_method_decode)
241{
242 SBufExt *sbx = buffer_tobufw(L);
243 setnilV(L->top++);
244 lj_serialize_get(sbx, L->top-1);
245 lj_gc_check(L);
246 return 1;
247}
248
249LJLIB_CF(buffer_method___gc)
250{
251 SBufExt *sbx = buffer_tobuf(L);
252 lj_bufx_free(G(L), sbx);
253 lj_bufx_init(L, sbx);
254 return 0;
255}
256
257LJLIB_CF(buffer_method___tostring)
258{
259 SBufExt *sbx = buffer_tobuf(L);
260 setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
261 lj_gc_check(L);
262 return 1;
263}
264
265LJLIB_CF(buffer_method___len)
266{
267 SBufExt *sbx = buffer_tobuf(L);
268 setintV(L->top-1, (int32_t)sbufxlen(sbx));
269 return 1;
270}
271
272LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
273LJLIB_PUSH(top-1) LJLIB_SET(__index)
274
275/* ------------------------------------------------------------------------ */
276
23#define LJLIB_MODULE_buffer 277#define LJLIB_MODULE_buffer
24 278
279LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
280
281LJLIB_CF(buffer_new)
282{
283 MSize sz = L->base == L->top ? 0u :
284 (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
285 GCtab *env = tabref(curr_func(L)->c.env);
286 GCudata *ud = lj_udata_new(L, sizeof(SBufExt), env);
287 SBufExt *sbx = (SBufExt *)uddata(ud);
288 ud->udtype = UDTYPE_BUFFER;
289 /* NOBARRIER: The GCudata is new (marked white). */
290 setgcref(ud->metatable, obj2gco(env));
291 setudataV(L, L->top++, ud);
292 lj_bufx_init(L, sbx);
293 if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
294 return 1;
295}
296
25LJLIB_CF(buffer_encode) 297LJLIB_CF(buffer_encode)
26{ 298{
27 cTValue *o = lj_lib_checkany(L, 1); 299 cTValue *o = lj_lib_checkany(L, 1);
@@ -35,13 +307,14 @@ LJLIB_CF(buffer_encode)
35 307
36LJLIB_CF(buffer_decode) 308LJLIB_CF(buffer_decode)
37{ 309{
38 GCstr *str = lj_lib_checkstr(L, 1); 310 GCstr *str = lj_lib_checkstrx(L, 1);
39 SBufExt sbx; 311 SBufExt sbx;
40 lj_bufx_init_cow(L, &sbx, strdata(str), str->len); 312 lj_bufx_init_cow(L, &sbx, strdata(str), str->len);
41 /* No need to set sbx.cowref here. */ 313 /* No need to set sbx.cowref here. */
42 setnilV(L->top++); 314 setnilV(L->top++);
43 lj_serialize_get(&sbx, L->top-1); 315 lj_serialize_get(&sbx, L->top-1);
44 lj_gc_check(L); 316 lj_gc_check(L);
317 if (sbx.r != sbx.w) lj_err_caller(L, LJ_ERR_BUFFER_LEFTOV);
45 return 1; 318 return 1;
46} 319}
47 320
@@ -51,6 +324,9 @@ LJLIB_CF(buffer_decode)
51 324
52int luaopen_string_buffer(lua_State *L) 325int luaopen_string_buffer(lua_State *L)
53{ 326{
327 LJ_LIB_REG(L, NULL, buffer_method);
328 lua_getfield(L, -1, "__tostring");
329 lua_setfield(L, -2, "tostring");
54 LJ_LIB_REG(L, NULL, buffer); 330 LJ_LIB_REG(L, NULL, buffer);
55 return 1; 331 return 1;
56} 332}
diff --git a/src/lj_asm.c b/src/lj_asm.c
index 286756c6..0e159e52 100644
--- a/src/lj_asm.c
+++ b/src/lj_asm.c
@@ -11,6 +11,7 @@
11#if LJ_HASJIT 11#if LJ_HASJIT
12 12
13#include "lj_gc.h" 13#include "lj_gc.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"
diff --git a/src/lj_buf.h b/src/lj_buf.h
index 1fb70146..02f0ac61 100644
--- a/src/lj_buf.h
+++ b/src/lj_buf.h
@@ -58,6 +58,10 @@ typedef struct SBufExt {
58 (lj_assertG_(G(sbufL(sb)), sbufisext(sb), "not an SBufExt"), (SBufExt *)(sb)) 58 (lj_assertG_(G(sbufL(sb)), sbufisext(sb), "not an SBufExt"), (SBufExt *)(sb))
59#define setsbufflag(sb, flag) (setmrefu((sb)->L, (flag))) 59#define setsbufflag(sb, flag) (setmrefu((sb)->L, (flag)))
60 60
61#define tvisbuf(o) \
62 (LJ_HASBUFFER && tvisudata(o) && udataV(o)->udtype == UDTYPE_BUFFER)
63#define bufV(o) check_exp(tvisbuf(o), ((SBufExt *)uddata(udataV(o))))
64
61/* Buffer management */ 65/* Buffer management */
62LJ_FUNC char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz); 66LJ_FUNC char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz);
63LJ_FUNC char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz); 67LJ_FUNC char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz);
diff --git a/src/lj_cconv.c b/src/lj_cconv.c
index f948002c..613f66e2 100644
--- a/src/lj_cconv.c
+++ b/src/lj_cconv.c
@@ -8,6 +8,7 @@
8#if LJ_HASFFI 8#if LJ_HASFFI
9 9
10#include "lj_err.h" 10#include "lj_err.h"
11#include "lj_buf.h"
11#include "lj_tab.h" 12#include "lj_tab.h"
12#include "lj_ctype.h" 13#include "lj_ctype.h"
13#include "lj_cdata.h" 14#include "lj_cdata.h"
@@ -621,6 +622,8 @@ void lj_cconv_ct_tv(CTState *cts, CType *d,
621 tmpptr = uddata(ud); 622 tmpptr = uddata(ud);
622 if (ud->udtype == UDTYPE_IO_FILE) 623 if (ud->udtype == UDTYPE_IO_FILE)
623 tmpptr = *(void **)tmpptr; 624 tmpptr = *(void **)tmpptr;
625 else if (ud->udtype == UDTYPE_BUFFER)
626 tmpptr = ((SBufExt *)tmpptr)->r;
624 } else if (tvislightud(o)) { 627 } else if (tvislightud(o)) {
625 tmpptr = lightudV(cts->g, o); 628 tmpptr = lightudV(cts->g, o);
626 } else if (tvisfunc(o)) { 629 } else if (tvisfunc(o)) {
diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index be23cd62..b0de5423 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -616,10 +616,12 @@ static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval)
616 sp = lj_ir_kptr(J, NULL); 616 sp = lj_ir_kptr(J, NULL);
617 } else if (tref_isudata(sp)) { 617 } else if (tref_isudata(sp)) {
618 GCudata *ud = udataV(sval); 618 GCudata *ud = udataV(sval);
619 if (ud->udtype == UDTYPE_IO_FILE) { 619 if (ud->udtype == UDTYPE_IO_FILE || ud->udtype == UDTYPE_BUFFER) {
620 TRef tr = emitir(IRT(IR_FLOAD, IRT_U8), sp, IRFL_UDATA_UDTYPE); 620 TRef tr = emitir(IRT(IR_FLOAD, IRT_U8), sp, IRFL_UDATA_UDTYPE);
621 emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, UDTYPE_IO_FILE)); 621 emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, ud->udtype));
622 sp = emitir(IRT(IR_FLOAD, IRT_PTR), sp, IRFL_UDATA_FILE); 622 sp = emitir(IRT(IR_FLOAD, IRT_PTR), sp,
623 ud->udtype == UDTYPE_IO_FILE ? IRFL_UDATA_FILE :
624 IRFL_UDATA_BUF_R);
623 } else { 625 } else {
624 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)));
625 } 627 }
diff --git a/src/lj_ctype.h b/src/lj_ctype.h
index 9589ef2a..700250df 100644
--- a/src/lj_ctype.h
+++ b/src/lj_ctype.h
@@ -298,6 +298,7 @@ typedef struct CTState {
298 _(P_VOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_VOID) \ 298 _(P_VOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_VOID) \
299 _(P_CVOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CVOID) \ 299 _(P_CVOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CVOID) \
300 _(P_CCHAR, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CCHAR) \ 300 _(P_CCHAR, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CCHAR) \
301 _(P_UINT8, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_UINT8) \
301 _(A_CCHAR, -1, CT_ARRAY, CTF_CONST|CTALIGN(0)|CTID_CCHAR) \ 302 _(A_CCHAR, -1, CT_ARRAY, CTF_CONST|CTALIGN(0)|CTID_CCHAR) \
302 _(CTYPEID, 4, CT_ENUM, CTALIGN(2)|CTID_INT32) \ 303 _(CTYPEID, 4, CT_ENUM, CTALIGN(2)|CTID_INT32) \
303 CTTYDEFP(_) \ 304 CTTYDEFP(_) \
diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h
index a6f638ce..af4a03dd 100644
--- a/src/lj_errmsg.h
+++ b/src/lj_errmsg.h
@@ -67,6 +67,7 @@ ERRDEF(PROTMT, "cannot change a protected metatable")
67ERRDEF(UNPACK, "too many results to unpack") 67ERRDEF(UNPACK, "too many results to unpack")
68ERRDEF(RDRSTR, "reader function must return a string") 68ERRDEF(RDRSTR, "reader function must return a string")
69ERRDEF(PRTOSTR, LUA_QL("tostring") " must return a string to " LUA_QL("print")) 69ERRDEF(PRTOSTR, LUA_QL("tostring") " must return a string to " LUA_QL("print"))
70ERRDEF(NUMRNG, "number out of range")
70ERRDEF(IDXRNG, "index out of range") 71ERRDEF(IDXRNG, "index out of range")
71ERRDEF(BASERNG, "base out of range") 72ERRDEF(BASERNG, "base out of range")
72ERRDEF(LVLRNG, "level out of range") 73ERRDEF(LVLRNG, "level out of range")
diff --git a/src/lj_gc.c b/src/lj_gc.c
index cfbce037..1f382ea0 100644
--- a/src/lj_gc.c
+++ b/src/lj_gc.c
@@ -65,6 +65,12 @@ static void gc_mark(global_State *g, GCobj *o)
65 gray2black(o); /* Userdata are never gray. */ 65 gray2black(o); /* Userdata are never gray. */
66 if (mt) gc_markobj(g, mt); 66 if (mt) gc_markobj(g, mt);
67 gc_markobj(g, tabref(gco2ud(o)->env)); 67 gc_markobj(g, tabref(gco2ud(o)->env));
68 if (LJ_HASBUFFER && gco2ud(o)->udtype == UDTYPE_BUFFER) {
69 SBufExt *sbx = (SBufExt *)uddata(gco2ud(o));
70 if (sbufiscow(sbx) && gcref(sbx->cowref) != NULL) {
71 gc_markobj(g, gcref(sbx->cowref));
72 }
73 }
68 } else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) { 74 } else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) {
69 GCupval *uv = gco2uv(o); 75 GCupval *uv = gco2uv(o);
70 gc_marktv(g, uvval(uv)); 76 gc_marktv(g, uvval(uv));
diff --git a/src/lj_ir.h b/src/lj_ir.h
index aacef2b4..f953ff0e 100644
--- a/src/lj_ir.h
+++ b/src/lj_ir.h
@@ -204,6 +204,7 @@ IRFPMDEF(FPMENUM)
204 _(UDATA_META, offsetof(GCudata, metatable)) \ 204 _(UDATA_META, offsetof(GCudata, metatable)) \
205 _(UDATA_UDTYPE, offsetof(GCudata, udtype)) \ 205 _(UDATA_UDTYPE, offsetof(GCudata, udtype)) \
206 _(UDATA_FILE, sizeof(GCudata)) \ 206 _(UDATA_FILE, sizeof(GCudata)) \
207 _(UDATA_BUF_R, sizeof(GCudata) + offsetof(SBufExt, r)) \
207 _(CDATA_CTYPEID, offsetof(GCcdata, ctypeid)) \ 208 _(CDATA_CTYPEID, offsetof(GCcdata, ctypeid)) \
208 _(CDATA_PTR, sizeof(GCcdata)) \ 209 _(CDATA_PTR, sizeof(GCcdata)) \
209 _(CDATA_INT, sizeof(GCcdata)) \ 210 _(CDATA_INT, sizeof(GCcdata)) \
diff --git a/src/lj_lib.c b/src/lj_lib.c
index a962ddc1..21e6a61d 100644
--- a/src/lj_lib.c
+++ b/src/lj_lib.c
@@ -16,6 +16,9 @@
16#include "lj_func.h" 16#include "lj_func.h"
17#include "lj_bc.h" 17#include "lj_bc.h"
18#include "lj_dispatch.h" 18#include "lj_dispatch.h"
19#if LJ_HASFFI
20#include "lj_ctype.h"
21#endif
19#include "lj_vm.h" 22#include "lj_vm.h"
20#include "lj_strscan.h" 23#include "lj_strscan.h"
21#include "lj_strfmt.h" 24#include "lj_strfmt.h"
@@ -301,3 +304,54 @@ int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst)
301 return def; 304 return def;
302} 305}
303 306
307/* -- Strict type checks -------------------------------------------------- */
308
309/* The following type checks do not coerce between strings and numbers.
310** And they handle plain int64_t/uint64_t FFI numbers, too.
311*/
312
313#if LJ_HASBUFFER
314GCstr *lj_lib_checkstrx(lua_State *L, int narg)
315{
316 TValue *o = L->base + narg-1;
317 if (!(o < L->top && tvisstr(o))) lj_err_argt(L, narg, LUA_TSTRING);
318 return strV(o);
319}
320
321int32_t lj_lib_checkintrange(lua_State *L, int narg, int32_t a, int32_t b)
322{
323 TValue *o = L->base + narg-1;
324 lj_assertL(b >= 0, "expected range must be non-negative");
325 if (o < L->top) {
326 if (LJ_LIKELY(tvisint(o))) {
327 int32_t i = intV(o);
328 if (i >= a && i <= b) return i;
329 } else if (LJ_LIKELY(tvisnum(o))) {
330 /* For performance reasons, this doesn't check for integerness or
331 ** integer overflow. Overflow detection still works, since all FPUs
332 ** return either MININT or MAXINT, which is then out of range.
333 */
334 int32_t i = (int32_t)numV(o);
335 if (i >= a && i <= b) return i;
336#if LJ_HASFFI
337 } else if (tviscdata(o)) {
338 GCcdata *cd = cdataV(o);
339 if (cd->ctypeid == CTID_INT64) {
340 int64_t i = *(int64_t *)cdataptr(cd);
341 if (i >= (int64_t)a && i <= (int64_t)b) return (int32_t)i;
342 } else if (cd->ctypeid == CTID_UINT64) {
343 uint64_t i = *(uint64_t *)cdataptr(cd);
344 if ((a < 0 || i >= (uint64_t)a) && i <= (uint64_t)b) return (int32_t)i;
345 }
346#endif
347 } else {
348 goto badtype;
349 }
350 lj_err_arg(L, narg, LJ_ERR_NUMRNG);
351 }
352badtype:
353 lj_err_argt(L, narg, LUA_TNUMBER);
354 return 0; /* unreachable */
355}
356#endif
357
diff --git a/src/lj_lib.h b/src/lj_lib.h
index 718d8eb4..f59e9ea2 100644
--- a/src/lj_lib.h
+++ b/src/lj_lib.h
@@ -46,6 +46,12 @@ LJ_FUNC GCtab *lj_lib_checktab(lua_State *L, int narg);
46LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg); 46LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg);
47LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst); 47LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst);
48 48
49#if LJ_HASBUFFER
50LJ_FUNC GCstr *lj_lib_checkstrx(lua_State *L, int narg);
51LJ_FUNC int32_t lj_lib_checkintrange(lua_State *L, int narg,
52 int32_t a, int32_t b);
53#endif
54
49/* Avoid including lj_frame.h. */ 55/* Avoid including lj_frame.h. */
50#if LJ_GC64 56#if LJ_GC64
51#define lj_lib_upvalue(L, n) \ 57#define lj_lib_upvalue(L, n) \
diff --git a/src/lj_meta.c b/src/lj_meta.c
index 07defa55..660dfec0 100644
--- a/src/lj_meta.c
+++ b/src/lj_meta.c
@@ -240,8 +240,8 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
240 int fromc = 0; 240 int fromc = 0;
241 if (left < 0) { left = -left; fromc = 1; } 241 if (left < 0) { left = -left; fromc = 1; }
242 do { 242 do {
243 if (!(tvisstr(top) || tvisnumber(top)) || 243 if (!(tvisstr(top) || tvisnumber(top) || tvisbuf(top)) ||
244 !(tvisstr(top-1) || tvisnumber(top-1))) { 244 !(tvisstr(top-1) || tvisnumber(top-1) || tvisbuf(top-1))) {
245 cTValue *mo = lj_meta_lookup(L, top-1, MM_concat); 245 cTValue *mo = lj_meta_lookup(L, top-1, MM_concat);
246 if (tvisnil(mo)) { 246 if (tvisnil(mo)) {
247 mo = lj_meta_lookup(L, top, MM_concat); 247 mo = lj_meta_lookup(L, top, MM_concat);
@@ -277,10 +277,12 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
277 ** next step: [...][CAT stack ............] 277 ** next step: [...][CAT stack ............]
278 */ 278 */
279 TValue *e, *o = top; 279 TValue *e, *o = top;
280 uint64_t tlen = tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; 280 uint64_t tlen = tvisstr(o) ? strV(o)->len :
281 tvisbuf(o) ? sbufxlen(bufV(o)) : STRFMT_MAXBUF_NUM;
281 SBuf *sb; 282 SBuf *sb;
282 do { 283 do {
283 o--; tlen += tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; 284 o--; tlen += tvisstr(o) ? strV(o)->len :
285 tvisbuf(o) ? sbufxlen(bufV(o)) : STRFMT_MAXBUF_NUM;
284 } while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1))); 286 } while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1)));
285 if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV); 287 if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV);
286 sb = lj_buf_tmp_(L); 288 sb = lj_buf_tmp_(L);
@@ -290,6 +292,9 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
290 GCstr *s = strV(o); 292 GCstr *s = strV(o);
291 MSize len = s->len; 293 MSize len = s->len;
292 lj_buf_putmem(sb, strdata(s), len); 294 lj_buf_putmem(sb, strdata(s), len);
295 } else if (tvisbuf(o)) {
296 SBufExt *sbx = bufV(o);
297 lj_buf_putmem(sb, sbx->r, sbufxlen(sbx));
293 } else if (tvisint(o)) { 298 } else if (tvisint(o)) {
294 lj_strfmt_putint(sb, intV(o)); 299 lj_strfmt_putint(sb, intV(o));
295 } else { 300 } else {
diff --git a/src/lj_obj.h b/src/lj_obj.h
index 9b691e49..0dae5fec 100644
--- a/src/lj_obj.h
+++ b/src/lj_obj.h
@@ -332,6 +332,7 @@ enum {
332 UDTYPE_USERDATA, /* Regular userdata. */ 332 UDTYPE_USERDATA, /* Regular userdata. */
333 UDTYPE_IO_FILE, /* I/O library FILE. */ 333 UDTYPE_IO_FILE, /* I/O library FILE. */
334 UDTYPE_FFI_CLIB, /* FFI C library namespace. */ 334 UDTYPE_FFI_CLIB, /* FFI C library namespace. */
335 UDTYPE_BUFFER, /* String buffer. */
335 UDTYPE__MAX 336 UDTYPE__MAX
336}; 337};
337 338
diff --git a/src/lj_serialize.c b/src/lj_serialize.c
index 4e76502a..49a25a7c 100644
--- a/src/lj_serialize.c
+++ b/src/lj_serialize.c
@@ -346,10 +346,7 @@ SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o)
346 346
347SBufExt * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o) 347SBufExt * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o)
348{ 348{
349 char *r = serialize_get(sbx->r, sbx, o); 349 sbx->r = serialize_get(sbx->r, sbx, o);
350 if (r != sbx->w)
351 lj_err_caller(sbufL(sbx), LJ_ERR_BUFFER_LEFTOV);
352 sbx->r = r;
353 return sbx; 350 return sbx;
354} 351}
355 352
diff --git a/src/lj_strfmt.c b/src/lj_strfmt.c
index a9541d41..5826b539 100644
--- a/src/lj_strfmt.c
+++ b/src/lj_strfmt.c
@@ -164,6 +164,10 @@ const char *lj_strfmt_wstrnum(lua_State *L, cTValue *o, MSize *lenp)
164 if (tvisstr(o)) { 164 if (tvisstr(o)) {
165 *lenp = strV(o)->len; 165 *lenp = strV(o)->len;
166 return strVdata(o); 166 return strVdata(o);
167 } else if (tvisbuf(o)) {
168 SBufExt *sbx = bufV(o);
169 *lenp = sbufxlen(sbx);
170 return sbx->r;
167 } else if (tvisint(o)) { 171 } else if (tvisint(o)) {
168 sb = lj_strfmt_putint(lj_buf_tmp_(L), intV(o)); 172 sb = lj_strfmt_putint(lj_buf_tmp_(L), intV(o));
169 } else if (tvisnum(o)) { 173 } else if (tvisnum(o)) {
@@ -421,6 +425,10 @@ int lj_strfmt_putarg(lua_State *L, SBuf *sb, int arg, int retry)
421 if (LJ_LIKELY(tvisstr(o))) { 425 if (LJ_LIKELY(tvisstr(o))) {
422 len = strV(o)->len; 426 len = strV(o)->len;
423 s = strVdata(o); 427 s = strVdata(o);
428 } else if (tvisbuf(o)) {
429 SBufExt *sbx = bufV(o);
430 len = sbufxlen(sbx);
431 s = sbx->r;
424 } else { 432 } else {
425 GCstr *str = lj_strfmt_obj(L, o); 433 GCstr *str = lj_strfmt_obj(L, o);
426 len = str->len; 434 len = str->len;