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

space with alignments
This commit is contained in:
Roberto Ierusalimschy 2017-06-09 13:48:44 -03:00
parent 4bb30f461b
commit b6f87491af
6 changed files with 202 additions and 111 deletions

42
lgc.c
View File

@ -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 */
}

6
llex.c
View File

@ -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;

View File

@ -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)

133
ltable.c
View File

@ -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); }

View File

@ -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);

View File

@ -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>");