diff options
-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>"); |