Sfoglia il codice sorgente

in hash nodes, keys are stored in separate pieces to avoid wasting
space with alignments

Roberto Ierusalimschy 8 anni fa
parent
commit
b6f87491af
6 ha cambiato i file con 201 aggiunte e 110 eliminazioni
  1. 23 19
      lgc.c
  2. 3 3
      llex.c
  3. 76 22
      lobject.h
  4. 85 46
      ltable.c
  5. 4 14
      ltable.h
  6. 10 6
      ltests.c

+ 23 - 19
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.229 2017/05/26 19:14:29 roberto Exp roberto $
+** $Id: lgc.c,v 2.230 2017/06/01 19:16:34 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -73,7 +73,9 @@
 
 #define valiswhite(x)   (iscollectable(x) && iswhite(gcvalue(x)))
 
-#define checkdeadkey(n)	lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n)))
+#define keyiswhite(n)   (keyiscollectable(n) && iswhite(gckey(n)))
+
+#define checkdeadkey(n)	lua_assert(!keyisdead(n) || ttisnil(gval(n)))
 
 
 #define checkconsistency(obj)  \
@@ -83,6 +85,8 @@
 #define markvalue(g,o) { checkconsistency(o); \
   if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
 
+#define markkey(g, n)	{ if keyiswhite(n) reallymarkobject(g,gckey(n)); }
+
 #define markobject(g,t)	{ if (iswhite(t)) reallymarkobject(g, obj2gco(t)); }
 
 /*
@@ -125,8 +129,8 @@ static lu_mem atomic (lua_State *L);
 */
 static void removeentry (Node *n) {
   lua_assert(ttisnil(gval(n)));
-  if (valiswhite(gkey(n)))
-    setdeadvalue(wgkey(n));  /* unused and unmarked key; remove it */
+  if (keyiswhite(n))
+    setdeadkey(n);  /* unused and unmarked key; remove it */
 }
 
 
