diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-06-09 13:48:44 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-06-09 13:48:44 -0300 |
| commit | b6f87491afe32140563fe3c546b8812c28a63410 (patch) | |
| tree | ac85dff5a850c5d488f1efa4ea95d0d7da99be16 | |
| parent | 4bb30f461b146e1d189ee301472953e948699acf (diff) | |
| download | lua-b6f87491afe32140563fe3c546b8812c28a63410.tar.gz lua-b6f87491afe32140563fe3c546b8812c28a63410.tar.bz2 lua-b6f87491afe32140563fe3c546b8812c28a63410.zip | |
in hash nodes, keys are stored in separate pieces to avoid wasting
space with alignments
| -rw-r--r-- | lgc.c | 42 | ||||
| -rw-r--r-- | llex.c | 6 | ||||
| -rw-r--r-- | lobject.h | 98 | ||||
| -rw-r--r-- | ltable.c | 131 | ||||
| -rw-r--r-- | ltable.h | 18 | ||||
| -rw-r--r-- | ltests.c | 16 |
6 files changed, 201 insertions, 110 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.229 2017/05/26 19:14:29 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.230 2017/06/01 19:16:34 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 | */ |
| @@ -73,7 +73,9 @@ | |||
| 73 | 73 | ||
| 74 | #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) | 74 | #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) |
| 75 | 75 | ||
| 76 | #define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) | 76 | #define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n))) |
| 77 | |||
| 78 | #define checkdeadkey(n) lua_assert(!keyisdead(n) || ttisnil(gval(n))) | ||
| 77 | 79 | ||
| 78 | 80 | ||
| 79 | #define checkconsistency(obj) \ | 81 | #define checkconsistency(obj) \ |
| @@ -83,6 +85,8 @@ | |||
| 83 | #define markvalue(g,o) { checkconsistency(o); \ | 85 | #define markvalue(g,o) { checkconsistency(o); \ |
| 84 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } | 86 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } |
| 85 | 87 | ||
| 88 | #define markkey(g, n) { if keyiswhite(n) reallymarkobject(g,gckey(n)); } | ||
| 89 | |||
| 86 | #define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } | 90 | #define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } |
| 87 | 91 | ||
| 88 | /* | 92 | /* |
| @@ -125,8 +129,8 @@ static lu_mem atomic (lua_State *L); | |||
| 125 | */ | 129 | */ |
| 126 | static void removeentry (Node *n) { | 130 | static void removeentry (Node *n) { |
| 127 | lua_assert(ttisnil(gval(n))); | 131 | lua_assert(ttisnil(gval(n))); |
| 128 | if (valiswhite(gkey(n))) | 132 | if (keyiswhite(n)) |
| 129 | setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ | 133 | setdeadkey(n); /* unused and unmarked key; remove it */ |
| 130 | } | 134 | } |
| 131 | 135 | ||
| 132 | 136 | ||
| @@ -137,13 +141,13 @@ static void removeentry (Node *n) { | |||
| 137 | ** other objects: if really collected, cannot keep them; for objects | 141 | ** other objects: if really collected, cannot keep them; for objects |
| 138 | ** being finalized, keep them in keys, but not in values | 142 | ** being finalized, keep them in keys, but not in values |
| 139 | */ | 143 | */ |
| 140 | static int iscleared (global_State *g, const TValue *o) { | 144 | static int iscleared (global_State *g, const GCObject *o) { |
| 141 | if (!iscollectable(o)) return 0; | 145 | if (o == NULL) return 0; /* non-collectable value */ |
| 142 | else if (ttisstring(o)) { | 146 | else if (novariant(o->tt) == LUA_TSTRING) { |
| 143 | markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ | 147 | markobject(g, o); /* strings are 'values', so are never weak */ |
| 144 | return 0; | 148 | return 0; |
| 145 | } | 149 | } |
| 146 | else return iswhite(gcvalue(o)); | 150 | else return iswhite(o); |
| 147 | } | 151 | } |
| 148 | 152 | ||
| 149 | 153 | ||
| @@ -391,9 +395,9 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
| 391 | if (ttisnil(gval(n))) /* entry is empty? */ | 395 | if (ttisnil(gval(n))) /* entry is empty? */ |
| 392 | removeentry(n); /* remove it */ | 396 | removeentry(n); /* remove it */ |
| 393 | else { | 397 | else { |
| 394 | lua_assert(!ttisnil(gkey(n))); | 398 | lua_assert(!keyisnil(n)); |
| 395 | markvalue(g, gkey(n)); /* mark key */ | 399 | markkey(g, n); |
| 396 | if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ | 400 | if (!hasclears && iscleared(g, gcvalueN(gval(n)))) /* a white value? */ |
| 397 | hasclears = 1; /* table will have to be cleared */ | 401 | hasclears = 1; /* table will have to be cleared */ |
| 398 | } | 402 | } |
| 399 | } | 403 | } |
| @@ -433,7 +437,7 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
| 433 | checkdeadkey(n); | 437 | checkdeadkey(n); |
| 434 | if (ttisnil(gval(n))) /* entry is empty? */ | 438 | if (ttisnil(gval(n))) /* entry is empty? */ |
| 435 | removeentry(n); /* remove it */ | 439 | removeentry(n); /* remove it */ |
| 436 | else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ | 440 | else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */ |
| 437 | hasclears = 1; /* table must be cleared */ | 441 | hasclears = 1; /* table must be cleared */ |
| 438 | if (valiswhite(gval(n))) /* value not marked yet? */ | 442 | if (valiswhite(gval(n))) /* value not marked yet? */ |
| 439 | hasww = 1; /* white-white entry */ | 443 | hasww = 1; /* white-white entry */ |
| @@ -468,9 +472,9 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
| 468 | if (ttisnil(gval(n))) /* entry is empty? */ | 472 | if (ttisnil(gval(n))) /* entry is empty? */ |
| 469 | removeentry(n); /* remove it */ | 473 | removeentry(n); /* remove it */ |
| 470 | else { | 474 | else { |
| 471 | lua_assert(!ttisnil(gkey(n))); | 475 | lua_assert(!keyisnil(n)); |
| 472 | markvalue(g, gkey(n)); /* mark key */ | 476 | markkey(g, n); |
| 473 | markvalue(g, gval(n)); /* mark value */ | 477 | markvalue(g, gval(n)); |
| 474 | } | 478 | } |
| 475 | } | 479 | } |
| 476 | if (g->gckind == KGC_GEN) { | 480 | if (g->gckind == KGC_GEN) { |
| @@ -691,7 +695,7 @@ static void clearkeys (global_State *g, GCObject *l) { | |||
| 691 | Table *h = gco2t(l); | 695 | Table *h = gco2t(l); |
| 692 | Node *n, *limit = gnodelast(h); | 696 | Node *n, *limit = gnodelast(h); |
| 693 | for (n = gnode(h, 0); n < limit; n++) { | 697 | for (n = gnode(h, 0); n < limit; n++) { |
| 694 | if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { | 698 | if (!ttisnil(gval(n)) && (iscleared(g, gckeyN(n)))) { |
| 695 | setnilvalue(gval(n)); /* remove value ... */ | 699 | setnilvalue(gval(n)); /* remove value ... */ |
| 696 | removeentry(n); /* and remove entry from table */ | 700 | removeentry(n); /* and remove entry from table */ |
| 697 | } | 701 | } |
| @@ -711,11 +715,11 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { | |||
| 711 | unsigned int i; | 715 | unsigned int i; |
| 712 | for (i = 0; i < h->sizearray; i++) { | 716 | for (i = 0; i < h->sizearray; i++) { |
| 713 | TValue *o = &h->array[i]; | 717 | TValue *o = &h->array[i]; |
| 714 | if (iscleared(g, o)) /* value was collected? */ | 718 | if (iscleared(g, gcvalueN(o))) /* value was collected? */ |
| 715 | setnilvalue(o); /* remove value */ | 719 | setnilvalue(o); /* remove value */ |
| 716 | } | 720 | } |
| 717 | for (n = gnode(h, 0); n < limit; n++) { | 721 | for (n = gnode(h, 0); n < limit; n++) { |
| 718 | if (iscleared(g, gval(n))) { | 722 | if (iscleared(g, gcvalueN(gval(n)))) { |
| 719 | setnilvalue(gval(n)); /* remove value ... */ | 723 | setnilvalue(gval(n)); /* remove value ... */ |
| 720 | removeentry(n); /* and remove entry from table */ | 724 | removeentry(n); /* and remove entry from table */ |
| 721 | } | 725 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp roberto $ | 2 | ** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp roberto $ |
| 3 | ** Lexical Analyzer | 3 | ** Lexical Analyzer |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -132,12 +132,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { | |||
| 132 | o = luaH_set(L, ls->h, L->top - 1); | 132 | o = luaH_set(L, ls->h, L->top - 1); |
| 133 | if (ttisnil(o)) { /* not in use yet? */ | 133 | if (ttisnil(o)) { /* not in use yet? */ |
| 134 | /* boolean value does not need GC barrier; | 134 | /* boolean value does not need GC barrier; |
| 135 | table has no metatable, so it does not need to invalidate cache */ | 135 | table is not a metatable, so it does not need to invalidate cache */ |
| 136 | setbvalue(o, 1); /* t[string] = true */ | 136 | setbvalue(o, 1); /* t[string] = true */ |
| 137 | luaC_checkGC(L); | 137 | luaC_checkGC(L); |
| 138 | } | 138 | } |
| 139 | else { /* string already present */ | 139 | else { /* string already present */ |
| 140 | ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ | 140 | ts = keystrval(nodefromval(o)); /* re-use value previously stored */ |
| 141 | } | 141 | } |
| 142 | L->top--; /* remove string from stack */ | 142 | L->top--; /* remove string from stack */ |
| 143 | return ts; | 143 | return ts; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lobject.h,v 2.120 2017/04/30 20:43:26 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.121 2017/06/01 20:24:05 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 | */ |
| @@ -122,6 +122,7 @@ typedef struct lua_TValue { | |||
| 122 | 122 | ||
| 123 | 123 | ||
| 124 | #define val_(o) ((o)->value_) | 124 | #define val_(o) ((o)->value_) |
| 125 | #define valraw(o) (&val_(o)) | ||
| 125 | 126 | ||
| 126 | 127 | ||
| 127 | /* raw type tag of a TValue */ | 128 | /* raw type tag of a TValue */ |
| @@ -131,7 +132,8 @@ typedef struct lua_TValue { | |||
| 131 | #define novariant(x) ((x) & 0x0F) | 132 | #define novariant(x) ((x) & 0x0F) |
| 132 | 133 | ||
| 133 | /* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ | 134 | /* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ |
| 134 | #define ttype(o) (rttype(o) & 0x3F) | 135 | #define ttyperaw(t) ((t) & 0x3F) |
| 136 | #define ttype(o) ttyperaw(rttype(o)) | ||
| 135 | 137 | ||
| 136 | /* type tag of a TValue with no variants (bits 0-3) */ | 138 | /* type tag of a TValue with no variants (bits 0-3) */ |
| 137 | #define ttnov(o) (novariant(rttype(o))) | 139 | #define ttnov(o) (novariant(rttype(o))) |
| @@ -157,7 +159,19 @@ typedef struct lua_TValue { | |||
| 157 | #define ttislcf(o) checktag((o), LUA_TLCF) | 159 | #define ttislcf(o) checktag((o), LUA_TLCF) |
| 158 | #define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) | 160 | #define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) |
| 159 | #define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) | 161 | #define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) |
| 160 | #define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) | 162 | |
| 163 | |||
| 164 | /* | ||
| 165 | ** Macros to access unstructured values (may come both from | ||
| 166 | ** 'TValue's and table keys) | ||
| 167 | */ | ||
| 168 | #define ivalueraw(v) ((v).i) | ||
| 169 | #define fltvalueraw(v) ((v).n) | ||
| 170 | #define gcvalueraw(v) ((v).gc) | ||
| 171 | #define pvalueraw(v) ((v).p) | ||
| 172 | #define tsvalueraw(v) (gco2ts((v).gc)) | ||
| 173 | #define fvalueraw(v) ((v).f) | ||
| 174 | #define bvalueraw(v) ((v).b) | ||
| 161 | 175 | ||
| 162 | 176 | ||
| 163 | /* Macros to access values */ | 177 | /* Macros to access values */ |
| @@ -176,8 +190,6 @@ typedef struct lua_TValue { | |||
| 176 | #define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) | 190 | #define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) |
| 177 | #define bvalue(o) check_exp(ttisboolean(o), val_(o).b) | 191 | #define bvalue(o) check_exp(ttisboolean(o), val_(o).b) |
| 178 | #define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) | 192 | #define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) |
| 179 | /* a dead value may get the 'gc' field, but cannot access its contents */ | ||
| 180 | #define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) | ||
| 181 | 193 | ||
| 182 | #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) | 194 | #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) |
| 183 | 195 | ||
| @@ -185,6 +197,12 @@ typedef struct lua_TValue { | |||
| 185 | #define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) | 197 | #define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) |
| 186 | 198 | ||
| 187 | 199 | ||
| 200 | /* | ||
| 201 | ** Protected access to objects in values | ||
| 202 | */ | ||
| 203 | #define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) | ||
| 204 | |||
| 205 | |||
| 188 | /* Macros for internal tests */ | 206 | /* Macros for internal tests */ |
| 189 | #define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) | 207 | #define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) |
| 190 | 208 | ||
| @@ -253,8 +271,6 @@ typedef struct lua_TValue { | |||
| 253 | val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ | 271 | val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ |
| 254 | checkliveness(L,io); } | 272 | checkliveness(L,io); } |
| 255 | 273 | ||
| 256 | #define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) | ||
| 257 | |||
| 258 | 274 | ||
| 259 | 275 | ||
| 260 | #define setobj(L,obj1,obj2) \ | 276 | #define setobj(L,obj1,obj2) \ |
| @@ -485,26 +501,37 @@ typedef union Closure { | |||
| 485 | ** Tables | 501 | ** Tables |
| 486 | */ | 502 | */ |
| 487 | 503 | ||
| 488 | typedef union TKey { | 504 | |
| 489 | struct { | 505 | /* |
| 490 | TValuefields; | 506 | ** Nodes for Hash tables. A pack of two TValue's (key-value pairs) |
| 491 | int next; /* for chaining (offset for next node) */ | 507 | ** plus a 'next' field to link colliding entries. The distribuition |
| 492 | } nk; | 508 | ** of the key's fields ('key_tt' and 'key_val') not forming a proper |
| 493 | TValue tvk; | 509 | ** 'TValue' allows for a smaller size for 'Node' both in 4-byte |
| 494 | } TKey; | 510 | ** and 8-byte alignments. |
| 511 | */ | ||
| 512 | typedef union Node { | ||
| 513 | struct NodeKey { | ||
| 514 | TValuefields; /* fields for value */ | ||
| 515 | lu_byte key_tt; /* key type */ | ||
| 516 | int next; /* for chaining */ | ||
| 517 | Value key_val; /* key value */ | ||
| 518 | } u; | ||
| 519 | TValue i_val; /* direct access to node's value as a proper 'TValue' */ | ||
| 520 | } Node; | ||
| 495 | 521 | ||
| 496 | 522 | ||
| 497 | /* copy a value into a key without messing up field 'next' */ | 523 | /* copy a value into a key */ |
| 498 | #define setnodekey(L,key,obj) \ | 524 | #define setnodekey(L,node,obj) \ |
| 499 | { TKey *k_=(key); const TValue *io_=(obj); \ | 525 | { Node *n_=(node); const TValue *io_=(obj); \ |
| 500 | k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ | 526 | n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \ |
| 501 | (void)L; checkliveness(L,io_); } | 527 | (void)L; checkliveness(L,io_); } |
| 502 | 528 | ||
| 503 | 529 | ||
| 504 | typedef struct Node { | 530 | /* copy a value from a key */ |
| 505 | TValue i_val; | 531 | #define getnodekey(L,obj,node) \ |
| 506 | TKey i_key; | 532 | { TValue *io_=(obj); const Node *n_=(node); \ |
| 507 | } Node; | 533 | io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \ |
| 534 | (void)L; checkliveness(L,io_); } | ||
| 508 | 535 | ||
| 509 | 536 | ||
| 510 | typedef struct Table { | 537 | typedef struct Table { |
| @@ -520,6 +547,33 @@ typedef struct Table { | |||
| 520 | } Table; | 547 | } Table; |
| 521 | 548 | ||
| 522 | 549 | ||
| 550 | /* | ||
| 551 | ** Macros to manipulate keys inserted in nodes | ||
| 552 | */ | ||
| 553 | #define keytt(node) ((node)->u.key_tt) | ||
| 554 | #define keyval(node) ((node)->u.key_val) | ||
| 555 | |||
| 556 | #define keyisnil(node) (keytt(node) == LUA_TNIL) | ||
| 557 | #define keyisinteger(node) (keytt(node) == LUA_TNUMINT) | ||
| 558 | #define keyival(node) (keyval(node).i) | ||
| 559 | #define keyisshrstr(node) (keytt(node) == ctb(LUA_TSHRSTR)) | ||
| 560 | #define keystrval(node) (gco2ts(keyval(node).gc)) | ||
| 561 | |||
| 562 | #define keyisdead(node) (keytt(node) == LUA_TDEADKEY) | ||
| 563 | |||
| 564 | #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 | |||
| 571 | #define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE) | ||
| 572 | |||
| 573 | #define gckey(n) (keyval(n).gc) | ||
| 574 | #define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL) | ||
| 575 | |||
| 576 | |||
| 523 | 577 | ||
| 524 | /* | 578 | /* |
| 525 | ** 'module' operation for hashing (size is always a power of 2) | 579 | ** 'module' operation for hashing (size is always a power of 2) |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltable.c,v 2.121 2017/05/19 12:47:00 roberto Exp roberto $ | 2 | ** $Id: ltable.c,v 2.122 2017/05/19 12:57:10 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 | */ |
| @@ -75,8 +75,8 @@ | |||
| 75 | #define dummynode (&dummynode_) | 75 | #define dummynode (&dummynode_) |
| 76 | 76 | ||
| 77 | static const Node dummynode_ = { | 77 | static const Node dummynode_ = { |
| 78 | {NILCONSTANT}, /* value */ | 78 | {{NULL}, LUA_TNIL, /* value's value and type */ |
| 79 | {{NILCONSTANT, 0}} /* key */ | 79 | LUA_TNIL, 0, {NULL}} /* key type, next, and key value */ |
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| 82 | 82 | ||
| @@ -111,43 +111,79 @@ static int l_hashfloat (lua_Number n) { | |||
| 111 | 111 | ||
| 112 | 112 | ||
| 113 | /* | 113 | /* |
| 114 | ** returns the 'main' position of an element in a table (that is, the index | 114 | ** returns the 'main' position of an element in a table (that is, |
| 115 | ** of its hash value) | 115 | ** the index of its hash value). The key comes broken (tag in 'ktt' |
| 116 | ** and value in 'vkl') so that we can call it on keys inserted into | ||
| 117 | ** nodes. | ||
| 116 | */ | 118 | */ |
| 117 | static Node *mainposition (const Table *t, const TValue *key) { | 119 | static Node *mainposition (const Table *t, int ktt, const Value *kvl) { |
| 118 | switch (ttype(key)) { | 120 | switch (ttyperaw(ktt)) { |
| 119 | case LUA_TNUMINT: | 121 | case LUA_TNUMINT: |
| 120 | return hashint(t, ivalue(key)); | 122 | return hashint(t, ivalueraw(*kvl)); |
| 121 | case LUA_TNUMFLT: | 123 | case LUA_TNUMFLT: |
| 122 | return hashmod(t, l_hashfloat(fltvalue(key))); | 124 | return hashmod(t, l_hashfloat(fltvalueraw(*kvl))); |
| 123 | case LUA_TSHRSTR: | 125 | case LUA_TSHRSTR: |
| 124 | return hashstr(t, tsvalue(key)); | 126 | return hashstr(t, tsvalueraw(*kvl)); |
| 125 | case LUA_TLNGSTR: | 127 | case LUA_TLNGSTR: |
| 126 | return hashpow2(t, luaS_hashlongstr(tsvalue(key))); | 128 | return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl))); |
| 127 | case LUA_TBOOLEAN: | 129 | case LUA_TBOOLEAN: |
| 128 | return hashboolean(t, bvalue(key)); | 130 | return hashboolean(t, bvalueraw(*kvl)); |
| 129 | case LUA_TLIGHTUSERDATA: | 131 | case LUA_TLIGHTUSERDATA: |
| 130 | return hashpointer(t, pvalue(key)); | 132 | return hashpointer(t, pvalueraw(*kvl)); |
| 131 | case LUA_TLCF: | 133 | case LUA_TLCF: |
| 132 | return hashpointer(t, fvalue(key)); | 134 | return hashpointer(t, fvalueraw(*kvl)); |
| 133 | default: | 135 | default: |
| 134 | lua_assert(!ttisdeadkey(key)); | 136 | return hashpointer(t, gcvalueraw(*kvl)); |
| 135 | return hashpointer(t, gcvalue(key)); | ||
| 136 | } | 137 | } |
| 137 | } | 138 | } |
| 138 | 139 | ||
| 139 | 140 | ||
| 141 | static Node *mainpositionTV (const Table *t, const TValue *key) { | ||
| 142 | return mainposition(t, rttype(key), valraw(key)); | ||
| 143 | } | ||
| 144 | |||
| 145 | |||
| 140 | /* | 146 | /* |
| 141 | ** returns the index for 'key' if 'key' is an appropriate key to live in | 147 | ** Check whether key 'k1' is equal to the key in node 'n2'. |
| 142 | ** the array part of the table, 0 otherwise. | 148 | ** This equality is raw, so there are no metamethods. Floats |
| 149 | ** with integer values have been normalized, so integers cannot | ||
| 150 | ** be equal to floats. It is assumed that 'eqshrstr' is simply | ||
| 151 | ** pointer equality, so that short strings are handled in the | ||
| 152 | ** default case. | ||
| 143 | */ | 153 | */ |
| 144 | static unsigned int arrayindex (const TValue *key) { | 154 | static int equalkey (const TValue *k1, const Node *n2) { |
| 145 | if (ttisinteger(key)) { | 155 | if (rttype(k1) != keytt(n2)) /* not the same variants? */ |
| 146 | lua_Integer k = ivalue(key); | 156 | return 0; /* cannot be same key */ |
| 147 | if (0 < k && (lua_Unsigned)k <= MAXASIZE) | 157 | switch (ttype(k1)) { |
| 148 | return cast(unsigned int, k); /* 'key' is an appropriate array index */ | 158 | case LUA_TNIL: |
| 159 | return 1; | ||
| 160 | case LUA_TNUMINT: | ||
| 161 | return (ivalue(k1) == keyival(n2)); | ||
| 162 | case LUA_TNUMFLT: | ||
| 163 | return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2))); | ||
| 164 | case LUA_TBOOLEAN: | ||
| 165 | return bvalue(k1) == bvalueraw(keyval(n2)); | ||
| 166 | case LUA_TLIGHTUSERDATA: | ||
| 167 | return pvalue(k1) == pvalueraw(keyval(n2)); | ||
| 168 | case LUA_TLCF: | ||
| 169 | return fvalue(k1) == fvalueraw(keyval(n2)); | ||
| 170 | case LUA_TLNGSTR: | ||
| 171 | return luaS_eqlngstr(tsvalue(k1), keystrval(n2)); | ||
| 172 | default: | ||
| 173 | return gcvalue(k1) == gcvalueraw(keyval(n2)); | ||
| 149 | } | 174 | } |
| 150 | return 0; /* 'key' did not match some condition */ | 175 | } |
| 176 | |||
| 177 | |||
| 178 | /* | ||
| 179 | ** returns the index for 'k' if 'k' is an appropriate key to live in | ||
| 180 | ** the array part of a table, 0 otherwise. | ||
| 181 | */ | ||
| 182 | static unsigned int arrayindex (lua_Integer k) { | ||
| 183 | if (0 < k && l_castS2U(k) <= MAXASIZE) | ||
| 184 | return cast(unsigned int, k); /* 'key' is an appropriate array index */ | ||
| 185 | else | ||
| 186 | return 0; | ||
| 151 | } | 187 | } |
| 152 | 188 | ||
| 153 | 189 | ||
| @@ -159,17 +195,17 @@ static unsigned int arrayindex (const TValue *key) { | |||
| 159 | static unsigned int findindex (lua_State *L, Table *t, StkId key) { | 195 | static unsigned int findindex (lua_State *L, Table *t, StkId key) { |
| 160 | unsigned int i; | 196 | unsigned int i; |
| 161 | if (ttisnil(key)) return 0; /* first iteration */ | 197 | if (ttisnil(key)) return 0; /* first iteration */ |
| 162 | i = arrayindex(key); | 198 | i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0; |
| 163 | if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ | 199 | if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ |
| 164 | return i; /* yes; that's the index */ | 200 | return i; /* yes; that's the index */ |
| 165 | else { | 201 | else { |
| 166 | int nx; | 202 | int nx; |
| 167 | Node *n = mainposition(t, key); | 203 | Node *n = mainpositionTV(t, key); |
| 168 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 204 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
| 169 | /* key may be dead already, but it is ok to use it in 'next' */ | 205 | /* key may be dead already, but it is ok to use it in 'next' */ |
| 170 | if (luaV_rawequalobj(gkey(n), key) || | 206 | if (equalkey(key, n) || |
| 171 | (ttisdeadkey(gkey(n)) && iscollectable(key) && | 207 | (keyisdead(n) && iscollectable(key) && |
| 172 | deadvalue(gkey(n)) == gcvalue(key))) { | 208 | deadkey(n) == gcvalue(key))) { |
| 173 | i = cast_int(n - gnode(t, 0)); /* key index in hash table */ | 209 | i = cast_int(n - gnode(t, 0)); /* key index in hash table */ |
| 174 | /* hash elements are numbered after array ones */ | 210 | /* hash elements are numbered after array ones */ |
| 175 | return (i + 1) + t->sizearray; | 211 | return (i + 1) + t->sizearray; |
| @@ -194,8 +230,9 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
| 194 | } | 230 | } |
| 195 | for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ | 231 | for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ |
| 196 | if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ | 232 | if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ |
| 197 | setobj2s(L, key, gkey(gnode(t, i))); | 233 | Node *n = gnode(t, i); |
| 198 | setobj2s(L, key+1, gval(gnode(t, i))); | 234 | getnodekey(L, key, n); |
| 235 | setobj2s(L, key + 1, gval(n)); | ||
| 199 | return 1; | 236 | return 1; |
| 200 | } | 237 | } |
| 201 | } | 238 | } |
| @@ -239,7 +276,7 @@ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { | |||
| 239 | } | 276 | } |
| 240 | 277 | ||
| 241 | 278 | ||
| 242 | static int countint (const TValue *key, unsigned int *nums) { | 279 | static int countint (lua_Integer key, unsigned int *nums) { |
| 243 | unsigned int k = arrayindex(key); | 280 | unsigned int k = arrayindex(key); |
| 244 | if (k != 0) { /* is 'key' an appropriate array index? */ | 281 | if (k != 0) { /* is 'key' an appropriate array index? */ |
| 245 | nums[luaO_ceillog2(k)]++; /* count as such */ | 282 | nums[luaO_ceillog2(k)]++; /* count as such */ |
| @@ -288,7 +325,8 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { | |||
| 288 | while (i--) { | 325 | while (i--) { |
| 289 | Node *n = &t->node[i]; | 326 | Node *n = &t->node[i]; |
| 290 | if (!ttisnil(gval(n))) { | 327 | if (!ttisnil(gval(n))) { |
| 291 | ause += countint(gkey(n), nums); | 328 | if (keyisinteger(n)) |
| 329 | ause += countint(keyival(n), nums); | ||
| 292 | totaluse++; | 330 | totaluse++; |
| 293 | } | 331 | } |
| 294 | } | 332 | } |
| @@ -322,7 +360,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
| 322 | for (i = 0; i < (int)size; i++) { | 360 | for (i = 0; i < (int)size; i++) { |
| 323 | Node *n = gnode(t, i); | 361 | Node *n = gnode(t, i); |
| 324 | gnext(n) = 0; | 362 | gnext(n) = 0; |
| 325 | setnilvalue(wgkey(n)); | 363 | setnilkey(n); |
| 326 | setnilvalue(gval(n)); | 364 | setnilvalue(gval(n)); |
| 327 | } | 365 | } |
| 328 | t->lsizenode = cast_byte(lsize); | 366 | t->lsizenode = cast_byte(lsize); |
| @@ -358,7 +396,8 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize, | |||
| 358 | if (!ttisnil(gval(old))) { | 396 | if (!ttisnil(gval(old))) { |
| 359 | /* doesn't need barrier/invalidate cache, as entry was | 397 | /* doesn't need barrier/invalidate cache, as entry was |
| 360 | already present in the table */ | 398 | already present in the table */ |
| 361 | setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); | 399 | TValue k; getnodekey(L, &k, old); |
| 400 | setobjt2t(L, luaH_set(L, t, &k), gval(old)); | ||
| 362 | } | 401 | } |
| 363 | } | 402 | } |
| 364 | if (oldhsize > 0) /* not the dummy node? */ | 403 | if (oldhsize > 0) /* not the dummy node? */ |
| @@ -385,7 +424,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) { | |||
| 385 | totaluse = na; /* all those keys are integer keys */ | 424 | totaluse = na; /* all those keys are integer keys */ |
| 386 | totaluse += numusehash(t, nums, &na); /* count keys in hash part */ | 425 | totaluse += numusehash(t, nums, &na); /* count keys in hash part */ |
| 387 | /* count extra key */ | 426 | /* count extra key */ |
| 388 | na += countint(ek, nums); | 427 | if (ttisinteger(ek)) |
| 428 | na += countint(ivalue(ek), nums); | ||
| 389 | totaluse++; | 429 | totaluse++; |
| 390 | /* compute new size for array part */ | 430 | /* compute new size for array part */ |
| 391 | asize = computesizes(nums, &na); | 431 | asize = computesizes(nums, &na); |
| @@ -424,7 +464,7 @@ static Node *getfreepos (Table *t) { | |||
| 424 | if (!isdummy(t)) { | 464 | if (!isdummy(t)) { |
| 425 | while (t->lastfree > t->node) { | 465 | while (t->lastfree > t->node) { |
| 426 | t->lastfree--; | 466 | t->lastfree--; |
| 427 | if (ttisnil(gkey(t->lastfree))) | 467 | if (keyisnil(t->lastfree)) |
| 428 | return t->lastfree; | 468 | return t->lastfree; |
| 429 | } | 469 | } |
| 430 | } | 470 | } |
| @@ -453,7 +493,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { | |||
| 453 | else if (luai_numisnan(fltvalue(key))) | 493 | else if (luai_numisnan(fltvalue(key))) |
| 454 | luaG_runerror(L, "table index is NaN"); | 494 | luaG_runerror(L, "table index is NaN"); |
| 455 | } | 495 | } |
| 456 | mp = mainposition(t, key); | 496 | mp = mainpositionTV(t, key); |
| 457 | if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */ | 497 | if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */ |
| 458 | Node *othern; | 498 | Node *othern; |
| 459 | Node *f = getfreepos(t); /* get a free place */ | 499 | Node *f = getfreepos(t); /* get a free place */ |
| @@ -463,7 +503,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { | |||
| 463 | return luaH_set(L, t, key); /* insert key into grown table */ | 503 | return luaH_set(L, t, key); /* insert key into grown table */ |
| 464 | } | 504 | } |
| 465 | lua_assert(!isdummy(t)); | 505 | lua_assert(!isdummy(t)); |
| 466 | othern = mainposition(t, gkey(mp)); | 506 | othern = mainposition(t, keytt(mp), &keyval(mp)); |
| 467 | if (othern != mp) { /* is colliding node out of its main position? */ | 507 | if (othern != mp) { /* is colliding node out of its main position? */ |
| 468 | /* yes; move colliding node into free position */ | 508 | /* yes; move colliding node into free position */ |
| 469 | while (othern + gnext(othern) != mp) /* find previous */ | 509 | while (othern + gnext(othern) != mp) /* find previous */ |
| @@ -485,7 +525,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { | |||
| 485 | mp = f; | 525 | mp = f; |
| 486 | } | 526 | } |
| 487 | } | 527 | } |
| 488 | setnodekey(L, &mp->i_key, key); | 528 | setnodekey(L, mp, key); |
| 489 | luaC_barrierback(L, t, key); | 529 | luaC_barrierback(L, t, key); |
| 490 | lua_assert(ttisnil(gval(mp))); | 530 | lua_assert(ttisnil(gval(mp))); |
| 491 | return gval(mp); | 531 | return gval(mp); |
| @@ -502,7 +542,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) { | |||
| 502 | else { | 542 | else { |
| 503 | Node *n = hashint(t, key); | 543 | Node *n = hashint(t, key); |
| 504 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 544 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
| 505 | if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) | 545 | if (keyisinteger(n) && keyival(n) == key) |
| 506 | return gval(n); /* that's it */ | 546 | return gval(n); /* that's it */ |
| 507 | else { | 547 | else { |
| 508 | int nx = gnext(n); | 548 | int nx = gnext(n); |
| @@ -522,8 +562,7 @@ const TValue *luaH_getshortstr (Table *t, TString *key) { | |||
| 522 | Node *n = hashstr(t, key); | 562 | Node *n = hashstr(t, key); |
| 523 | lua_assert(key->tt == LUA_TSHRSTR); | 563 | lua_assert(key->tt == LUA_TSHRSTR); |
| 524 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 564 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
| 525 | const TValue *k = gkey(n); | 565 | if (keyisshrstr(n) && eqshrstr(keystrval(n), key)) |
| 526 | if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) | ||
| 527 | return gval(n); /* that's it */ | 566 | return gval(n); /* that's it */ |
| 528 | else { | 567 | else { |
| 529 | int nx = gnext(n); | 568 | int nx = gnext(n); |
| @@ -540,9 +579,9 @@ const TValue *luaH_getshortstr (Table *t, TString *key) { | |||
| 540 | ** which may be in array part, nor for floats with integral values.) | 579 | ** which may be in array part, nor for floats with integral values.) |
| 541 | */ | 580 | */ |
| 542 | static const TValue *getgeneric (Table *t, const TValue *key) { | 581 | static const TValue *getgeneric (Table *t, const TValue *key) { |
| 543 | Node *n = mainposition(t, key); | 582 | Node *n = mainpositionTV(t, key); |
| 544 | for (;;) { /* check whether 'key' is somewhere in the chain */ | 583 | for (;;) { /* check whether 'key' is somewhere in the chain */ |
| 545 | if (luaV_rawequalobj(gkey(n), key)) | 584 | if (equalkey(key, n)) |
| 546 | return gval(n); /* that's it */ | 585 | return gval(n); /* that's it */ |
| 547 | else { | 586 | else { |
| 548 | int nx = gnext(n); | 587 | int nx = gnext(n); |
| @@ -683,7 +722,7 @@ lua_Unsigned luaH_getn (Table *t) { | |||
| 683 | #if defined(LUA_DEBUG) | 722 | #if defined(LUA_DEBUG) |
| 684 | 723 | ||
| 685 | Node *luaH_mainposition (const Table *t, const TValue *key) { | 724 | Node *luaH_mainposition (const Table *t, const TValue *key) { |
| 686 | return mainposition(t, key); | 725 | return mainpositionTV(t, key); |
| 687 | } | 726 | } |
| 688 | 727 | ||
| 689 | int luaH_isdummy (const Table *t) { return isdummy(t); } | 728 | int luaH_isdummy (const Table *t) { return isdummy(t); } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp roberto $ | 2 | ** $Id: ltable.h,v 2.24 2017/05/19 12:48:15 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 | */ |
| @@ -12,18 +12,9 @@ | |||
| 12 | 12 | ||
| 13 | #define gnode(t,i) (&(t)->node[i]) | 13 | #define gnode(t,i) (&(t)->node[i]) |
| 14 | #define gval(n) (&(n)->i_val) | 14 | #define gval(n) (&(n)->i_val) |
| 15 | #define gnext(n) ((n)->i_key.nk.next) | 15 | #define gnext(n) ((n)->u.next) |
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | /* 'const' to avoid wrong writings that can mess up field 'next' */ | ||
| 19 | #define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) | ||
| 20 | |||
| 21 | /* | ||
| 22 | ** writable version of 'gkey'; allows updates to individual fields, | ||
| 23 | ** but not to the whole (which has incompatible type) | ||
| 24 | */ | ||
| 25 | #define wgkey(n) (&(n)->i_key.nk) | ||
| 26 | |||
| 27 | #define invalidateTMcache(t) ((t)->flags = 0) | 18 | #define invalidateTMcache(t) ((t)->flags = 0) |
| 28 | 19 | ||
| 29 | 20 | ||
| @@ -35,9 +26,8 @@ | |||
| 35 | #define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) | 26 | #define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) |
| 36 | 27 | ||
| 37 | 28 | ||
| 38 | /* returns the key, given the value of a table entry */ | 29 | /* returns the Node, given the value of a table entry */ |
| 39 | #define keyfromval(v) \ | 30 | #define nodefromval(v) cast(Node *, (v)) |
| 40 | (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) | ||
| 41 | 31 | ||
| 42 | 32 | ||
| 43 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); | 33 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.c,v 2.217 2017/05/04 13:32:01 roberto Exp $ | 2 | ** $Id: ltests.c,v 2.218 2017/05/31 18:54:58 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 | */ |
| @@ -253,8 +253,10 @@ static void checktable (global_State *g, Table *h) { | |||
| 253 | checkvalref(g, hgc, &h->array[i]); | 253 | checkvalref(g, hgc, &h->array[i]); |
| 254 | for (n = gnode(h, 0); n < limit; n++) { | 254 | for (n = gnode(h, 0); n < limit; n++) { |
| 255 | if (!ttisnil(gval(n))) { | 255 | if (!ttisnil(gval(n))) { |
| 256 | lua_assert(!ttisnil(gkey(n))); | 256 | TValue k; |
| 257 | checkvalref(g, hgc, gkey(n)); | 257 | getnodekey(g->mainthread, &k, n); |
| 258 | lua_assert(!keyisnil(n)); | ||
| 259 | checkvalref(g, hgc, &k); | ||
| 258 | checkvalref(g, hgc, gval(n)); | 260 | checkvalref(g, hgc, gval(n)); |
| 259 | } | 261 | } |
| 260 | } | 262 | } |
| @@ -802,10 +804,12 @@ static int table_query (lua_State *L) { | |||
| 802 | lua_pushnil(L); | 804 | lua_pushnil(L); |
| 803 | } | 805 | } |
| 804 | else if ((i -= t->sizearray) < sizenode(t)) { | 806 | else if ((i -= t->sizearray) < sizenode(t)) { |
| 807 | TValue k; | ||
| 808 | getnodekey(L, &k, gnode(t, i)); | ||
| 805 | if (!ttisnil(gval(gnode(t, i))) || | 809 | if (!ttisnil(gval(gnode(t, i))) || |
| 806 | ttisnil(gkey(gnode(t, i))) || | 810 | ttisnil(&k) || |
| 807 | ttisnumber(gkey(gnode(t, i)))) { | 811 | ttisnumber(&k)) { |
| 808 | pushobject(L, gkey(gnode(t, i))); | 812 | pushobject(L, &k); |
| 809 | } | 813 | } |
| 810 | else | 814 | else |
| 811 | lua_pushliteral(L, "<undef>"); | 815 | lua_pushliteral(L, "<undef>"); |
