commit 3b57e37e4821ddce4756428956b7e9f4969efa4c
parent 024f9064f1b43758eb36aba52547edc0312bf4ba
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Fri, 10 Nov 2023 12:35:21 -0300
Fixed buffers save long strings as external.
Diffstat:
4 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/ldump.c b/ldump.c
@@ -126,7 +126,7 @@ static void dumpString (DumpState *D, TString *ts) {
size_t size;
const char *s = getlstr(ts, size);
dumpSize(D, size + 2);
- dumpVector(D, s, size);
+ dumpVector(D, s, size + 1); /* include ending '\0' */
D->nstr++; /* one more saved string */
setsvalue(D->L, &key, ts); /* the string is the key */
setivalue(&value, D->nstr); /* its index is the value */
diff --git a/lundump.c b/lundump.c
@@ -147,17 +147,24 @@ static TString *loadStringN (LoadState *S, Proto *p) {
luaH_getint(S->h, idx, &stv);
return tsvalue(&stv);
}
- else if (size -= 2, size <= LUAI_MAXSHORTLEN) { /* short string? */
- char buff[LUAI_MAXSHORTLEN];
- loadVector(S, buff, size); /* load string into buffer */
+ else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */
+ char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */
+ loadVector(S, buff, size + 1); /* load string into buffer */
ts = luaS_newlstr(L, buff, size); /* create string */
}
else { /* long string */
- 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 */
- L->top.p--; /* pop string */
+ if (S->fixed) { /* for a fixed buffer, use a fixed string */
+ const char *s = getaddr(S, size + 1, char); /* get content address */
+ ts = luaS_newextlstr(L, s, size, NULL, NULL);
+ }
+ 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);
S->nstr++; /* add string to list of saved strings */
diff --git a/manual/manual.of b/manual/manual.of
@@ -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.
A fixed buffer means that the address returned by the reader function
-should contain the chunk until everything created by the chunk has
-been collected.
+will contain the chunk until everything created by the chunk has
+been collected;
+therefore, Lua can avoid copying to internal structures
+some parts of the chunk.
(In general, a fixed buffer would keep the chunk
as its contents until the end of the program,
for instance with the chunk in ROM.)
diff --git a/testes/api.lua b/testes/api.lua
@@ -528,13 +528,15 @@ do
local N = 1000
-- create a somewhat "large" source
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)
-- give chunk an explicit name to avoid using source as name
source = load(source, "name1")
-- dump without debug information
source = string.dump(source, true)
- -- each "X=X+1" generates 4 opcodes with 4 bytes each
- assert(#source > N * 4 * 4)
+ -- each "X=X+1" generates 4 opcodes with 4 bytes each, plus the string
+ assert(#source > N * 4 * 4 + N)
collectgarbage(); collectgarbage()
local m1 = collectgarbage"count" * 1024
-- load dump using fixed buffer
@@ -544,9 +546,11 @@ do
]], source)
collectgarbage()
local m2 = collectgarbage"count" * 1024
- -- load used fewer than 300 bytes
- assert(m2 > m1 and m2 - m1 < 300)
- X = 0; code(); assert(X == N); X = nil
+ -- load used fewer than 350 bytes. Code alone has more than 3*N bytes,
+ -- and string literal has N bytes. Both were not loaded.
+ assert(m2 > m1 and m2 - m1 < 350)
+ X = 0; code(); assert(X == N and Y == string.rep("a", N))
+ X = nil; Y = nil
end