diff options
Diffstat (limited to 'src/lj_tab.c')
-rw-r--r-- | src/lj_tab.c | 222 |
1 files changed, 131 insertions, 91 deletions
diff --git a/src/lj_tab.c b/src/lj_tab.c index c5b6bcbf..c3609b38 100644 --- a/src/lj_tab.c +++ b/src/lj_tab.c | |||
@@ -16,25 +16,10 @@ | |||
16 | 16 | ||
17 | /* -- Object hashing ------------------------------------------------------ */ | 17 | /* -- Object hashing ------------------------------------------------------ */ |
18 | 18 | ||
19 | /* Hash values are masked with the table hash mask and used as an index. */ | ||
20 | static LJ_AINLINE Node *hashmask(const GCtab *t, uint32_t hash) | ||
21 | { | ||
22 | Node *n = noderef(t->node); | ||
23 | return &n[hash & t->hmask]; | ||
24 | } | ||
25 | |||
26 | /* String hashes are precomputed when they are interned. */ | ||
27 | #define hashstr(t, s) hashmask(t, (s)->hash) | ||
28 | |||
29 | #define hashlohi(t, lo, hi) hashmask((t), hashrot((lo), (hi))) | ||
30 | #define hashnum(t, o) hashlohi((t), (o)->u32.lo, ((o)->u32.hi << 1)) | ||
31 | #define hashptr(t, p) hashlohi((t), u32ptr(p), u32ptr(p) + HASH_BIAS) | ||
32 | #define hashgcref(t, r) hashlohi((t), gcrefu(r), gcrefu(r) + HASH_BIAS) | ||
33 | |||
34 | /* Hash an arbitrary key and return its anchor position in the hash table. */ | 19 | /* Hash an arbitrary key and return its anchor position in the hash table. */ |
35 | static Node *hashkey(const GCtab *t, cTValue *key) | 20 | static Node *hashkey(const GCtab *t, cTValue *key) |
36 | { | 21 | { |
37 | lua_assert(!tvisint(key)); | 22 | lj_assertX(!tvisint(key), "attempt to hash integer"); |
38 | if (tvisstr(key)) | 23 | if (tvisstr(key)) |
39 | return hashstr(t, strV(key)); | 24 | return hashstr(t, strV(key)); |
40 | else if (tvisnum(key)) | 25 | else if (tvisnum(key)) |
@@ -53,13 +38,13 @@ static LJ_AINLINE void newhpart(lua_State *L, GCtab *t, uint32_t hbits) | |||
53 | { | 38 | { |
54 | uint32_t hsize; | 39 | uint32_t hsize; |
55 | Node *node; | 40 | Node *node; |
56 | lua_assert(hbits != 0); | 41 | lj_assertL(hbits != 0, "zero hash size"); |
57 | if (hbits > LJ_MAX_HBITS) | 42 | if (hbits > LJ_MAX_HBITS) |
58 | lj_err_msg(L, LJ_ERR_TABOV); | 43 | lj_err_msg(L, LJ_ERR_TABOV); |
59 | hsize = 1u << hbits; | 44 | hsize = 1u << hbits; |
60 | node = lj_mem_newvec(L, hsize, Node); | 45 | node = lj_mem_newvec(L, hsize, Node); |
61 | setmref(node->freetop, &node[hsize]); | ||
62 | setmref(t->node, node); | 46 | setmref(t->node, node); |
47 | setfreetop(t, node, &node[hsize]); | ||
63 | t->hmask = hsize-1; | 48 | t->hmask = hsize-1; |
64 | } | 49 | } |
65 | 50 | ||
@@ -74,7 +59,7 @@ static LJ_AINLINE void clearhpart(GCtab *t) | |||
74 | { | 59 | { |
75 | uint32_t i, hmask = t->hmask; | 60 | uint32_t i, hmask = t->hmask; |
76 | Node *node = noderef(t->node); | 61 | Node *node = noderef(t->node); |
77 | lua_assert(t->hmask != 0); | 62 | lj_assertX(t->hmask != 0, "empty hash part"); |
78 | for (i = 0; i <= hmask; i++) { | 63 | for (i = 0; i <= hmask; i++) { |
79 | Node *n = &node[i]; | 64 | Node *n = &node[i]; |
80 | setmref(n->next, NULL); | 65 | setmref(n->next, NULL); |
@@ -98,7 +83,8 @@ static GCtab *newtab(lua_State *L, uint32_t asize, uint32_t hbits) | |||
98 | GCtab *t; | 83 | GCtab *t; |
99 | /* First try to colocate the array part. */ | 84 | /* First try to colocate the array part. */ |
100 | if (LJ_MAX_COLOSIZE != 0 && asize > 0 && asize <= LJ_MAX_COLOSIZE) { | 85 | if (LJ_MAX_COLOSIZE != 0 && asize > 0 && asize <= LJ_MAX_COLOSIZE) { |
101 | lua_assert((sizeof(GCtab) & 7) == 0); | 86 | Node *nilnode; |
87 | lj_assertL((sizeof(GCtab) & 7) == 0, "bad GCtab size"); | ||
102 | t = (GCtab *)lj_mem_newgco(L, sizetabcolo(asize)); | 88 | t = (GCtab *)lj_mem_newgco(L, sizetabcolo(asize)); |
103 | t->gct = ~LJ_TTAB; | 89 | t->gct = ~LJ_TTAB; |
104 | t->nomm = (uint8_t)~0; | 90 | t->nomm = (uint8_t)~0; |
@@ -107,8 +93,13 @@ static GCtab *newtab(lua_State *L, uint32_t asize, uint32_t hbits) | |||
107 | setgcrefnull(t->metatable); | 93 | setgcrefnull(t->metatable); |
108 | t->asize = asize; | 94 | t->asize = asize; |
109 | t->hmask = 0; | 95 | t->hmask = 0; |
110 | setmref(t->node, &G(L)->nilnode); | 96 | nilnode = &G(L)->nilnode; |
97 | setmref(t->node, nilnode); | ||
98 | #if LJ_GC64 | ||
99 | setmref(t->freetop, nilnode); | ||
100 | #endif | ||
111 | } else { /* Otherwise separately allocate the array part. */ | 101 | } else { /* Otherwise separately allocate the array part. */ |
102 | Node *nilnode; | ||
112 | t = lj_mem_newobj(L, GCtab); | 103 | t = lj_mem_newobj(L, GCtab); |
113 | t->gct = ~LJ_TTAB; | 104 | t->gct = ~LJ_TTAB; |
114 | t->nomm = (uint8_t)~0; | 105 | t->nomm = (uint8_t)~0; |
@@ -117,7 +108,11 @@ static GCtab *newtab(lua_State *L, uint32_t asize, uint32_t hbits) | |||
117 | setgcrefnull(t->metatable); | 108 | setgcrefnull(t->metatable); |
118 | t->asize = 0; /* In case the array allocation fails. */ | 109 | t->asize = 0; /* In case the array allocation fails. */ |
119 | t->hmask = 0; | 110 | t->hmask = 0; |
120 | setmref(t->node, &G(L)->nilnode); | 111 | nilnode = &G(L)->nilnode; |
112 | setmref(t->node, nilnode); | ||
113 | #if LJ_GC64 | ||
114 | setmref(t->freetop, nilnode); | ||
115 | #endif | ||
121 | if (asize > 0) { | 116 | if (asize > 0) { |
122 | if (asize > LJ_MAX_ASIZE) | 117 | if (asize > LJ_MAX_ASIZE) |
123 | lj_err_msg(L, LJ_ERR_TABOV); | 118 | lj_err_msg(L, LJ_ERR_TABOV); |
@@ -149,6 +144,12 @@ GCtab *lj_tab_new(lua_State *L, uint32_t asize, uint32_t hbits) | |||
149 | return t; | 144 | return t; |
150 | } | 145 | } |
151 | 146 | ||
147 | /* The API of this function conforms to lua_createtable(). */ | ||
148 | GCtab *lj_tab_new_ah(lua_State *L, int32_t a, int32_t h) | ||
149 | { | ||
150 | return lj_tab_new(L, (uint32_t)(a > 0 ? a+1 : 0), hsize2hbits(h)); | ||
151 | } | ||
152 | |||
152 | #if LJ_HASJIT | 153 | #if LJ_HASJIT |
153 | GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize) | 154 | GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize) |
154 | { | 155 | { |
@@ -165,7 +166,8 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt) | |||
165 | GCtab *t; | 166 | GCtab *t; |
166 | uint32_t asize, hmask; | 167 | uint32_t asize, hmask; |
167 | t = newtab(L, kt->asize, kt->hmask > 0 ? lj_fls(kt->hmask)+1 : 0); | 168 | t = newtab(L, kt->asize, kt->hmask > 0 ? lj_fls(kt->hmask)+1 : 0); |
168 | lua_assert(kt->asize == t->asize && kt->hmask == t->hmask); | 169 | lj_assertL(kt->asize == t->asize && kt->hmask == t->hmask, |
170 | "mismatched size of table and template"); | ||
169 | t->nomm = 0; /* Keys with metamethod names may be present. */ | 171 | t->nomm = 0; /* Keys with metamethod names may be present. */ |
170 | asize = kt->asize; | 172 | asize = kt->asize; |
171 | if (asize > 0) { | 173 | if (asize > 0) { |
@@ -185,7 +187,7 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt) | |||
185 | Node *node = noderef(t->node); | 187 | Node *node = noderef(t->node); |
186 | Node *knode = noderef(kt->node); | 188 | Node *knode = noderef(kt->node); |
187 | ptrdiff_t d = (char *)node - (char *)knode; | 189 | ptrdiff_t d = (char *)node - (char *)knode; |
188 | setmref(node->freetop, (Node *)((char *)noderef(knode->freetop) + d)); | 190 | setfreetop(t, node, (Node *)((char *)getfreetop(kt, knode) + d)); |
189 | for (i = 0; i <= hmask; i++) { | 191 | for (i = 0; i <= hmask; i++) { |
190 | Node *kn = &knode[i]; | 192 | Node *kn = &knode[i]; |
191 | Node *n = &node[i]; | 193 | Node *n = &node[i]; |
@@ -198,6 +200,17 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt) | |||
198 | return t; | 200 | return t; |
199 | } | 201 | } |
200 | 202 | ||
203 | /* Clear a table. */ | ||
204 | void LJ_FASTCALL lj_tab_clear(GCtab *t) | ||
205 | { | ||
206 | clearapart(t); | ||
207 | if (t->hmask > 0) { | ||
208 | Node *node = noderef(t->node); | ||
209 | setfreetop(t, node, &node[t->hmask+1]); | ||
210 | clearhpart(t); | ||
211 | } | ||
212 | } | ||
213 | |||
201 | /* Free a table. */ | 214 | /* Free a table. */ |
202 | void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t) | 215 | void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t) |
203 | { | 216 | { |
@@ -214,7 +227,7 @@ void LJ_FASTCALL lj_tab_free(global_State *g, GCtab *t) | |||
214 | /* -- Table resizing ------------------------------------------------------ */ | 227 | /* -- Table resizing ------------------------------------------------------ */ |
215 | 228 | ||
216 | /* Resize a table to fit the new array/hash part sizes. */ | 229 | /* Resize a table to fit the new array/hash part sizes. */ |
217 | static void resizetab(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits) | 230 | void lj_tab_resize(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits) |
218 | { | 231 | { |
219 | Node *oldnode = noderef(t->node); | 232 | Node *oldnode = noderef(t->node); |
220 | uint32_t oldasize = t->asize; | 233 | uint32_t oldasize = t->asize; |
@@ -247,6 +260,9 @@ static void resizetab(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits) | |||
247 | } else { | 260 | } else { |
248 | global_State *g = G(L); | 261 | global_State *g = G(L); |
249 | setmref(t->node, &g->nilnode); | 262 | setmref(t->node, &g->nilnode); |
263 | #if LJ_GC64 | ||
264 | setmref(t->freetop, &g->nilnode); | ||
265 | #endif | ||
250 | t->hmask = 0; | 266 | t->hmask = 0; |
251 | } | 267 | } |
252 | if (asize < oldasize) { /* Array part shrinks? */ | 268 | if (asize < oldasize) { /* Array part shrinks? */ |
@@ -276,7 +292,7 @@ static void resizetab(lua_State *L, GCtab *t, uint32_t asize, uint32_t hbits) | |||
276 | 292 | ||
277 | static uint32_t countint(cTValue *key, uint32_t *bins) | 293 | static uint32_t countint(cTValue *key, uint32_t *bins) |
278 | { | 294 | { |
279 | lua_assert(!tvisint(key)); | 295 | lj_assertX(!tvisint(key), "bad integer key"); |
280 | if (tvisnum(key)) { | 296 | if (tvisnum(key)) { |
281 | lua_Number nk = numV(key); | 297 | lua_Number nk = numV(key); |
282 | int32_t k = lj_num2int(nk); | 298 | int32_t k = lj_num2int(nk); |
@@ -348,7 +364,7 @@ static void rehashtab(lua_State *L, GCtab *t, cTValue *ek) | |||
348 | asize += countint(ek, bins); | 364 | asize += countint(ek, bins); |
349 | na = bestasize(bins, &asize); | 365 | na = bestasize(bins, &asize); |
350 | total -= na; | 366 | total -= na; |
351 | resizetab(L, t, asize, hsize2hbits(total)); | 367 | lj_tab_resize(L, t, asize, hsize2hbits(total)); |
352 | } | 368 | } |
353 | 369 | ||
354 | #if LJ_HASFFI | 370 | #if LJ_HASFFI |
@@ -360,7 +376,7 @@ void lj_tab_rehash(lua_State *L, GCtab *t) | |||
360 | 376 | ||
361 | void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize) | 377 | void lj_tab_reasize(lua_State *L, GCtab *t, uint32_t nasize) |
362 | { | 378 | { |
363 | resizetab(L, t, nasize+1, t->hmask > 0 ? lj_fls(t->hmask)+1 : 0); | 379 | lj_tab_resize(L, t, nasize+1, t->hmask > 0 ? lj_fls(t->hmask)+1 : 0); |
364 | } | 380 | } |
365 | 381 | ||
366 | /* -- Table getters ------------------------------------------------------- */ | 382 | /* -- Table getters ------------------------------------------------------- */ |
@@ -378,7 +394,7 @@ cTValue * LJ_FASTCALL lj_tab_getinth(GCtab *t, int32_t key) | |||
378 | return NULL; | 394 | return NULL; |
379 | } | 395 | } |
380 | 396 | ||
381 | cTValue *lj_tab_getstr(GCtab *t, GCstr *key) | 397 | cTValue *lj_tab_getstr(GCtab *t, const GCstr *key) |
382 | { | 398 | { |
383 | Node *n = hashstr(t, key); | 399 | Node *n = hashstr(t, key); |
384 | do { | 400 | do { |
@@ -428,16 +444,17 @@ TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key) | |||
428 | Node *n = hashkey(t, key); | 444 | Node *n = hashkey(t, key); |
429 | if (!tvisnil(&n->val) || t->hmask == 0) { | 445 | if (!tvisnil(&n->val) || t->hmask == 0) { |
430 | Node *nodebase = noderef(t->node); | 446 | Node *nodebase = noderef(t->node); |
431 | Node *collide, *freenode = noderef(nodebase->freetop); | 447 | Node *collide, *freenode = getfreetop(t, nodebase); |
432 | lua_assert(freenode >= nodebase && freenode <= nodebase+t->hmask+1); | 448 | lj_assertL(freenode >= nodebase && freenode <= nodebase+t->hmask+1, |
449 | "bad freenode"); | ||
433 | do { | 450 | do { |
434 | if (freenode == nodebase) { /* No free node found? */ | 451 | if (freenode == nodebase) { /* No free node found? */ |
435 | rehashtab(L, t, key); /* Rehash table. */ | 452 | rehashtab(L, t, key); /* Rehash table. */ |
436 | return lj_tab_set(L, t, key); /* Retry key insertion. */ | 453 | return lj_tab_set(L, t, key); /* Retry key insertion. */ |
437 | } | 454 | } |
438 | } while (!tvisnil(&(--freenode)->key)); | 455 | } while (!tvisnil(&(--freenode)->key)); |
439 | setmref(nodebase->freetop, freenode); | 456 | setfreetop(t, nodebase, freenode); |
440 | lua_assert(freenode != &G(L)->nilnode); | 457 | lj_assertL(freenode != &G(L)->nilnode, "store to fallback hash"); |
441 | collide = hashkey(t, &n->key); | 458 | collide = hashkey(t, &n->key); |
442 | if (collide != n) { /* Colliding node not the main node? */ | 459 | if (collide != n) { /* Colliding node not the main node? */ |
443 | while (noderef(collide->next) != n) /* Find predecessor. */ | 460 | while (noderef(collide->next) != n) /* Find predecessor. */ |
@@ -493,7 +510,7 @@ TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key) | |||
493 | if (LJ_UNLIKELY(tvismzero(&n->key))) | 510 | if (LJ_UNLIKELY(tvismzero(&n->key))) |
494 | n->key.u64 = 0; | 511 | n->key.u64 = 0; |
495 | lj_gc_anybarriert(L, t); | 512 | lj_gc_anybarriert(L, t); |
496 | lua_assert(tvisnil(&n->val)); | 513 | lj_assertL(tvisnil(&n->val), "new hash slot is not empty"); |
497 | return &n->val; | 514 | return &n->val; |
498 | } | 515 | } |
499 | 516 | ||
@@ -510,7 +527,7 @@ TValue *lj_tab_setinth(lua_State *L, GCtab *t, int32_t key) | |||
510 | return lj_tab_newkey(L, t, &k); | 527 | return lj_tab_newkey(L, t, &k); |
511 | } | 528 | } |
512 | 529 | ||
513 | TValue *lj_tab_setstr(lua_State *L, GCtab *t, GCstr *key) | 530 | TValue *lj_tab_setstr(lua_State *L, GCtab *t, const GCstr *key) |
514 | { | 531 | { |
515 | TValue k; | 532 | TValue k; |
516 | Node *n = hashstr(t, key); | 533 | Node *n = hashstr(t, key); |
@@ -551,103 +568,126 @@ TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key) | |||
551 | 568 | ||
552 | /* -- Table traversal ----------------------------------------------------- */ | 569 | /* -- Table traversal ----------------------------------------------------- */ |
553 | 570 | ||
554 | /* Get the traversal index of a key. */ | 571 | /* Table traversal indexes: |
555 | static uint32_t keyindex(lua_State *L, GCtab *t, cTValue *key) | 572 | ** |
573 | ** Array key index: [0 .. t->asize-1] | ||
574 | ** Hash key index: [t->asize .. t->asize+t->hmask] | ||
575 | ** Invalid key: ~0 | ||
576 | */ | ||
577 | |||
578 | /* Get the successor traversal index of a key. */ | ||
579 | uint32_t LJ_FASTCALL lj_tab_keyindex(GCtab *t, cTValue *key) | ||
556 | { | 580 | { |
557 | TValue tmp; | 581 | TValue tmp; |
558 | if (tvisint(key)) { | 582 | if (tvisint(key)) { |
559 | int32_t k = intV(key); | 583 | int32_t k = intV(key); |
560 | if ((uint32_t)k < t->asize) | 584 | if ((uint32_t)k < t->asize) |
561 | return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */ | 585 | return (uint32_t)k + 1; |
562 | setnumV(&tmp, (lua_Number)k); | 586 | setnumV(&tmp, (lua_Number)k); |
563 | key = &tmp; | 587 | key = &tmp; |
564 | } else if (tvisnum(key)) { | 588 | } else if (tvisnum(key)) { |
565 | lua_Number nk = numV(key); | 589 | lua_Number nk = numV(key); |
566 | int32_t k = lj_num2int(nk); | 590 | int32_t k = lj_num2int(nk); |
567 | if ((uint32_t)k < t->asize && nk == (lua_Number)k) | 591 | if ((uint32_t)k < t->asize && nk == (lua_Number)k) |
568 | return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */ | 592 | return (uint32_t)k + 1; |
569 | } | 593 | } |
570 | if (!tvisnil(key)) { | 594 | if (!tvisnil(key)) { |
571 | Node *n = hashkey(t, key); | 595 | Node *n = hashkey(t, key); |
572 | do { | 596 | do { |
573 | if (lj_obj_equal(&n->key, key)) | 597 | if (lj_obj_equal(&n->key, key)) |
574 | return t->asize + (uint32_t)(n - noderef(t->node)); | 598 | return t->asize + (uint32_t)((n+1) - noderef(t->node)); |
575 | /* Hash key indexes: [t->asize..t->asize+t->nmask] */ | ||
576 | } while ((n = nextnode(n))); | 599 | } while ((n = nextnode(n))); |
577 | if (key->u32.hi == 0xfffe7fff) /* ITERN was despecialized while running. */ | 600 | if (key->u32.hi == LJ_KEYINDEX) /* Despecialized ITERN while running. */ |
578 | return key->u32.lo - 1; | 601 | return key->u32.lo; |
579 | lj_err_msg(L, LJ_ERR_NEXTIDX); | 602 | return ~0u; /* Invalid key to next. */ |
580 | return 0; /* unreachable */ | ||
581 | } | 603 | } |
582 | return ~0u; /* A nil key starts the traversal. */ | 604 | return 0; /* A nil key starts the traversal. */ |
583 | } | 605 | } |
584 | 606 | ||
585 | /* Advance to the next step in a table traversal. */ | 607 | /* Get the next key/value pair of a table traversal. */ |
586 | int lj_tab_next(lua_State *L, GCtab *t, TValue *key) | 608 | int lj_tab_next(GCtab *t, cTValue *key, TValue *o) |
587 | { | 609 | { |
588 | uint32_t i = keyindex(L, t, key); /* Find predecessor key index. */ | 610 | uint32_t idx = lj_tab_keyindex(t, key); /* Find successor index of key. */ |
589 | for (i++; i < t->asize; i++) /* First traverse the array keys. */ | 611 | /* First traverse the array part. */ |
590 | if (!tvisnil(arrayslot(t, i))) { | 612 | for (; idx < t->asize; idx++) { |
591 | setintV(key, i); | 613 | cTValue *a = arrayslot(t, idx); |
592 | copyTV(L, key+1, arrayslot(t, i)); | 614 | if (LJ_LIKELY(!tvisnil(a))) { |
615 | setintV(o, idx); | ||
616 | o[1] = *a; | ||
593 | return 1; | 617 | return 1; |
594 | } | 618 | } |
595 | for (i -= t->asize; i <= t->hmask; i++) { /* Then traverse the hash keys. */ | 619 | } |
596 | Node *n = &noderef(t->node)[i]; | 620 | idx -= t->asize; |
621 | /* Then traverse the hash part. */ | ||
622 | for (; idx <= t->hmask; idx++) { | ||
623 | Node *n = &noderef(t->node)[idx]; | ||
597 | if (!tvisnil(&n->val)) { | 624 | if (!tvisnil(&n->val)) { |
598 | copyTV(L, key, &n->key); | 625 | o[0] = n->key; |
599 | copyTV(L, key+1, &n->val); | 626 | o[1] = n->val; |
600 | return 1; | 627 | return 1; |
601 | } | 628 | } |
602 | } | 629 | } |
603 | return 0; /* End of traversal. */ | 630 | return (int32_t)idx < 0 ? -1 : 0; /* Invalid key or end of traversal. */ |
604 | } | 631 | } |
605 | 632 | ||
606 | /* -- Table length calculation -------------------------------------------- */ | 633 | /* -- Table length calculation -------------------------------------------- */ |
607 | 634 | ||
608 | static MSize unbound_search(GCtab *t, MSize j) | 635 | /* Compute table length. Slow path with mixed array/hash lookups. */ |
636 | LJ_NOINLINE static MSize tab_len_slow(GCtab *t, size_t hi) | ||
609 | { | 637 | { |
610 | cTValue *tv; | 638 | cTValue *tv; |
611 | MSize i = j; /* i is zero or a present index */ | 639 | size_t lo = hi; |
612 | j++; | 640 | hi++; |
613 | /* find `i' and `j' such that i is present and j is not */ | 641 | /* Widening search for an upper bound. */ |
614 | while ((tv = lj_tab_getint(t, (int32_t)j)) && !tvisnil(tv)) { | 642 | while ((tv = lj_tab_getint(t, (int32_t)hi)) && !tvisnil(tv)) { |
615 | i = j; | 643 | lo = hi; |
616 | j *= 2; | 644 | hi += hi; |
617 | if (j > (MSize)(INT_MAX-2)) { /* overflow? */ | 645 | if (hi > (size_t)(INT_MAX-2)) { /* Punt and do a linear search. */ |
618 | /* table was built with bad purposes: resort to linear search */ | 646 | lo = 1; |
619 | i = 1; | 647 | while ((tv = lj_tab_getint(t, (int32_t)lo)) && !tvisnil(tv)) lo++; |
620 | while ((tv = lj_tab_getint(t, (int32_t)i)) && !tvisnil(tv)) i++; | 648 | return (MSize)(lo - 1); |
621 | return i - 1; | ||
622 | } | 649 | } |
623 | } | 650 | } |
624 | /* now do a binary search between them */ | 651 | /* Binary search to find a non-nil to nil transition. */ |
625 | while (j - i > 1) { | 652 | while (hi - lo > 1) { |
626 | MSize m = (i+j)/2; | 653 | size_t mid = (lo+hi) >> 1; |
627 | cTValue *tvb = lj_tab_getint(t, (int32_t)m); | 654 | cTValue *tvb = lj_tab_getint(t, (int32_t)mid); |
628 | if (tvb && !tvisnil(tvb)) i = m; else j = m; | 655 | if (tvb && !tvisnil(tvb)) lo = mid; else hi = mid; |
629 | } | 656 | } |
630 | return i; | 657 | return (MSize)lo; |
631 | } | 658 | } |
632 | 659 | ||
633 | /* | 660 | /* Compute table length. Fast path. */ |
634 | ** Try to find a boundary in table `t'. A `boundary' is an integer index | ||
635 | ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). | ||
636 | */ | ||
637 | MSize LJ_FASTCALL lj_tab_len(GCtab *t) | 661 | MSize LJ_FASTCALL lj_tab_len(GCtab *t) |
638 | { | 662 | { |
639 | MSize j = (MSize)t->asize; | 663 | size_t hi = (size_t)t->asize; |
640 | if (j > 1 && tvisnil(arrayslot(t, j-1))) { | 664 | if (hi) hi--; |
641 | MSize i = 1; | 665 | /* In a growing array the last array element is very likely nil. */ |
642 | while (j - i > 1) { | 666 | if (hi > 0 && LJ_LIKELY(tvisnil(arrayslot(t, hi)))) { |
643 | MSize m = (i+j)/2; | 667 | /* Binary search to find a non-nil to nil transition in the array. */ |
644 | if (tvisnil(arrayslot(t, m-1))) j = m; else i = m; | 668 | size_t lo = 0; |
669 | while (hi - lo > 1) { | ||
670 | size_t mid = (lo+hi) >> 1; | ||
671 | if (tvisnil(arrayslot(t, mid))) hi = mid; else lo = mid; | ||
645 | } | 672 | } |
646 | return i-1; | 673 | return (MSize)lo; |
647 | } | 674 | } |
648 | if (j) j--; | 675 | /* Without a hash part, there's an implicit nil after the last element. */ |
649 | if (t->hmask <= 0) | 676 | return t->hmask ? tab_len_slow(t, hi) : (MSize)hi; |
650 | return j; | ||
651 | return unbound_search(t, j); | ||
652 | } | 677 | } |
653 | 678 | ||
679 | #if LJ_HASJIT | ||
680 | /* Verify hinted table length or compute it. */ | ||
681 | MSize LJ_FASTCALL lj_tab_len_hint(GCtab *t, size_t hint) | ||
682 | { | ||
683 | size_t asize = (size_t)t->asize; | ||
684 | cTValue *tv = arrayslot(t, hint); | ||
685 | if (LJ_LIKELY(hint+1 < asize)) { | ||
686 | if (LJ_LIKELY(!tvisnil(tv) && tvisnil(tv+1))) return (MSize)hint; | ||
687 | } else if (hint+1 <= asize && LJ_LIKELY(t->hmask == 0) && !tvisnil(tv)) { | ||
688 | return (MSize)hint; | ||
689 | } | ||
690 | return lj_tab_len(t); | ||
691 | } | ||
692 | #endif | ||
693 | |||