@@ -137,13 +141,13 @@ static void removeentry (Node *n) {
 ** other objects: if really collected, cannot keep them; for objects
 ** being finalized, keep them in keys, but not in values
 */
-static int iscleared (global_State *g, const TValue *o) {
-  if (!iscollectable(o)) return 0;
-  else if (ttisstring(o)) {
-    markobject(g, tsvalue(o));  /* strings are 'values', so are never weak */
+static int iscleared (global_State *g, const GCObject *o) {
+  if (o == NULL) return 0;  /* non-collectable value */
+  else if (novariant(o->tt) == LUA_TSTRING) {
+    markobject(g, o);  /* strings are 'values', so are never weak */
     return 0;
   }
-  else return iswhite(gcvalue(o));
+  else return iswhite(o);
 }
 
 
@@ -391,9 +395,9 @@ static void traverseweakvalue (global_State *g, Table *h) {
     if (ttisnil(gval(n)))  /* entry is empty? */
       removeentry(n);  /* remove it */
     else {
-      lua_assert(!ttisnil(gkey(n)));
-      markvalue(g, gkey(n));  /* mark key */
-      if (!hasclears && iscleared(g, gval(n)))  /* is there a white value? */
+      lua_assert(!keyisnil(n));
+      markkey(g, n);
+      if (!hasclears && iscleared(g, gcvalueN(gval(n))))  /* a white value? */
         hasclears = 1;  /* table will have to be cleared */
     }
   }
@@ -433,7 +437,7 @@ static int traverseephemeron (global_State *g, Table *h) {
     checkdeadkey(n);
     if (ttisnil(gval(n)))  /* entry is empty? */
       removeentry(n);  /* remove it */
-    else if (iscleared(g, gkey(n))) {  /* key is not marked (yet)? */
+    else if (iscleared(g, gckeyN(n))) {  /* key is not marked (yet)? */
       hasclears = 1;  /* table must be cleared */
       if (valiswhite(gval(n)))  /* value not marked yet? */
         hasww = 1;  /* white-white entry */
@@ -468,9 +472,9 @@ static void traversestrongtable (global_State *g, Table *h) {
     if (ttisnil(gval(n)))  /* entry is empty? */
       removeentry(n);  /* remove it */
     else {
-      lua_assert(!ttisnil(gkey(n)));
-      markvalue(g, gkey(n));  /* mark key */
-      markvalue(g, gval(n));  /* mark value */
+      lua_assert(!keyisnil(n));
+      markkey(g, n);
+      markvalue(g, gval(n));
     }
   }
   if (g->gckind == KGC_GEN) {
@@ -691,7 +695,7 @@ static void clearkeys (global_State *g, GCObject *l) {
     Table *h = gco2t(l);
     Node *n, *limit = gnodelast(h);
     for (n = gnode(h, 0); n < limit; n++) {
-      if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
+      if (!ttisnil(gval(n)) && (iscleared(g, gckeyN(n)))) {
         setnilvalue(gval(n));  /* remove value ... */
         removeentry(n);  /* and remove entry from table */
       }
@@ -711,11 +715,11 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
     unsigned int i;
     for (i = 0; i < h->sizearray; i++) {
       TValue *o = &h->array[i];
-      if (iscleared(g, o))  /* value was collected? */
+      if (iscleared(g, gcvalueN(o)))  /* value was collected? */
         setnilvalue(o);  /* remove value */
     }
     for (n = gnode(h, 0); n < limit; n++) {
-      if (iscleared(g, gval(n))) {
+      if (iscleared(g, gcvalueN(gval(n)))) {
         setnilvalue(gval(n));  /* remove value ... */
         removeentry(n);  /* and remove entry from table */
       }

+ 3 - 3
llex.c

@@ -1,5 +1,5 @@
 /*
-** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp roberto $
+** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp roberto $
 ** Lexical Analyzer
 ** See Copyright Notice in lua.h
 */
@@ -132,12 +132,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
   o = luaH_set(L, ls->h, L->top - 1);
   if (ttisnil(o)) {  /* not in use yet? */
     /* boolean value does not need GC barrier;
-       table has no metatable, so it does not need to invalidate cache */
+       table is not a metatable, so it does not need to invalidate cache */
     setbvalue(o, 1);  /* t[string] = true */
     luaC_checkGC(L);
   }
   else {  /* string already present */
-    ts = tsvalue(keyfromval(o));  /* re-use value previously stored */
+    ts = keystrval(nodefromval(o));  /* re-use value previously stored */
   }
   L->top--;  /* remove string from stack */
   return ts;

+ 76 - 22
lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 2.120 2017/04/30 20:43:26 roberto Exp roberto $
+** $Id: lobject.h,v 2.121 2017/06/01 20:24:05 roberto Exp roberto $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -122,6 +122,7 @@ typedef struct lua_TValue {
 
 
 #define val_(o)		((o)->value_)
+#define valraw(o)	(&val_(o))
 
 
 /* raw type tag of a TValue */
@@ -131,7 +132,8 @@ typedef struct lua_TValue {
 #define novariant(x)	((x) & 0x0F)
 
 /* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
-#define ttype(o)	(rttype(o) & 0x3F)
+#define ttyperaw(t)	((t) & 0x3F)
+#define ttype(o)	ttyperaw(rttype(o))
 
 /* type tag of a TValue with no variants (bits 0-3) */
 #define ttnov(o)	(novariant(rttype(o)))
@@ -157,7 +159,19 @@ typedef struct lua_TValue {
 #define ttislcf(o)		checktag((o), LUA_TLCF)
 #define ttisfulluserdata(o)	checktag((o), ctb(LUA_TUSERDATA))
 #define ttisthread(o)		checktag((o), ctb(LUA_TTHREAD))
-#define ttisdeadkey(o)		checktag((o), LUA_TDEADKEY)
+
+
+/*
+** Macros to access unstructured values (may come both from
+** 'TValue's and table keys)
+*/
+#define ivalueraw(v)	((v).i)
+#define fltvalueraw(v)	((v).n)
+#define gcvalueraw(v)	((v).gc)
+#define pvalueraw(v)	((v).p)
+#define tsvalueraw(v)	(gco2ts((v).gc))
+#define fvalueraw(v)	((v).f)
+#define bvalueraw(v)	((v).b)
 
 
 /* Macros to access values */
@@ -176,8 +190,6 @@ typedef struct lua_TValue {
 #define hvalue(o)	check_exp(ttistable(o), gco2t(val_(o).gc))
 #define bvalue(o)	check_exp(ttisboolean(o), val_(o).b)
 #define thvalue(o)	check_exp(ttisthread(o), gco2th(val_(o).gc))
-/* a dead value may get the 'gc' field, but cannot access its contents */
-#define deadvalue(o)	check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))
 
 #define l_isfalse(o)	(ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
 
@@ -185,6 +197,12 @@ typedef struct lua_TValue {
 #define iscollectable(o)	(rttype(o) & BIT_ISCOLLECTABLE)
 
 
+/*
+** Protected access to objects in values
+*/
+#define gcvalueN(o)	(iscollectable(o) ? gcvalue(o) : NULL)
+
+
 /* Macros for internal tests */
 #define righttt(obj)		(ttype(obj) == gcvalue(obj)->tt)
 
@@ -253,8 +271,6 @@ typedef struct lua_TValue {
     val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
     checkliveness(L,io); }
 
-#define setdeadvalue(obj)	settt_(obj, LUA_TDEADKEY)
-
 
 
 #define setobj(L,obj1,obj2) \
@@ -485,26 +501,37 @@ typedef union Closure {
 ** Tables
 */
 
-typedef union TKey {
-  struct {
-    TValuefields;
-    int next;  /* for chaining (offset for next node) */
-  } nk;
-  TValue tvk;
-} TKey;
+
+/*
+** Nodes for Hash tables. A pack of two TValue's (key-value pairs)
+** plus a 'next' field to link colliding entries. The distribuition
+** of the key's fields ('key_tt' and 'key_val') not forming a proper
+** 'TValue' allows for a smaller size for 'Node' both in 4-byte
+** and 8-byte alignments.
+*/
+typedef union Node {
+  struct NodeKey {
+    TValuefields;  /* fields for value */
+    lu_byte key_tt;  /* key type */
+    int next;  /* for chaining */
+    Value key_val;  /* key value */
+  } u;
+  TValue i_val;  /* direct access to node's value as a proper 'TValue' */
+} Node;
 
 
-/* copy a value into a key without messing up field 'next' */
-#define setnodekey(L,key,obj) \
-	{ TKey *k_=(key); const TValue *io_=(obj); \
-	  k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
+/* copy a value into a key */
+#define setnodekey(L,node,obj) \
+	{ Node *n_=(node); const TValue *io_=(obj); \
+	  n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
 	  (void)L; checkliveness(L,io_); }
 
 
-typedef struct Node {
-  TValue i_val;
-  TKey i_key;
-} Node;
+/* copy a value from a key */
+#define getnodekey(L,obj,node) \
+	{ TValue *io_=(obj); const Node *n_=(node); \
+	  io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \
+	  (void)L; checkliveness(L,io_); }
 
 
 typedef struct Table {
@@ -520,6 +547,33 @@ typedef struct Table {
 } Table;
 
 
+/*
+** Macros to manipulate keys inserted in nodes
+*/
+#define keytt(node)		((node)->u.key_tt)
+#define keyval(node)		((node)->u.key_val)
+
+#define keyisnil(node)		(keytt(node) == LUA_TNIL)
+#define keyisinteger(node)	(keytt(node) == LUA_TNUMINT)
+#define keyival(node)		(keyval(node).i)
+#define keyisshrstr(node)	(keytt(node) == ctb(LUA_TSHRSTR))
+#define keystrval(node)		(gco2ts(keyval(node).gc))
+
+#define keyisdead(node)		(keytt(node) == LUA_TDEADKEY)
+
+#define setnilkey(node)		(keytt(node) = LUA_TNIL)
+#define setdeadkey(node)	(keytt(node) = LUA_TDEADKEY)
+
+/* a dead value may get the 'gc' field, but cannot access its contents */
+#define deadkey(n)  \
+  check_exp(keytt(n) == LUA_TDEADKEY, cast(void *, keyval(n).gc))
+
+#define keyiscollectable(n)	(keytt(n) & BIT_ISCOLLECTABLE)
+
+#define gckey(n)	(keyval(n).gc)
+#define gckeyN(n)	(keyiscollectable(n) ? gckey(n) : NULL)
+
+
 
 /*
 ** 'module' operation for hashing (size is always a power of 2)

+ 85 - 46
ltable.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltable.c,v 2.121 2017/05/19 12:47:00 roberto Exp roberto $
+** $Id: ltable.c,v 2.122 2017/05/19 12:57:10 roberto Exp roberto $
 ** Lua tables (hash)
 ** See Copyright Notice in lua.h
 */
@@ -75,8 +75,8 @@
 #define dummynode		(&dummynode_)
 
 static const Node dummynode_ = {
-  {NILCONSTANT},  /* value */
-  {{NILCONSTANT, 0}}  /* key */
+  {{NULL}, LUA_TNIL,  /* value's value and type */
+   LUA_TNIL, 0, {NULL}}  /* key type, next, and key value */
 };
 
 
@@ -111,43 +111,79 @@ static int l_hashfloat (lua_Number n) {
 
 
 /*
-** returns the 'main' position of an element in a table (that is, the index
-** of its hash value)
+** returns the 'main' position of an element in a table (that is,
+** the index of its hash value). The key comes broken (tag in 'ktt'
+** and value in 'vkl') so that we can call it on keys inserted into
+** nodes.
 */
-static Node *mainposition (const Table *t, const TValue *key) {
-  switch (ttype(key)) {
+static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
+  switch (ttyperaw(ktt)) {
     case LUA_TNUMINT:
-      return hashint(t, ivalue(key));
+      return hashint(t, ivalueraw(*kvl));
     case LUA_TNUMFLT:
-      return hashmod(t, l_hashfloat(fltvalue(key)));
+      return hashmod(t, l_hashfloat(fltvalueraw(*kvl)));
     case LUA_TSHRSTR:
-      return hashstr(t, tsvalue(key));
+      return hashstr(t, tsvalueraw(*kvl));
     case LUA_TLNGSTR:
-      return hashpow2(t, luaS_hashlongstr(tsvalue(key)));
+      return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl)));
     case LUA_TBOOLEAN:
-      return hashboolean(t, bvalue(key));
+      return hashboolean(t, bvalueraw(*kvl));
     case LUA_TLIGHTUSERDATA:
-      return hashpointer(t, pvalue(key));
+      return hashpointer(t, pvalueraw(*kvl));
     case LUA_TLCF:
-      return hashpointer(t, fvalue(key));
+      return hashpointer(t, fvalueraw(*kvl));
     default:
-      lua_assert(!ttisdeadkey(key));
-      return hashpointer(t, gcvalue(key));
+      return hashpointer(t, gcvalueraw(*kvl));
   }
 }
 
 
+static Node *mainpositionTV (const Table *t, const TValue *key) {
+  return mainposition(t, rttype(key), valraw(key));
+}
+
+
 /*
-** returns the index for 'key' if 'key' is an appropriate key to live in
-** the array part of the table, 0 otherwise.
+** Check whether key 'k1' is equal to the key in node 'n2'.
+** This equality is raw, so there are no metamethods. Floats
+** with integer values have been normalized, so integers cannot
+** be equal to floats. It is assumed that 'eqshrstr' is simply
+** pointer equality, so that short strings are handled in the
+** default case.
 */
-static unsigned int arrayindex (const TValue *key) {
-  if (ttisinteger(key)) {
-    lua_Integer k = ivalue(key);
-    if (0 < k && (lua_Unsigned)k <= MAXASIZE)
-      return cast(unsigned int, k);  /* 'key' is an appropriate array index */
+static int equalkey (const TValue *k1, const Node *n2) {
+  if (rttype(k1) != keytt(n2))  /* not the same variants? */
+   return 0;  /* cannot be same key */
+  switch (ttype(k1)) {
+    case LUA_TNIL:
+      return 1;
+    case LUA_TNUMINT:
+      return (ivalue(k1) == keyival(n2));
+    case LUA_TNUMFLT:
+      return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
+    case LUA_TBOOLEAN:
+      return bvalue(k1) == bvalueraw(keyval(n2));
+    case LUA_TLIGHTUSERDATA:
+      return pvalue(k1) == pvalueraw(keyval(n2));
+    case LUA_TLCF:
+      return fvalue(k1) == fvalueraw(keyval(n2));
+    case LUA_TLNGSTR:
+      return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
+    default:
+      return gcvalue(k1) == gcvalueraw(keyval(n2));
   }
-  return 0;  /* 'key' did not match some condition */
+}
+
+
+/*
+** returns the index for 'k' if 'k' is an appropriate key to live in
+** the array part of a table, 0 otherwise.
+*/
+static unsigned int arrayindex (lua_Integer k) {
+  if (0 < k && l_castS2U(k) <= MAXASIZE)
+    return cast(unsigned int, k);  /* 'key' is an appropriate array index */
+  else
+    return 0;
 }
 
 
@@ -159,17 +195,17 @@ static unsigned int arrayindex (const TValue *key) {
 static unsigned int findindex (lua_State *L, Table *t, StkId key) {
   unsigned int i;
   if (ttisnil(key)) return 0;  /* first iteration */
-  i = arrayindex(key);
+  i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0;
   if (i != 0 && i <= t->sizearray)  /* is 'key' inside array part? */
     return i;  /* yes; that's the index */
   else {
     int nx;
-    Node *n = mainposition(t, key);
+    Node *n = mainpositionTV(t, key);
     for (;;) {  /* check whether 'key' is somewhere in the chain */
       /* key may be dead already, but it is ok to use it in 'next' */
-      if (luaV_rawequalobj(gkey(n), key) ||
-            (ttisdeadkey(gkey(n)) && iscollectable(key) &&
-             deadvalue(gkey(n)) == gcvalue(key))) {
+      if (equalkey(key, n) ||
+             (keyisdead(n) && iscollectable(key) &&
+             deadkey(n) == gcvalue(key))) {
         i = cast_int(n - gnode(t, 0));  /* key index in hash table */
         /* hash elements are numbered after array ones */
         return (i + 1) + t->sizearray;
@@ -194,8 +230,9 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
   }
   for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) {  /* hash part */
     if (!ttisnil(gval(gnode(t, i)))) {  /* a non-nil value? */
-      setobj2s(L, key, gkey(gnode(t, i)));
-      setobj2s(L, key+1, gval(gnode(t, i)));
+      Node *n = gnode(t, i);
+      getnodekey(L, key, n);
+      setobj2s(L, key + 1, gval(n));
       return 1;
     }
   }
@@ -239,7 +276,7 @@ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
 }
 
 
-static int countint (const TValue *key, unsigned int *nums) {
+static int countint (lua_Integer key, unsigned int *nums) {
   unsigned int k = arrayindex(key);
   if (k != 0) {  /* is 'key' an appropriate array index? */
     nums[luaO_ceillog2(k)]++;  /* count as such */
@@ -288,7 +325,8 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
   while (i--) {
     Node *n = &t->node[i];
     if (!ttisnil(gval(n))) {
-      ause += countint(gkey(n), nums);
+      if (keyisinteger(n))
+        ause += countint(keyival(n), nums);
       totaluse++;
     }
   }
@@ -322,7 +360,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
     for (i = 0; i < (int)size; i++) {
       Node *n = gnode(t, i);
       gnext(n) = 0;
-      setnilvalue(wgkey(n));
+      setnilkey(n);
       setnilvalue(gval(n));
     }
     t->lsizenode = cast_byte(lsize);
@@ -358,7 +396,8 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
     if (!ttisnil(gval(old))) {
       /* doesn't need barrier/invalidate cache, as entry was
          already present in the table */
-      setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
+      TValue k; getnodekey(L, &k, old);
+      setobjt2t(L, luaH_set(L, t, &k), gval(old));
     }
   }
   if (oldhsize > 0)  /* not the dummy node? */
@@ -385,7 +424,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
   totaluse = na;  /* all those keys are integer keys */
   totaluse += numusehash(t, nums, &na);  /* count keys in hash part */
   /* count extra key */
-  na += countint(ek, nums);
+  if (ttisinteger(ek))
+    na += countint(ivalue(ek), nums);
   totaluse++;
   /* compute new size for array part */
   asize = computesizes(nums, &na);
@@ -424,7 +464,7 @@ static Node *getfreepos (Table *t) {
   if (!isdummy(t)) {
     while (t->lastfree > t->node) {
       t->lastfree--;
-      if (ttisnil(gkey(t->lastfree)))
+      if (keyisnil(t->lastfree))
         return t->lastfree;
     }
   }
@@ -453,7 +493,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
     else if (luai_numisnan(fltvalue(key)))
       luaG_runerror(L, "table index is NaN");
   }
-  mp = mainposition(t, key);
+  mp = mainpositionTV(t, key);
   if (!ttisnil(gval(mp)) || isdummy(t)) {  /* main position is taken? */
     Node *othern;
     Node *f = getfreepos(t);  /* get a free place */
@@ -463,7 +503,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
       return luaH_set(L, t, key);  /* insert key into grown table */
     }
     lua_assert(!isdummy(t));
-    othern = mainposition(t, gkey(mp));
+    othern = mainposition(t, keytt(mp), &keyval(mp));
     if (othern != mp) {  /* is colliding node out of its main position? */
       /* yes; move colliding node into free position */
       while (othern + gnext(othern) != mp)  /* find previous */
@@ -485,7 +525,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
       mp = f;
     }
   }
-  setnodekey(L, &mp->i_key, key);
+  setnodekey(L, mp, key);
   luaC_barrierback(L, t, key);
   lua_assert(ttisnil(gval(mp)));
   return gval(mp);
@@ -502,7 +542,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
   else {
     Node *n = hashint(t, key);
     for (;;) {  /* check whether 'key' is somewhere in the chain */
-      if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key)
+      if (keyisinteger(n) && keyival(n) == key)
         return gval(n);  /* that's it */
       else {
         int nx = gnext(n);
@@ -522,8 +562,7 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
   Node *n = hashstr(t, key);
   lua_assert(key->tt == LUA_TSHRSTR);
   for (;;) {  /* check whether 'key' is somewhere in the chain */
-    const TValue *k = gkey(n);
-    if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
+    if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
       return gval(n);  /* that's it */
     else {
       int nx = gnext(n);
@@ -540,9 +579,9 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
 ** which may be in array part, nor for floats with integral values.)
 */
 static const TValue *getgeneric (Table *t, const TValue *key) {
-  Node *n = mainposition(t, key);
+  Node *n = mainpositionTV(t, key);
   for (;;) {  /* check whether 'key' is somewhere in the chain */
-    if (luaV_rawequalobj(gkey(n), key))
+    if (equalkey(key, n))
       return gval(n);  /* that's it */
     else {
       int nx = gnext(n);
@@ -683,7 +722,7 @@ lua_Unsigned luaH_getn (Table *t) {
 #if defined(LUA_DEBUG)
 
 Node *luaH_mainposition (const Table *t, const TValue *key) {
-  return mainposition(t, key);
+  return mainpositionTV(t, key);
 }
 
 int luaH_isdummy (const Table *t) { return isdummy(t); }

+ 4 - 14
ltable.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp roberto $
+** $Id: ltable.h,v 2.24 2017/05/19 12:48:15 roberto Exp roberto $
 ** Lua tables (hash)
 ** See Copyright Notice in lua.h
 */
@@ -12,18 +12,9 @@
 
 #define gnode(t,i)	(&(t)->node[i])
 #define gval(n)		(&(n)->i_val)
-#define gnext(n)	((n)->i_key.nk.next)
+#define gnext(n)	((n)->u.next)
 
 
-/* 'const' to avoid wrong writings that can mess up field 'next' */
-#define gkey(n)		cast(const TValue*, (&(n)->i_key.tvk))
-
-/*
-** writable version of 'gkey'; allows updates to individual fields,
-** but not to the whole (which has incompatible type)
-*/
-#define wgkey(n)		(&(n)->i_key.nk)
-
 #define invalidateTMcache(t)	((t)->flags = 0)
 
 
@@ -35,9 +26,8 @@
 #define allocsizenode(t)	(isdummy(t) ? 0 : sizenode(t))
 
 
-/* returns the key, given the value of a table entry */
-#define keyfromval(v) \
-  (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
+/* returns the Node, given the value of a table entry */
+#define nodefromval(v) 	cast(Node *, (v))
 
 
 LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);

+ 10 - 6
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 2.217 2017/05/04 13:32:01 roberto Exp $
+** $Id: ltests.c,v 2.218 2017/05/31 18:54:58 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -253,8 +253,10 @@ static void checktable (global_State *g, Table *h) {
     checkvalref(g, hgc, &h->array[i]);
   for (n = gnode(h, 0); n < limit; n++) {
     if (!ttisnil(gval(n))) {
-      lua_assert(!ttisnil(gkey(n)));
-      checkvalref(g, hgc, gkey(n));
+      TValue k;
+      getnodekey(g->mainthread, &k, n);
+      lua_assert(!keyisnil(n));
+      checkvalref(g, hgc, &k);
       checkvalref(g, hgc, gval(n));
     }
   }
@@ -802,10 +804,12 @@ static int table_query (lua_State *L) {
     lua_pushnil(L);
   }
   else if ((i -= t->sizearray) < sizenode(t)) {
+    TValue k;
+    getnodekey(L, &k, gnode(t, i));
     if (!ttisnil(gval(gnode(t, i))) ||
-        ttisnil(gkey(gnode(t, i))) ||
-        ttisnumber(gkey(gnode(t, i)))) {
-      pushobject(L, gkey(gnode(t, i)));
+        ttisnil(&k) ||
+        ttisnumber(&k)) {
+      pushobject(L, &k);
     }
     else
       lua_pushliteral(L, "<undef>");