diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-10 12:35:48 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-10 12:35:48 -0300 |
commit | 3b57e37e4821ddce4756428956b7e9f4969efa4c (patch) | |
tree | a0bd071341349d964d98f55e7c2be8860792ff1f | |
parent | 024f9064f1b43758eb36aba52547edc0312bf4ba (diff) | |
download | lua-3b57e37e4821ddce4756428956b7e9f4969efa4c.tar.gz lua-3b57e37e4821ddce4756428956b7e9f4969efa4c.tar.bz2 lua-3b57e37e4821ddce4756428956b7e9f4969efa4c.zip |
Fixed buffers save long strings as external.
-rw-r--r-- | ldump.c | 2 | ||||
-rw-r--r-- | lundump.c | 23 | ||||
-rw-r--r-- | manual/manual.of | 6 | ||||
-rw-r--r-- | testes/api.lua | 14 |
4 files changed, 29 insertions, 16 deletions
@@ -126,7 +126,7 @@ static void dumpString (DumpState *D, TString *ts) { | |||
126 | size_t size; | 126 | size_t size; |
127 | const char *s = getlstr(ts, size); | 127 | const char *s = getlstr(ts, size); |
128 | dumpSize(D, size + 2); | 128 | dumpSize(D, size + 2); |
129 | dumpVector(D, s, size); | 129 | dumpVector(D, s, size + 1); /* include ending '\0' */ |
130 | D->nstr++; /* one more saved string */ | 130 | D->nstr++; /* one more saved string */ |
131 | setsvalue(D->L, &key, ts); /* the string is the key */ | 131 | setsvalue(D->L, &key, ts); /* the string is the key */ |
132 | setivalue(&value, D->nstr); /* its index is the value */ | 132 | setivalue(&value, D->nstr); /* its index is the value */ |
@@ -147,17 +147,24 @@ static TString *loadStringN (LoadState *S, Proto *p) { | |||
147 | luaH_getint(S->h, idx, &stv); | 147 | luaH_getint(S->h, idx, &stv); |
148 | return tsvalue(&stv); | 148 | return tsvalue(&stv); |
149 | } | 149 | } |
150 | else if (size -= 2, size <= LUAI_MAXSHORTLEN) { /* short string? */ | 150 | else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ |
151 | char buff[LUAI_MAXSHORTLEN]; | 151 | char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ |
152 | loadVector(S, buff, size); /* load string into buffer */ | 152 | loadVector(S, buff, size + 1); /* load string into buffer */ |
153 | ts = luaS_newlstr(L, buff, size); /* create string */ | 153 | ts = luaS_newlstr(L, buff, size); /* create string */ |
154 | } | 154 | } |
155 | else { /* long string */ | 155 | else { /* long string */ |
156 | ts = luaS_createlngstrobj(L, size); /* create string */ | 156 | if (S->fixed) { /* for a fixed buffer, use a fixed string */ |
157 | setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ | 157 | const char *s = getaddr(S, size + 1, char); /* get content address */ |
158 | luaD_inctop(L); | 158 | ts = luaS_newextlstr(L, s, size, NULL, NULL); |
159 | loadVector(S, getlngstr(ts), size); /* load directly in final place */ | 159 | } |
160 | L->top.p--; /* pop string */ | 160 | else { /* create internal copy */ |
161 | ts = luaS_createlngstrobj(L, size); /* create string */ | ||
162 | setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ | ||
163 | luaD_inctop(L); | ||
164 | loadVector(S, getlngstr(ts), size); /* load directly in final place */ | ||
165 | loadByte(S); /* skip ending '\0' */ | ||
166 | L->top.p--; /* pop string */ | ||
167 | } | ||
161 | } | 168 | } |
162 | luaC_objbarrier(L, p, ts); | 169 | luaC_objbarrier(L, p, ts); |
163 | S->nstr++; /* add string to list of saved strings */ | 170 | S->nstr++; /* add string to list of saved strings */ |
diff --git a/manual/manual.of b/manual/manual.of index 9d6a7fd9..9ca28aee 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -3651,8 +3651,10 @@ Moreover, it may have a @Char{B} instead of a @Char{b}, | |||
3651 | meaning a @emphx{fixed buffer} with the binary dump. | 3651 | meaning a @emphx{fixed buffer} with the binary dump. |
3652 | 3652 | ||
3653 | A fixed buffer means that the address returned by the reader function | 3653 | A fixed buffer means that the address returned by the reader function |
3654 | should contain the chunk until everything created by the chunk has | 3654 | will contain the chunk until everything created by the chunk has |
3655 | been collected. | 3655 | been collected; |
3656 | therefore, Lua can avoid copying to internal structures | ||
3657 | some parts of the chunk. | ||
3656 | (In general, a fixed buffer would keep the chunk | 3658 | (In general, a fixed buffer would keep the chunk |
3657 | as its contents until the end of the program, | 3659 | as its contents until the end of the program, |
3658 | for instance with the chunk in ROM.) | 3660 | for instance with the chunk in ROM.) |
diff --git a/testes/api.lua b/testes/api.lua index 181c1d53..7d64cb22 100644 --- a/testes/api.lua +++ b/testes/api.lua | |||
@@ -528,13 +528,15 @@ do | |||
528 | local N = 1000 | 528 | local N = 1000 |
529 | -- create a somewhat "large" source | 529 | -- create a somewhat "large" source |
530 | for i = 1, N do source[i] = "X = X + 1; " end | 530 | for i = 1, N do source[i] = "X = X + 1; " end |
531 | -- add a long string to the source | ||
532 | source[#source + 1] = string.format("Y = '%s'", string.rep("a", N)); | ||
531 | source = table.concat(source) | 533 | source = table.concat(source) |
532 | -- give chunk an explicit name to avoid using source as name | 534 | -- give chunk an explicit name to avoid using source as name |
533 | source = load(source, "name1") | 535 | source = load(source, "name1") |
534 | -- dump without debug information | 536 | -- dump without debug information |
535 | source = string.dump(source, true) | 537 | source = string.dump(source, true) |
536 | -- each "X=X+1" generates 4 opcodes with 4 bytes each | 538 | -- each "X=X+1" generates 4 opcodes with 4 bytes each, plus the string |
537 | assert(#source > N * 4 * 4) | 539 | assert(#source > N * 4 * 4 + N) |
538 | collectgarbage(); collectgarbage() | 540 | collectgarbage(); collectgarbage() |
539 | local m1 = collectgarbage"count" * 1024 | 541 | local m1 = collectgarbage"count" * 1024 |
540 | -- load dump using fixed buffer | 542 | -- load dump using fixed buffer |
@@ -544,9 +546,11 @@ do | |||
544 | ]], source) | 546 | ]], source) |
545 | collectgarbage() | 547 | collectgarbage() |
546 | local m2 = collectgarbage"count" * 1024 | 548 | local m2 = collectgarbage"count" * 1024 |
547 | -- load used fewer than 300 bytes | 549 | -- load used fewer than 350 bytes. Code alone has more than 3*N bytes, |
548 | assert(m2 > m1 and m2 - m1 < 300) | 550 | -- and string literal has N bytes. Both were not loaded. |
549 | X = 0; code(); assert(X == N); X = nil | 551 | assert(m2 > m1 and m2 - m1 < 350) |
552 | X = 0; code(); assert(X == N and Y == string.rep("a", N)) | ||
553 | X = nil; Y = nil | ||
550 | end | 554 | end |
551 | 555 | ||
552 | 556 | ||