Fixed buffers save long strings as external.

This commit is contained in:
Roberto Ierusalimschy
2023-11-10 12:35:48 -03:00
parent 024f9064f1
commit 3b57e37e48
4 changed files with 29 additions and 16 deletions

View File

@@ -126,7 +126,7 @@ static void dumpString (DumpState *D, TString *ts) {
size_t size; size_t size;
const char *s = getlstr(ts, size); const char *s = getlstr(ts, size);
dumpSize(D, size + 2); dumpSize(D, size + 2);
dumpVector(D, s, size); dumpVector(D, s, size + 1); /* include ending '\0' */
D->nstr++; /* one more saved string */ D->nstr++; /* one more saved string */
setsvalue(D->L, &key, ts); /* the string is the key */ setsvalue(D->L, &key, ts); /* the string is the key */
setivalue(&value, D->nstr); /* its index is the value */ setivalue(&value, D->nstr); /* its index is the value */

View File

@@ -147,17 +147,24 @@ static TString *loadStringN (LoadState *S, Proto *p) {
luaH_getint(S->h, idx, &stv); luaH_getint(S->h, idx, &stv);
return tsvalue(&stv); return tsvalue(&stv);
} }
else if (size -= 2, size <= LUAI_MAXSHORTLEN) { /* short string? */ else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */
char buff[LUAI_MAXSHORTLEN]; char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */
loadVector(S, buff, size); /* load string into buffer */ loadVector(S, buff, size + 1); /* load string into buffer */
ts = luaS_newlstr(L, buff, size); /* create string */ ts = luaS_newlstr(L, buff, size); /* create string */
} }
else { /* long string */ else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */ if (S->fixed) { /* for a fixed buffer, use a fixed string */
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ const char *s = getaddr(S, size + 1, char); /* get content address */
luaD_inctop(L); ts = luaS_newextlstr(L, s, size, NULL, NULL);
loadVector(S, getlngstr(ts), size); /* load directly in final place */ }
L->top.p--; /* pop string */ else { /* create internal copy */
ts = luaS_createlngstrobj(L, size); /* create string */
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
loadVector(S, getlngstr(ts), size); /* load directly in final place */
loadByte(S); /* skip ending '\0' */
L->top.p--; /* pop string */
}
} }
luaC_objbarrier(L, p, ts); luaC_objbarrier(L, p, ts);
S->nstr++; /* add string to list of saved strings */ S->nstr++; /* add string to list of saved strings */

View File

@@ -3651,8 +3651,10 @@ Moreover, it may have a @Char{B} instead of a @Char{b},
meaning a @emphx{fixed buffer} with the binary dump. meaning a @emphx{fixed buffer} with the binary dump.
A fixed buffer means that the address returned by the reader function A fixed buffer means that the address returned by the reader function
should contain the chunk until everything created by the chunk has will contain the chunk until everything created by the chunk has
been collected. been collected;
therefore, Lua can avoid copying to internal structures
some parts of the chunk.
(In general, a fixed buffer would keep the chunk (In general, a fixed buffer would keep the chunk
as its contents until the end of the program, as its contents until the end of the program,
for instance with the chunk in ROM.) for instance with the chunk in ROM.)

View File

@@ -528,13 +528,15 @@ do
local N = 1000 local N = 1000
-- create a somewhat "large" source -- create a somewhat "large" source
for i = 1, N do source[i] = "X = X + 1; " end for i = 1, N do source[i] = "X = X + 1; " end
-- add a long string to the source
source[#source + 1] = string.format("Y = '%s'", string.rep("a", N));
source = table.concat(source) source = table.concat(source)
-- give chunk an explicit name to avoid using source as name -- give chunk an explicit name to avoid using source as name
source = load(source, "name1") source = load(source, "name1")
-- dump without debug information -- dump without debug information
source = string.dump(source, true) source = string.dump(source, true)
-- each "X=X+1" generates 4 opcodes with 4 bytes each -- each "X=X+1" generates 4 opcodes with 4 bytes each, plus the string
assert(#source > N * 4 * 4) assert(#source > N * 4 * 4 + N)
collectgarbage(); collectgarbage() collectgarbage(); collectgarbage()
local m1 = collectgarbage"count" * 1024 local m1 = collectgarbage"count" * 1024
-- load dump using fixed buffer -- load dump using fixed buffer
@@ -544,9 +546,11 @@ do
]], source) ]], source)
collectgarbage() collectgarbage()
local m2 = collectgarbage"count" * 1024 local m2 = collectgarbage"count" * 1024
-- load used fewer than 300 bytes -- load used fewer than 350 bytes. Code alone has more than 3*N bytes,
assert(m2 > m1 and m2 - m1 < 300) -- and string literal has N bytes. Both were not loaded.
X = 0; code(); assert(X == N); X = nil assert(m2 > m1 and m2 - m1 < 350)
X = 0; code(); assert(X == N and Y == string.rep("a", N))
X = nil; Y = nil
end end