瀏覽代碼

Dump uses varints also for integer constants

Unlike sizes, these constants can be negative, so it encodes those
integers into unsigned integers in a way that keeps small numbers
small.
Roberto Ierusalimschy 1 月之前
父節點
當前提交
0cecf1ab6d
共有 3 個文件被更改,包括 48 次插入18 次删除
  1. 18 9
      ldump.c
  2. 12 9
      lundump.c
  3. 18 0
      testes/code.lua

+ 18 - 9
ldump.c

@@ -31,7 +31,7 @@ typedef struct {
   int strip;
   int status;
   Table *h;  /* table to track saved strings */
-  lua_Integer nstr;  /* counter for counting saved strings */
+  lua_Unsigned nstr;  /* counter for counting saved strings */
 } DumpState;
 
 
@@ -87,12 +87,12 @@ static void dumpByte (DumpState *D, int y) {
 ** size for 'dumpVarint' buffer: each byte can store up to 7 bits.
 ** (The "+6" rounds up the division.)
 */
-#define DIBS    ((l_numbits(size_t) + 6) / 7)
+#define DIBS    ((l_numbits(lua_Unsigned) + 6) / 7)
 
 /*
 ** Dumps an unsigned integer using the MSB Varint encoding
 */
-static void dumpVarint (DumpState *D, size_t x) {
+static void dumpVarint (DumpState *D, lua_Unsigned x) {
   lu_byte buff[DIBS];
   unsigned n = 1;
   buff[DIBS - 1] = x & 0x7f;  /* fill least-significant byte */
@@ -103,12 +103,13 @@ static void dumpVarint (DumpState *D, size_t x) {
 
 
 static void dumpSize (DumpState *D, size_t sz) {
-  dumpVarint(D, sz);
+  dumpVarint(D, cast(lua_Unsigned, sz));
 }
 
+
 static void dumpInt (DumpState *D, int x) {
   lua_assert(x >= 0);
-  dumpVarint(D, cast_sizet(x));
+  dumpVarint(D, cast_uint(x));
 }
 
 
@@ -117,8 +118,16 @@ static void dumpNumber (DumpState *D, lua_Number x) {
 }
 
 
+/*
+** Signed integers are coded to keep small values small. (Coding -1 as
+** 0xfff...fff would use too many bytes to save a quite common value.)
+** A non-negative x is coded as 2x; a negative x is coded as -2x - 1.
+** (0 => 0; -1 => 1; 1 => 2; -2 => 3; 2 => 4; ...)
+*/
 static void dumpInteger (DumpState *D, lua_Integer x) {
-  dumpVar(D, x);
+  lua_Unsigned cx = (x >= 0) ? 2u * l_castS2U(x)
+                             : (2u * ~l_castS2U(x)) + 1;
+  dumpVarint(D, cx);
 }
 
 
@@ -136,8 +145,8 @@ static void dumpString (DumpState *D, TString *ts) {
     TValue idx;
     int tag = luaH_getstr(D->h, ts, &idx);
     if (!tagisempty(tag)) {  /* string already saved? */
-      dumpSize(D, 1);  /* reuse a saved string */
-      dumpSize(D, cast_sizet(ivalue(&idx)));  /* index of saved string */
+      dumpVarint(D, 1);  /* reuse a saved string */
+      dumpVarint(D, l_castS2U(ivalue(&idx)));  /* index of saved string */
     }
     else {  /* must write and save the string */
       TValue key, value;  /* to save the string in the hash */
@@ -147,7 +156,7 @@ static void dumpString (DumpState *D, TString *ts) {
       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 */
+      setivalue(&value, l_castU2S(D->nstr));  /* its index is the value */
       luaH_set(D->L, D->h, &key, &value);  /* h[ts] = nstr */
       /* integer value does not need barrier */
     }

+ 12 - 9
lundump.c

@@ -37,7 +37,7 @@ typedef struct {
   const char *name;
   Table *h;  /* list for string reuse */
   size_t offset;  /* current position relative to beginning of dump */
-  lua_Integer nstr;  /* number of strings in the list */
+  lua_Unsigned nstr;  /* number of strings in the list */
   lu_byte fixed;  /* dump is fixed in memory */
 } LoadState;
 
@@ -94,8 +94,8 @@ static lu_byte loadByte (LoadState *S) {
 }
 
 
-static size_t loadVarint (LoadState *S, size_t limit) {
-  size_t x = 0;
+static lua_Unsigned loadVarint (LoadState *S, lua_Unsigned limit) {
+  lua_Unsigned x = 0;
   int b;
   limit >>= 7;
   do {
@@ -127,9 +127,12 @@ static lua_Number loadNumber (LoadState *S) {
 
 
 static lua_Integer loadInteger (LoadState *S) {
-  lua_Integer x;
-  loadVar(S, x);
-  return x;
+  lua_Unsigned cx = loadVarint(S, LUA_MAXUNSIGNED);
+  /* decode unsigned to signed */
+  if ((cx & 1) != 0)
+    return l_castU2S(~(cx >> 1));
+  else
+    return l_castU2S(cx >> 1);
 }
 
 
@@ -149,9 +152,9 @@ static void loadString (LoadState *S, Proto *p, TString **sl) {
     return;
   }
   else if (size == 1) {  /* previously saved string? */
-    lua_Integer idx = cast_st2S(loadSize(S));  /* get its index */
+    lua_Unsigned idx = loadVarint(S, LUA_MAXUNSIGNED);  /* get its index */
     TValue stv;
-    luaH_getint(S->h, idx, &stv);  /* get its value */
+    luaH_getint(S->h, l_castU2S(idx), &stv);  /* get its value */
     *sl = ts = tsvalue(&stv);
     luaC_objbarrier(L, p, ts);
     return;  /* do not save it again */
@@ -175,7 +178,7 @@ static void loadString (LoadState *S, Proto *p, TString **sl) {
   /* add string to list of saved strings */
   S->nstr++;
   setsvalue(L, &sv, ts);
-  luaH_setint(L, S->h, S->nstr, &sv);
+  luaH_setint(L, S->h, l_castU2S(S->nstr), &sv);
   luaC_objbarrierback(L, obj2gco(S->h), ts);
 }
 

+ 18 - 0
testes/code.lua

@@ -482,5 +482,23 @@ do   -- basic check for SETLIST
   assert(count == 1)
 end
 
+
+do   print("testing code for integer limits")
+  local function checkints (n)
+    local source = string.format(
+      "local a = {[true] = 0X%x}; return a[true]", n)
+    local f = assert(load(source))
+    checkKlist(f, {n})
+    assert(f() == n)
+    f = load(string.dump(f))
+    assert(f() == n)
+  end
+
+  checkints(math.maxinteger)
+  checkints(math.mininteger)
+  checkints(-1)
+
+end
+
 print 'OK'