aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-06-12 11:21:44 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-06-12 11:21:44 -0300
commit73ec04fcf3e3f7017786fbaf0a83291b22bec5c4 (patch)
treeb2870a1e832fa3e013b67209592db32b611f8e5f
parentd13a3fb070fd0ec9ec3b85f88e0fcd914aa666d3 (diff)
downloadlua-73ec04fcf3e3f7017786fbaf0a83291b22bec5c4.tar.gz
lua-73ec04fcf3e3f7017786fbaf0a83291b22bec5c4.tar.bz2
lua-73ec04fcf3e3f7017786fbaf0a83291b22bec5c4.zip
no more 'DEADKEY'. Table traversals do not need to consider dead keys;
if the key is dead, it cannot be given to 'next'. Instead, we now use a 'table' tag without the collectable bit, which makes it a unique tag good enough to reserve space.
-rw-r--r--lgc.c21
-rw-r--r--lobject.h22
-rw-r--r--lstate.h5
-rw-r--r--ltable.c64
-rw-r--r--ltests.c3
5 files changed, 49 insertions, 66 deletions
diff --git a/lgc.c b/lgc.c
index 36e34368..18a05142 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.230 2017/06/01 19:16:34 roberto Exp roberto $ 2** $Id: lgc.c,v 2.231 2017/06/09 16:48:44 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -75,8 +75,6 @@
75 75
76#define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n))) 76#define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n)))
77 77
78#define checkdeadkey(n) lua_assert(!keyisdead(n) || ttisnil(gval(n)))
79
80 78
81#define checkconsistency(obj) \ 79#define checkconsistency(obj) \
82 lua_longassert(!iscollectable(obj) || righttt(obj)) 80 lua_longassert(!iscollectable(obj) || righttt(obj))
@@ -119,13 +117,11 @@ static lu_mem atomic (lua_State *L);
119 117
120 118
121/* 119/*
122** If key is not marked, mark its entry as dead. This allows key to be 120** If key is not marked, mark its entry as dead. This allows the
123** collected, but keeps its entry in the table. A dead node is needed 121** collection of the key, but keeps its entry in the table (its removal
124** when Lua looks up for a key (it may be part of a chain) and when 122** could break a chain). Other places never manipulate dead keys,
125** traversing a weak table (key might be removed from the table during 123** because its associated nil value is enough to signal that the entry
126** traversal). Other places never manipulate dead keys, because its 124** is logically empty.
127** associated nil value is enough to signal that the entry is logically
128** empty.
129*/ 125*/
130static void removeentry (Node *n) { 126static void removeentry (Node *n) {
131 lua_assert(ttisnil(gval(n))); 127 lua_assert(ttisnil(gval(n)));
@@ -203,7 +199,7 @@ LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p) {
203 lua_assert(g->gckind != KGC_GEN || isold(p)); 199 lua_assert(g->gckind != KGC_GEN || isold(p));
204 if (getage(p) == G_OLD1) /* still need to be visited? */ 200 if (getage(p) == G_OLD1) /* still need to be visited? */
205 linkgclist(p, g->grayagain); /* link it in 'grayagain' */ 201 linkgclist(p, g->grayagain); /* link it in 'grayagain' */
206 else 202 else
207 linkgclist(p, g->protogray); /* link it in 'protogray' */ 203 linkgclist(p, g->protogray); /* link it in 'protogray' */
208 black2gray(p); /* make prototype gray (to avoid other barriers) */ 204 black2gray(p); /* make prototype gray (to avoid other barriers) */
209} 205}
@@ -391,7 +387,6 @@ static void traverseweakvalue (global_State *g, Table *h) {
391 worth traversing it now just to check) */ 387 worth traversing it now just to check) */
392 int hasclears = (h->sizearray > 0); 388 int hasclears = (h->sizearray > 0);
393 for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ 389 for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */
394 checkdeadkey(n);
395 if (ttisnil(gval(n))) /* entry is empty? */ 390 if (ttisnil(gval(n))) /* entry is empty? */
396 removeentry(n); /* remove it */ 391 removeentry(n); /* remove it */
397 else { 392 else {
@@ -434,7 +429,6 @@ static int traverseephemeron (global_State *g, Table *h) {
434 } 429 }
435 /* traverse hash part */ 430 /* traverse hash part */
436 for (n = gnode(h, 0); n < limit; n++) { 431 for (n = gnode(h, 0); n < limit; n++) {
437 checkdeadkey(n);
438 if (ttisnil(gval(n))) /* entry is empty? */ 432 if (ttisnil(gval(n))) /* entry is empty? */
439 removeentry(n); /* remove it */ 433 removeentry(n); /* remove it */
440 else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */ 434 else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */
@@ -468,7 +462,6 @@ static void traversestrongtable (global_State *g, Table *h) {
468 for (i = 0; i < h->sizearray; i++) /* traverse array part */ 462 for (i = 0; i < h->sizearray; i++) /* traverse array part */
469 markvalue(g, &h->array[i]); 463 markvalue(g, &h->array[i]);
470 for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ 464 for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */
471 checkdeadkey(n);
472 if (ttisnil(gval(n))) /* entry is empty? */ 465 if (ttisnil(gval(n))) /* entry is empty? */
473 removeentry(n); /* remove it */ 466 removeentry(n); /* remove it */
474 else { 467 else {
diff --git a/lobject.h b/lobject.h
index 97afa143..e245f306 100644
--- a/lobject.h
+++ b/lobject.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lobject.h,v 2.121 2017/06/01 20:24:05 roberto Exp roberto $ 2** $Id: lobject.h,v 2.122 2017/06/09 16:48:44 roberto Exp roberto $
3** Type definitions for Lua objects 3** Type definitions for Lua objects
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -21,10 +21,9 @@
21*/ 21*/
22#define LUA_TUPVAL LUA_NUMTAGS /* upvalues */ 22#define LUA_TUPVAL LUA_NUMTAGS /* upvalues */
23#define LUA_TPROTO (LUA_NUMTAGS+1) /* function prototypes */ 23#define LUA_TPROTO (LUA_NUMTAGS+1) /* function prototypes */
24#define LUA_TDEADKEY (LUA_NUMTAGS+2) /* removed keys in tables */
25 24
26/* 25/*
27** number of all possible tags (including LUA_TNONE but excluding DEADKEY) 26** number of all possible tags (including LUA_TNONE)
28*/ 27*/
29#define LUA_TOTALTAGS (LUA_TPROTO + 2) 28#define LUA_TOTALTAGS (LUA_TPROTO + 2)
30 29
@@ -559,14 +558,7 @@ typedef struct Table {
559#define keyisshrstr(node) (keytt(node) == ctb(LUA_TSHRSTR)) 558#define keyisshrstr(node) (keytt(node) == ctb(LUA_TSHRSTR))
560#define keystrval(node) (gco2ts(keyval(node).gc)) 559#define keystrval(node) (gco2ts(keyval(node).gc))
561 560
562#define keyisdead(node) (keytt(node) == LUA_TDEADKEY)
563
564#define setnilkey(node) (keytt(node) = LUA_TNIL) 561#define setnilkey(node) (keytt(node) = LUA_TNIL)
565#define setdeadkey(node) (keytt(node) = LUA_TDEADKEY)
566
567/* a dead value may get the 'gc' field, but cannot access its contents */
568#define deadkey(n) \
569 check_exp(keytt(n) == LUA_TDEADKEY, cast(void *, keyval(n).gc))
570 562
571#define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE) 563#define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE)
572 564
@@ -574,6 +566,16 @@ typedef struct Table {
574#define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL) 566#define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL)
575 567
576 568
569/*
570** Use a "nil table" to mark dead keys in a table. Those keys serve
571** only to keep space for removed entries, which may still be part of
572** chains. Note that the 'keytt' does not have the BIT_ISCOLLECTABLE
573** set, so these values are considered not collectable and are different
574** from any valid value.
575*/
576#define setdeadkey(n) (keytt(n) = LUA_TTABLE, gckey(n) = NULL)
577
578
577 579
578/* 580/*
579** 'module' operation for hashing (size is always a power of 2) 581** 'module' operation for hashing (size is always a power of 2)
diff --git a/lstate.h b/lstate.h
index 9a3e778a..12dddf3b 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.141 2017/05/13 13:54:47 roberto Exp roberto $ 2** $Id: lstate.h,v 2.142 2017/05/26 19:14:29 roberto Exp roberto $
3** Global State 3** Global State
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -247,8 +247,7 @@ union GCUnion {
247 247
248 248
249/* macro to convert a Lua object into a GCObject */ 249/* macro to convert a Lua object into a GCObject */
250#define obj2gco(v) \ 250#define obj2gco(v) (&(cast_u(v)->gc))
251 check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc)))
252 251
253 252
254/* actual number of total bytes allocated */ 253/* actual number of total bytes allocated */
diff --git a/ltable.c b/ltable.c
index 498eb121..b8244dca 100644
--- a/ltable.c
+++ b/ltable.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltable.c,v 2.122 2017/05/19 12:57:10 roberto Exp roberto $ 2** $Id: ltable.c,v 2.123 2017/06/09 16:48:44 roberto Exp roberto $
3** Lua tables (hash) 3** Lua tables (hash)
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -176,6 +176,25 @@ static int equalkey (const TValue *k1, const Node *n2) {
176 176
177 177
178/* 178/*
179** "Generic" get version. (Not that generic: not valid for integers,
180** which may be in array part, nor for floats with integral values.)
181*/
182static const TValue *getgeneric (Table *t, const TValue *key) {
183 Node *n = mainpositionTV(t, key);
184 for (;;) { /* check whether 'key' is somewhere in the chain */
185 if (equalkey(key, n))
186 return gval(n); /* that's it */
187 else {
188 int nx = gnext(n);
189 if (nx == 0)
190 return luaO_nilobject; /* not found */
191 n += nx;
192 }
193 }
194}
195
196
197/*
179** returns the index for 'k' if 'k' is an appropriate key to live in 198** returns the index for 'k' if 'k' is an appropriate key to live in
180** the array part of a table, 0 otherwise. 199** the array part of a table, 0 otherwise.
181*/ 200*/
@@ -199,22 +218,12 @@ static unsigned int findindex (lua_State *L, Table *t, StkId key) {
199 if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ 218 if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */
200 return i; /* yes; that's the index */ 219 return i; /* yes; that's the index */
201 else { 220 else {
202 int nx; 221 const TValue *n = getgeneric(t, key);
203 Node *n = mainpositionTV(t, key); 222 if (n == luaO_nilobject)
204 for (;;) { /* check whether 'key' is somewhere in the chain */ 223 luaG_runerror(L, "invalid key to 'next'"); /* key not found */
205 /* key may be dead already, but it is ok to use it in 'next' */ 224 i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */
206 if (equalkey(key, n) || 225 /* hash elements are numbered after array ones */
207 (keyisdead(n) && iscollectable(key) && 226 return (i + 1) + t->sizearray;
208 deadkey(n) == gcvalue(key))) {
209 i = cast_int(n - gnode(t, 0)); /* key index in hash table */
210 /* hash elements are numbered after array ones */
211 return (i + 1) + t->sizearray;
212 }
213 nx = gnext(n);
214 if (nx == 0)
215 luaG_runerror(L, "invalid key to 'next'"); /* key not found */
216 else n += nx;
217 }
218 } 227 }
219} 228}
220 229
@@ -574,25 +583,6 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
574} 583}
575 584
576 585
577/*
578** "Generic" get version. (Not that generic: not valid for integers,
579** which may be in array part, nor for floats with integral values.)
580*/
581static const TValue *getgeneric (Table *t, const TValue *key) {
582 Node *n = mainpositionTV(t, key);
583 for (;;) { /* check whether 'key' is somewhere in the chain */
584 if (equalkey(key, n))
585 return gval(n); /* that's it */
586 else {
587 int nx = gnext(n);
588 if (nx == 0)
589 return luaO_nilobject; /* not found */
590 n += nx;
591 }
592 }
593}
594
595
596const TValue *luaH_getstr (Table *t, TString *key) { 586const TValue *luaH_getstr (Table *t, TString *key) {
597 if (key->tt == LUA_TSHRSTR) 587 if (key->tt == LUA_TSHRSTR)
598 return luaH_getshortstr(t, key); 588 return luaH_getshortstr(t, key);
@@ -662,7 +652,7 @@ void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
662** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a 652** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a
663** boundary. ('j + 1' cannot be a present integer key because it is 653** boundary. ('j + 1' cannot be a present integer key because it is
664** not a valid integer in Lua.) 654** not a valid integer in Lua.)
665*/ 655*/
666static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { 656static lua_Unsigned hash_search (Table *t, lua_Unsigned j) {
667 lua_Unsigned i; 657 lua_Unsigned i;
668 if (j == 0) j++; /* the caller ensures 'j + 1' is present */ 658 if (j == 0) j++; /* the caller ensures 'j + 1' is present */
diff --git a/ltests.c b/ltests.c
index a9c93132..733e47d4 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltests.c,v 2.218 2017/05/31 18:54:58 roberto Exp roberto $ 2** $Id: ltests.c,v 2.219 2017/06/09 16:48:44 roberto Exp roberto $
3** Internal Module for Debugging of the Lua Implementation 3** Internal Module for Debugging of the Lua Implementation
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -449,7 +449,6 @@ static void markgrays (global_State *g) {
449 checkgraylist(g, g->grayagain); 449 checkgraylist(g, g->grayagain);
450 checkgraylist(g, g->weak); 450 checkgraylist(g, g->weak);
451 checkgraylist(g, g->ephemeron); 451 checkgraylist(g, g->ephemeron);
452 checkgraylist(g, g->allweak);
453 checkgraylist(g, g->protogray); 452 checkgraylist(g, g->protogray);
454} 453}
455 454