aboutsummaryrefslogtreecommitdiff
path: root/src/lj_buf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_buf.c')
-rw-r--r--src/lj_buf.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/src/lj_buf.c b/src/lj_buf.c
new file mode 100644
index 00000000..01dcad5b
--- /dev/null
+++ b/src/lj_buf.c
@@ -0,0 +1,303 @@
1/*
2** Buffer handling.
3** Copyright (C) 2005-2025 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lj_buf_c
7#define LUA_CORE
8
9#include "lj_obj.h"
10#include "lj_gc.h"
11#include "lj_err.h"
12#include "lj_buf.h"
13#include "lj_str.h"
14#include "lj_tab.h"
15#include "lj_strfmt.h"
16
17/* -- Buffer management --------------------------------------------------- */
18
19static void buf_grow(SBuf *sb, MSize sz)
20{
21 MSize osz = sbufsz(sb), len = sbuflen(sb), nsz = osz;
22 char *b;
23 GCSize flag;
24 if (nsz < LJ_MIN_SBUF) nsz = LJ_MIN_SBUF;
25 while (nsz < sz) nsz += nsz;
26 flag = sbufflag(sb);
27 if ((flag & SBUF_FLAG_COW)) { /* Copy-on-write semantics. */
28 lj_assertG_(G(sbufL(sb)), sb->w == sb->e, "bad SBuf COW");
29 b = (char *)lj_mem_new(sbufL(sb), nsz);
30 setsbufflag(sb, flag & ~(GCSize)SBUF_FLAG_COW);
31 setgcrefnull(sbufX(sb)->cowref);
32 memcpy(b, sb->b, osz);
33 } else {
34 b = (char *)lj_mem_realloc(sbufL(sb), sb->b, osz, nsz);
35 }
36 if ((flag & SBUF_FLAG_EXT)) {
37 sbufX(sb)->r = sbufX(sb)->r - sb->b + b; /* Adjust read pointer, too. */
38 }
39 /* Adjust buffer pointers. */
40 sb->b = b;
41 sb->w = b + len;
42 sb->e = b + nsz;
43 if ((flag & SBUF_FLAG_BORROW)) { /* Adjust borrowed buffer pointers. */
44 SBuf *bsb = mref(sbufX(sb)->bsb, SBuf);
45 bsb->b = b;
46 bsb->w = b + len;
47 bsb->e = b + nsz;
48 }
49}
50
51LJ_NOINLINE char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz)
52{
53 lj_assertG_(G(sbufL(sb)), sz > sbufsz(sb), "SBuf overflow");
54 if (LJ_UNLIKELY(sz > LJ_MAX_BUF))
55 lj_err_mem(sbufL(sb));
56 buf_grow(sb, sz);
57 return sb->b;
58}
59
60LJ_NOINLINE char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz)
61{
62 if (sbufisext(sb)) {
63 SBufExt *sbx = (SBufExt *)sb;
64 MSize len = sbufxlen(sbx);
65 if (LJ_UNLIKELY(sz > LJ_MAX_BUF || len + sz > LJ_MAX_BUF))
66 lj_err_mem(sbufL(sbx));
67 if (len + sz > sbufsz(sbx)) { /* Must grow. */
68 buf_grow((SBuf *)sbx, len + sz);
69 } else if (sbufiscow(sb) || sbufxslack(sbx) < (sbufsz(sbx) >> 3)) {
70 /* Also grow to avoid excessive compactions, if slack < size/8. */
71 buf_grow((SBuf *)sbx, sbuflen(sbx) + sz); /* Not sbufxlen! */
72 return sbx->w;
73 }
74 if (sbx->r != sbx->b) { /* Compact by moving down. */
75 memmove(sbx->b, sbx->r, len);
76 sbx->r = sbx->b;
77 sbx->w = sbx->b + len;
78 lj_assertG_(G(sbufL(sbx)), len + sz <= sbufsz(sbx), "bad SBuf compact");
79 }
80 } else {
81 MSize len = sbuflen(sb);
82 lj_assertG_(G(sbufL(sb)), sz > sbufleft(sb), "SBuf overflow");
83 if (LJ_UNLIKELY(sz > LJ_MAX_BUF || len + sz > LJ_MAX_BUF))
84 lj_err_mem(sbufL(sb));
85 buf_grow(sb, len + sz);
86 }
87 return sb->w;
88}
89
90void LJ_FASTCALL lj_buf_shrink(lua_State *L, SBuf *sb)
91{
92 char *b = sb->b;
93 MSize osz = (MSize)(sb->e - b);
94 if (osz > 2*LJ_MIN_SBUF) {
95 b = lj_mem_realloc(L, b, osz, (osz >> 1));
96 sb->w = sb->b = b; /* Not supposed to keep data across shrinks. */
97 sb->e = b + (osz >> 1);
98 }
99 lj_assertG_(G(sbufL(sb)), !sbufisext(sb), "YAGNI shrink SBufExt");
100}
101
102char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz)
103{
104 SBuf *sb = &G(L)->tmpbuf;
105 setsbufL(sb, L);
106 return lj_buf_need(sb, sz);
107}
108
109#if LJ_HASBUFFER && LJ_HASJIT
110void lj_bufx_set(SBufExt *sbx, const char *p, MSize len, GCobj *ref)
111{
112 lua_State *L = sbufL(sbx);
113 lj_bufx_free(L, sbx);
114 lj_bufx_set_cow(L, sbx, p, len);
115 setgcref(sbx->cowref, ref);
116 lj_gc_objbarrier(L, (GCudata *)sbx - 1, ref);
117}
118
119#if LJ_HASFFI
120MSize LJ_FASTCALL lj_bufx_more(SBufExt *sbx, MSize sz)
121{
122 lj_buf_more((SBuf *)sbx, sz);
123 return sbufleft(sbx);
124}
125#endif
126#endif
127
128/* -- Low-level buffer put operations ------------------------------------- */
129
130SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len)
131{
132 char *w = lj_buf_more(sb, len);
133 w = lj_buf_wmem(w, q, len);
134 sb->w = w;
135 return sb;
136}
137
138#if LJ_HASJIT || LJ_HASFFI
139static LJ_NOINLINE SBuf * LJ_FASTCALL lj_buf_putchar2(SBuf *sb, int c)
140{
141 char *w = lj_buf_more2(sb, 1);
142 *w++ = (char)c;
143 sb->w = w;
144 return sb;
145}
146
147SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c)
148{
149 char *w = sb->w;
150 if (LJ_LIKELY(w < sb->e)) {
151 *w++ = (char)c;
152 sb->w = w;
153 return sb;
154 }
155 return lj_buf_putchar2(sb, c);
156}
157#endif
158
159SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s)
160{
161 MSize len = s->len;
162 char *w = lj_buf_more(sb, len);
163 w = lj_buf_wmem(w, strdata(s), len);
164 sb->w = w;
165 return sb;
166}
167
168/* -- High-level buffer put operations ------------------------------------ */
169
170SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s)
171{
172 MSize len = s->len;
173 char *w = lj_buf_more(sb, len), *e = w+len;
174 const char *q = strdata(s)+len-1;
175 while (w < e)
176 *w++ = *q--;
177 sb->w = w;
178 return sb;
179}
180
181SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s)
182{
183 MSize len = s->len;
184 char *w = lj_buf_more(sb, len), *e = w+len;
185 const char *q = strdata(s);
186 for (; w < e; w++, q++) {
187 uint32_t c = *(unsigned char *)q;
188#if LJ_TARGET_PPC
189 *w = c + ((c >= 'A' && c <= 'Z') << 5);
190#else
191 if (c >= 'A' && c <= 'Z') c += 0x20;
192 *w = c;
193#endif
194 }
195 sb->w = w;
196 return sb;
197}
198
199SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s)
200{
201 MSize len = s->len;
202 char *w = lj_buf_more(sb, len), *e = w+len;
203 const char *q = strdata(s);
204 for (; w < e; w++, q++) {
205 uint32_t c = *(unsigned char *)q;
206#if LJ_TARGET_PPC
207 *w = c - ((c >= 'a' && c <= 'z') << 5);
208#else
209 if (c >= 'a' && c <= 'z') c -= 0x20;
210 *w = c;
211#endif
212 }
213 sb->w = w;
214 return sb;
215}
216
217SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep)
218{
219 MSize len = s->len;
220 if (rep > 0 && len) {
221 uint64_t tlen = (uint64_t)rep * len;
222 char *w;
223 if (LJ_UNLIKELY(tlen > LJ_MAX_STR))
224 lj_err_mem(sbufL(sb));
225 w = lj_buf_more(sb, (MSize)tlen);
226 if (len == 1) { /* Optimize a common case. */
227 uint32_t c = strdata(s)[0];
228 do { *w++ = c; } while (--rep > 0);
229 } else {
230 const char *e = strdata(s) + len;
231 do {
232 const char *q = strdata(s);
233 do { *w++ = *q++; } while (q < e);
234 } while (--rep > 0);
235 }
236 sb->w = w;
237 }
238 return sb;
239}
240
241SBuf *lj_buf_puttab(SBuf *sb, GCtab *t, GCstr *sep, int32_t i, int32_t e)
242{
243 MSize seplen = sep ? sep->len : 0;
244 if (i <= e) {
245 for (;;) {
246 cTValue *o = lj_tab_getint(t, i);
247 char *w;
248 if (!o) {
249 badtype: /* Error: bad element type. */
250 sb->w = (char *)(intptr_t)i; /* Store failing index. */
251 return NULL;
252 } else if (tvisstr(o)) {
253 MSize len = strV(o)->len;
254 w = lj_buf_wmem(lj_buf_more(sb, len + seplen), strVdata(o), len);
255 } else if (tvisint(o)) {
256 w = lj_strfmt_wint(lj_buf_more(sb, STRFMT_MAXBUF_INT+seplen), intV(o));
257 } else if (tvisnum(o)) {
258 w = lj_buf_more(lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)), seplen);
259 } else {
260 goto badtype;
261 }
262 if (i++ == e) {
263 sb->w = w;
264 break;
265 }
266 if (seplen) w = lj_buf_wmem(w, strdata(sep), seplen);
267 sb->w = w;
268 }
269 }
270 return sb;
271}
272
273/* -- Miscellaneous buffer operations ------------------------------------- */
274
275GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb)
276{
277 return lj_str_new(sbufL(sb), sb->b, sbuflen(sb));
278}
279
280/* Concatenate two strings. */
281GCstr *lj_buf_cat2str(lua_State *L, GCstr *s1, GCstr *s2)
282{
283 MSize len1 = s1->len, len2 = s2->len;
284 char *buf = lj_buf_tmp(L, len1 + len2);
285 memcpy(buf, strdata(s1), len1);
286 memcpy(buf+len1, strdata(s2), len2);
287 return lj_str_new(L, buf, len1 + len2);
288}
289
290/* Read ULEB128 from buffer. */
291uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp)
292{
293 const uint8_t *w = (const uint8_t *)*pp;
294 uint32_t v = *w++;
295 if (LJ_UNLIKELY(v >= 0x80)) {
296 int sh = 0;
297 v &= 0x7f;
298 do { v |= ((*w & 0x7f) << (sh += 7)); } while (*w++ >= 0x80);
299 }
300 *pp = (const char *)w;
301 return v;
302}
303