Bladeren bron

Fixed buffers save long strings as external.

Roberto Ierusalimschy 1 jaar geleden
bovenliggende
commit
3b57e37e48
4 gewijzigde bestanden met toevoegingen van 29 en 16 verwijderingen
  1. 1 1
      ldump.c
  2. 15 8
      lundump.c
  3. 4 2
      manual/manual.of
  4. 9 5
      testes/api.lua

+ 1 - 1
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 */

+ 15 - 8
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 */

+ 4 - 2
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.)

+ 9 - 5
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