From b6f87491afe32140563fe3c546b8812c28a63410 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 9 Jun 2017 13:48:44 -0300 Subject: [PATCH] in hash nodes, keys are stored in separate pieces to avoid wasting space with alignments --- lgc.c | 42 +++++++++-------- llex.c | 6 +-- lobject.h | 98 +++++++++++++++++++++++++++++++--------- ltable.c | 133 +++++++++++++++++++++++++++++++++++------------------- ltable.h | 18 ++------ ltests.c | 16 ++++--- 6 files changed, 202 insertions(+), 111 deletions(-) diff --git a/lgc.c b/lgc.c index fa6cf799..36e34368 100644 --- a/lgc.c +++ b/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 */ } diff --git a/llex.c b/llex.c index 8f44cbef..d840a3ca 100644 --- a/llex.c +++ b/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; diff --git a/lobject.h b/lobject.h index 2bef659a..97afa143 100644 --- a/lobject.h +++ b/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) diff --git a/ltable.c b/ltable.c index 4ce33319..498eb121 100644 --- a/ltable.c +++ b/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)); +} + + +/* +** 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 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)); } } /* -** returns the index for 'key' if 'key' is an appropriate key to live in -** the array part of the table, 0 otherwise. +** 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 (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 */ - } - return 0; /* 'key' did not match some condition */ +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); } diff --git a/ltable.h b/ltable.h index ee22cf62..88f90636 100644 --- a/ltable.h +++ b/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); diff --git a/ltests.c b/ltests.c index fc233c7f..a9c93132 100644 --- a/ltests.c +++ b/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, "");