Merge branch 'master' into v2.1
[luajit-2.0.git] / src / lj_buf.c
blobae2ccd82d1c235d06ab3bae1930dc03748add75f
1 /*
2 ** Buffer handling.
3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
4 */
6 #define lj_buf_c
7 #define LUA_CORE
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"
17 /* -- Buffer management --------------------------------------------------- */
19 static void buf_grow(SBuf *sb, MSize sz)
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);
36 if ((flag & SBUF_FLAG_EXT)) {
37 sbufX(sb)->r = sbufX(sb)->r - sb->b + b; /* Adjust read pointer, too. */
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;
51 LJ_NOINLINE char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz)
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;
60 LJ_NOINLINE char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz)
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;
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");
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);
87 return sb->w;
90 void LJ_FASTCALL lj_buf_shrink(lua_State *L, SBuf *sb)
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);
101 lj_assertG_(G(sbufL(sb)), !sbufisext(sb), "YAGNI shrink SBufExt");
104 char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz)
106 SBuf *sb = &G(L)->tmpbuf;
107 setsbufL(sb, L);
108 return lj_buf_need(sb, sz);
111 #if LJ_HASBUFFER && LJ_HASJIT
112 void lj_bufx_set(SBufExt *sbx, const char *p, MSize len, GCobj *ref)
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);
121 #if LJ_HASFFI
122 MSize LJ_FASTCALL lj_bufx_more(SBufExt *sbx, MSize sz)
124 lj_buf_more((SBuf *)sbx, sz);
125 return sbufleft(sbx);
127 #endif
128 #endif
130 /* -- Low-level buffer put operations ------------------------------------- */
132 SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len)
134 char *w = lj_buf_more(sb, len);
135 w = lj_buf_wmem(w, q, len);
136 sb->w = w;
137 return sb;
140 #if LJ_HASJIT || LJ_HASFFI
141 static LJ_NOINLINE SBuf * LJ_FASTCALL lj_buf_putchar2(SBuf *sb, int c)
143 char *w = lj_buf_more2(sb, 1);
144 *w++ = (char)c;
145 sb->w = w;
146 return sb;
149 SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c)
151 char *w = sb->w;
152 if (LJ_LIKELY(w < sb->e)) {
153 *w++ = (char)c;
154 sb->w = w;
155 return sb;
157 return lj_buf_putchar2(sb, c);
159 #endif
161 SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s)
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;
170 /* -- High-level buffer put operations ------------------------------------ */
172 SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s)
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;
183 SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s)
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
197 sb->w = w;
198 return sb;
201 SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s)
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
215 sb->w = w;
216 return sb;
219 SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep)
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);
238 sb->w = w;
240 return sb;
243 SBuf *lj_buf_puttab(SBuf *sb, GCtab *t, GCstr *sep, int32_t i, int32_t e)
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;
264 if (i++ == e) {
265 sb->w = w;
266 break;
268 if (seplen) w = lj_buf_wmem(w, strdata(sep), seplen);
269 sb->w = w;
272 return sb;
275 /* -- Miscellaneous buffer operations ------------------------------------- */
277 GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb)
279 return lj_str_new(sbufL(sb), sb->b, sbuflen(sb));
282 /* Concatenate two strings. */
283 GCstr *lj_buf_cat2str(lua_State *L, GCstr *s1, GCstr *s2)
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);
292 /* Read ULEB128 from buffer. */
293 uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp)
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);
302 *pp = (const char *)w;
303 return v;