diff options
Diffstat (limited to 'src/lj_buf.c')
-rw-r--r-- | src/lj_buf.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/src/lj_buf.c b/src/lj_buf.c index 66a096fb..889ccbca 100644 --- a/src/lj_buf.c +++ b/src/lj_buf.c | |||
@@ -20,12 +20,32 @@ static void buf_grow(SBuf *sb, MSize sz) | |||
20 | { | 20 | { |
21 | MSize osz = sbufsz(sb), len = sbuflen(sb), nsz = osz; | 21 | MSize osz = sbufsz(sb), len = sbuflen(sb), nsz = osz; |
22 | char *b; | 22 | char *b; |
23 | GCSize flag; | ||
23 | if (nsz < LJ_MIN_SBUF) nsz = LJ_MIN_SBUF; | 24 | if (nsz < LJ_MIN_SBUF) nsz = LJ_MIN_SBUF; |
24 | while (nsz < sz) nsz += nsz; | 25 | while (nsz < sz) nsz += nsz; |
25 | b = (char *)lj_mem_realloc(sbufL(sb), sb->b, osz, 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. */ | ||
26 | sb->b = b; | 40 | sb->b = b; |
27 | sb->w = b + len; | 41 | sb->w = b + len; |
28 | sb->e = b + nsz; | 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 | } | ||
29 | } | 49 | } |
30 | 50 | ||
31 | LJ_NOINLINE char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz) | 51 | LJ_NOINLINE char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz) |
@@ -39,11 +59,31 @@ LJ_NOINLINE char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz) | |||
39 | 59 | ||
40 | LJ_NOINLINE char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz) | 60 | LJ_NOINLINE char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz) |
41 | { | 61 | { |
42 | MSize len = sbuflen(sb); | 62 | if (sbufisext(sb)) { |
43 | lj_assertG_(G(sbufL(sb)), sz > sbufleft(sb), "SBuf overflow"); | 63 | SBufExt *sbx = (SBufExt *)sb; |
44 | if (LJ_UNLIKELY(sz > LJ_MAX_BUF || len + sz > LJ_MAX_BUF)) | 64 | MSize len = sbufxlen(sbx); |
45 | lj_err_mem(sbufL(sb)); | 65 | if (LJ_UNLIKELY(sz > LJ_MAX_BUF || len + sz > LJ_MAX_BUF)) |
46 | buf_grow(sb, len + sz); | 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 | } | ||
47 | return sb->w; | 87 | return sb->w; |
48 | } | 88 | } |
49 | 89 | ||
@@ -58,6 +98,7 @@ void LJ_FASTCALL lj_buf_shrink(lua_State *L, SBuf *sb) | |||
58 | sb->w = b + n; | 98 | sb->w = b + n; |
59 | sb->e = b + (osz >> 1); | 99 | sb->e = b + (osz >> 1); |
60 | } | 100 | } |
101 | lj_assertG_(G(sbufL(sb)), !sbufisext(sb), "YAGNI shrink SBufExt"); | ||
61 | } | 102 | } |
62 | 103 | ||
63 | char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz) | 104 | char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz) |