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.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/src/lj_buf.c b/src/lj_buf.c
new file mode 100644
index 00000000..5a03ea6a
--- /dev/null
+++ b/src/lj_buf.c
@@ -0,0 +1,305 @@
1/*
2** Buffer handling.
3** Copyright (C) 2005-2022 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 (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 MSize n = (MSize)(sb->w - b);
96 b = lj_mem_realloc(L, b, osz, (osz >> 1));
97 sb->b = b;
98 sb->w = b + n;
99 sb->e = b + (osz >> 1);
100 }
101 lj_assertG_(G(sbufL(sb)), !sbufisext(sb), "YAGNI shrink SBufExt");
102}
103
104char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz)
105{
106 SBuf *sb = &G(L)->tmpbuf;
107 setsbufL(sb, L);
108 return lj_buf_need(sb, sz);
109}
110
111#if LJ_HASBUFFER && LJ_HASJIT
112void lj_bufx_set(SBufExt *sbx, const char *p, MSize len, GCobj *ref)
113{
114 lua_State *L = sbufL(sbx);
115 lj_bufx_free(L, sbx);
116 lj_bufx_set_cow(L, sbx, p, len);
117 setgcref(sbx->cowref, ref);
118 lj_gc_objbarrier(L, (GCudata *)sbx - 1, ref);
119}
120
121#if LJ_HASFFI
122MSize LJ_FASTCALL lj_bufx_more(SBufExt *sbx, MSize sz)
123{
124 lj_buf_more((SBuf *)sbx, sz);
125 return sbufleft(sbx);
126}
127#endif
128#endif
129
130/* -- Low-level buffer put operations ------------------------------------- */
131
132SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len)
133{
134 char *w = lj_buf_more(sb, len);
135 w = lj_buf_wmem(w, q, len);
136 sb->w = w;
137 return sb;
138}
139
140#if LJ_HASJIT || LJ_HASFFI
141static LJ_NOINLINE SBuf * LJ_FASTCALL lj_buf_putchar2(SBuf *sb, int c)
142{
143 char *w = lj_buf_more2(sb, 1);
144 *w++ = (char)c;
145 sb->w = w;
146 return sb;
147}
148
149SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c)
150{
151 char *w = sb->w;
152 if (LJ_LIKELY(w < sb->e)) {
153 *w++ = (char)c;
154 sb->w = w;
155 return sb;
156 }
157 return lj_buf_putchar2(sb, c);
158}
159#endif
160
161SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s)
162{
163 MSize len = s->len;
164 char *w = lj_buf_more(sb, len);
165 w = lj_buf_wmem(w, strdata(s), len);
166 sb->w = w;
167 return sb;
168}
169
170/* -- High-level buffer put operations ------------------------------------ */
171
172SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s)
173{
174 MSize len = s->len;
175 char *w = lj_buf_more(sb, len), *e = w+len;
176 const char *q = strdata(s)+len-1;
177 while (w < e)
178 *w++ = *q--;
179 sb->w = w;
180 return sb;
181}
182
183SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s)
184{
185 MSize len = s->len;
186 char *w = lj_buf_more(sb, len), *e = w+len;
187 const char *q = strdata(s);
188 for (; w < e; w++, q++) {
189 uint32_t c = *(unsigned char *)q;
190#if LJ_TARGET_PPC
191 *w = c + ((c >= 'A' && c <= 'Z') << 5);
192#else
193 if (c >= 'A' && c <= 'Z') c += 0x20;
194 *w = c;
195#endif
196 }
197 sb->w = w;
198 return sb;
199}
200
201SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s)
202{
203 MSize len = s->len;
204 char *w = lj_buf_more(sb, len), *e = w+len;
205 const char *q = strdata(s);
206 for (; w < e; w++, q++) {
207 uint32_t c = *(unsigned char *)q;
208#if LJ_TARGET_PPC
209 *w = c - ((c >= 'a' && c <= 'z') << 5);
210#else
211 if (c >= 'a' && c <= 'z') c -= 0x20;
212 *w = c;
213#endif
214 }
215 sb->w = w;
216 return sb;
217}
218
219SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep)
220{
221 MSize len = s->len;
222 if (rep > 0 && len) {
223 uint64_t tlen = (uint64_t)rep * len;
224 char *w;
225 if (LJ_UNLIKELY(tlen > LJ_MAX_STR))
226 lj_err_mem(sbufL(sb));
227 w = lj_buf_more(sb, (MSize)tlen);
228 if (len == 1) { /* Optimize a common case. */
229 uint32_t c = strdata(s)[0];
230 do { *w++ = c; } while (--rep > 0);
231 } else {
232 const char *e = strdata(s) + len;
233 do {
234 const char *q = strdata(s);
235 do { *w++ = *q++; } while (q < e);
236 } while (--rep > 0);
237 }
238 sb->w = w;
239 }
240 return sb;
241}
242
243SBuf *lj_buf_puttab(SBuf *sb, GCtab *t, GCstr *sep, int32_t i, int32_t e)
244{
245 MSize seplen = sep ? sep->len : 0;
246 if (i <= e) {
247 for (;;) {
248 cTValue *o = lj_tab_getint(t, i);
249 char *w;
250 if (!o) {
251 badtype: /* Error: bad element type. */
252 sb->w = (char *)(intptr_t)i; /* Store failing index. */
253 return NULL;
254 } else if (tvisstr(o)) {
255 MSize len = strV(o)->len;
256 w = lj_buf_wmem(lj_buf_more(sb, len + seplen), strVdata(o), len);
257 } else if (tvisint(o)) {
258 w = lj_strfmt_wint(lj_buf_more(sb, STRFMT_MAXBUF_INT+seplen), intV(o));
259 } else if (tvisnum(o)) {
260 w = lj_buf_more(lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)), seplen);
261 } else {
262 goto badtype;
263 }
264 if (i++ == e) {
265 sb->w = w;
266 break;
267 }
268 if (seplen) w = lj_buf_wmem(w, strdata(sep), seplen);
269 sb->w = w;
270 }
271 }
272 return sb;
273}
274
275/* -- Miscellaneous buffer operations ------------------------------------- */
276
277GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb)
278{
279 return lj_str_new(sbufL(sb), sb->b, sbuflen(sb));
280}
281
282/* Concatenate two strings. */
283GCstr *lj_buf_cat2str(lua_State *L, GCstr *s1, GCstr *s2)
284{
285 MSize len1 = s1->len, len2 = s2->len;
286 char *buf = lj_buf_tmp(L, len1 + len2);
287 memcpy(buf, strdata(s1), len1);
288 memcpy(buf+len1, strdata(s2), len2);
289 return lj_str_new(L, buf, len1 + len2);
290}
291
292/* Read ULEB128 from buffer. */
293uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp)
294{
295 const uint8_t *w = (const uint8_t *)*pp;
296 uint32_t v = *w++;
297 if (LJ_UNLIKELY(v >= 0x80)) {
298 int sh = 0;
299 v &= 0x7f;
300 do { v |= ((*w & 0x7f) << (sh += 7)); } while (*w++ >= 0x80);
301 }
302 *pp = (const char *)w;
303 return v;
304}
305