diff options
-rw-r--r-- | lgc.c | 21 | ||||
-rw-r--r-- | lobject.h | 22 | ||||
-rw-r--r-- | lstate.h | 5 | ||||
-rw-r--r-- | ltable.c | 64 | ||||
-rw-r--r-- | ltests.c | 3 |
5 files changed, 49 insertions, 66 deletions
@@ -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 | */ |
130 | static void removeentry (Node *n) { | 126 | static 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 { |
@@ -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) |
@@ -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 */ |
@@ -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 | */ | ||
182 | static 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 | */ | ||
581 | static 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 | |||
596 | const TValue *luaH_getstr (Table *t, TString *key) { | 586 | const 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 | */ |
666 | static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { | 656 | static 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 */ |
@@ -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 | ||