diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-10-30 14:25:59 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-10-30 14:25:59 -0300 |
| commit | 43c8e5bded052801f54a7439d18933b83570eb82 (patch) | |
| tree | 97f6d1e020110e14c798537c7bbb1f90feed4044 | |
| parent | b8b709b6d40c5c18d9b8ef33bb50afc55f048ab8 (diff) | |
| download | lua-43c8e5bded052801f54a7439d18933b83570eb82.tar.gz lua-43c8e5bded052801f54a7439d18933b83570eb82.tar.bz2 lua-43c8e5bded052801f54a7439d18933b83570eb82.zip | |
Full abstraction for representation of array values
| -rw-r--r-- | lapi.c | 31 | ||||
| -rw-r--r-- | lgc.c | 25 | ||||
| -rw-r--r-- | lobject.h | 5 | ||||
| -rw-r--r-- | lstate.c | 7 | ||||
| -rw-r--r-- | ltable.c | 116 | ||||
| -rw-r--r-- | ltable.h | 21 | ||||
| -rw-r--r-- | ltests.c | 10 | ||||
| -rw-r--r-- | lvm.c | 2 | ||||
| -rw-r--r-- | lvm.h | 4 |
9 files changed, 128 insertions, 93 deletions
| @@ -653,21 +653,17 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { | |||
| 653 | } | 653 | } |
| 654 | 654 | ||
| 655 | 655 | ||
| 656 | /* | 656 | static void getGlobalTable (lua_State *L, TValue *gt) { |
| 657 | ** Get the global table in the registry. Since all predefined | 657 | Table *registry = hvalue(&G(L)->l_registry); |
| 658 | ** indices in the registry were inserted right when the registry | 658 | luaH_getint(registry, LUA_RIDX_GLOBALS, gt); |
| 659 | ** was created and never removed, they must always be in the array | 659 | } |
| 660 | ** part of the registry. | ||
| 661 | */ | ||
| 662 | #define getGtable(L) \ | ||
| 663 | (&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1]) | ||
| 664 | 660 | ||
| 665 | 661 | ||
| 666 | LUA_API int lua_getglobal (lua_State *L, const char *name) { | 662 | LUA_API int lua_getglobal (lua_State *L, const char *name) { |
| 667 | const TValue *G; | 663 | TValue gt; |
| 668 | lua_lock(L); | 664 | lua_lock(L); |
| 669 | G = getGtable(L); | 665 | getGlobalTable(L, >); |
| 670 | return auxgetstr(L, G, name); | 666 | return auxgetstr(L, >, name); |
| 671 | } | 667 | } |
| 672 | 668 | ||
| 673 | 669 | ||
| @@ -840,10 +836,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) { | |||
| 840 | 836 | ||
| 841 | 837 | ||
| 842 | LUA_API void lua_setglobal (lua_State *L, const char *name) { | 838 | LUA_API void lua_setglobal (lua_State *L, const char *name) { |
| 843 | const TValue *G; | 839 | TValue gt; |
| 844 | lua_lock(L); /* unlock done in 'auxsetstr' */ | 840 | lua_lock(L); /* unlock done in 'auxsetstr' */ |
| 845 | G = getGtable(L); | 841 | getGlobalTable(L, >); |
| 846 | auxsetstr(L, G, name); | 842 | auxsetstr(L, >, name); |
| 847 | } | 843 | } |
| 848 | 844 | ||
| 849 | 845 | ||
| @@ -1093,10 +1089,11 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, | |||
| 1093 | LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */ | 1089 | LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */ |
| 1094 | if (f->nupvalues >= 1) { /* does it have an upvalue? */ | 1090 | if (f->nupvalues >= 1) { /* does it have an upvalue? */ |
| 1095 | /* get global table from registry */ | 1091 | /* get global table from registry */ |
| 1096 | const TValue *gt = getGtable(L); | 1092 | TValue gt; |
| 1093 | getGlobalTable(L, >); | ||
| 1097 | /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ | 1094 | /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ |
| 1098 | setobj(L, f->upvals[0]->v.p, gt); | 1095 | setobj(L, f->upvals[0]->v.p, >); |
| 1099 | luaC_barrier(L, f->upvals[0], gt); | 1096 | luaC_barrier(L, f->upvals[0], >); |
| 1100 | } | 1097 | } |
| 1101 | } | 1098 | } |
| 1102 | lua_unlock(L); | 1099 | lua_unlock(L); |
| @@ -91,6 +91,13 @@ | |||
| 91 | #define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) | 91 | #define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) |
| 92 | 92 | ||
| 93 | 93 | ||
| 94 | /* | ||
| 95 | ** Access to collectable objects in array part of tables | ||
| 96 | */ | ||
| 97 | #define gcvalarr(t,i) \ | ||
| 98 | ((*getArrTag(t,i) & BIT_ISCOLLECTABLE) ? getArrVal(t,i)->gc : NULL) | ||
| 99 | |||
| 100 | |||
| 94 | #define markvalue(g,o) { checkliveness(g->mainthread,o); \ | 101 | #define markvalue(g,o) { checkliveness(g->mainthread,o); \ |
| 95 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } | 102 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } |
| 96 | 103 | ||
| @@ -486,9 +493,10 @@ static int traverseephemeron (global_State *g, Table *h, int inv) { | |||
| 486 | unsigned int nsize = sizenode(h); | 493 | unsigned int nsize = sizenode(h); |
| 487 | /* traverse array part */ | 494 | /* traverse array part */ |
| 488 | for (i = 0; i < asize; i++) { | 495 | for (i = 0; i < asize; i++) { |
| 489 | if (valiswhite(&h->array[i])) { | 496 | GCObject *o = gcvalarr(h, i + 1); |
| 497 | if (o != NULL && iswhite(o)) { | ||
| 490 | marked = 1; | 498 | marked = 1; |
| 491 | reallymarkobject(g, gcvalue(&h->array[i])); | 499 | reallymarkobject(g, o); |
| 492 | } | 500 | } |
| 493 | } | 501 | } |
| 494 | /* traverse hash part; if 'inv', traverse descending | 502 | /* traverse hash part; if 'inv', traverse descending |
| @@ -524,8 +532,11 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
| 524 | Node *n, *limit = gnodelast(h); | 532 | Node *n, *limit = gnodelast(h); |
| 525 | unsigned int i; | 533 | unsigned int i; |
| 526 | unsigned int asize = luaH_realasize(h); | 534 | unsigned int asize = luaH_realasize(h); |
| 527 | for (i = 0; i < asize; i++) /* traverse array part */ | 535 | for (i = 0; i < asize; i++) { /* traverse array part */ |
| 528 | markvalue(g, &h->array[i]); | 536 | GCObject *o = gcvalarr(h, i + 1); |
| 537 | if (o != NULL && iswhite(o)) | ||
| 538 | reallymarkobject(g, o); | ||
| 539 | } | ||
| 529 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ | 540 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
| 530 | if (isempty(gval(n))) /* entry is empty? */ | 541 | if (isempty(gval(n))) /* entry is empty? */ |
| 531 | clearkey(n); /* clear its key */ | 542 | clearkey(n); /* clear its key */ |
| @@ -746,9 +757,9 @@ static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | |||
| 746 | unsigned int i; | 757 | unsigned int i; |
| 747 | unsigned int asize = luaH_realasize(h); | 758 | unsigned int asize = luaH_realasize(h); |
| 748 | for (i = 0; i < asize; i++) { | 759 | for (i = 0; i < asize; i++) { |
| 749 | TValue *o = &h->array[i]; | 760 | GCObject *o = gcvalarr(h, i + 1); |
| 750 | if (iscleared(g, gcvalueN(o))) /* value was collected? */ | 761 | if (iscleared(g, o)) /* value was collected? */ |
| 751 | setempty(o); /* remove entry */ | 762 | *getArrTag(h, i + 1) = LUA_VEMPTY; /* remove entry */ |
| 752 | } | 763 | } |
| 753 | for (n = gnode(h, 0); n < limit; n++) { | 764 | for (n = gnode(h, 0); n < limit; n++) { |
| 754 | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ | 765 | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ |
| @@ -736,12 +736,15 @@ typedef union Node { | |||
| 736 | #define setnorealasize(t) ((t)->flags |= BITRAS) | 736 | #define setnorealasize(t) ((t)->flags |= BITRAS) |
| 737 | 737 | ||
| 738 | 738 | ||
| 739 | typedef struct ArrayCell ArrayCell; | ||
| 740 | |||
| 741 | |||
| 739 | typedef struct Table { | 742 | typedef struct Table { |
| 740 | CommonHeader; | 743 | CommonHeader; |
| 741 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ | 744 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ |
| 742 | lu_byte lsizenode; /* log2 of size of 'node' array */ | 745 | lu_byte lsizenode; /* log2 of size of 'node' array */ |
| 743 | unsigned int alimit; /* "limit" of 'array' array */ | 746 | unsigned int alimit; /* "limit" of 'array' array */ |
| 744 | TValue *array; /* array part */ | 747 | ArrayCell *array; /* array part */ |
| 745 | Node *node; | 748 | Node *node; |
| 746 | Node *lastfree; /* any free position is before this position */ | 749 | Node *lastfree; /* any free position is before this position */ |
| 747 | struct Table *metatable; | 750 | struct Table *metatable; |
| @@ -215,13 +215,16 @@ static void freestack (lua_State *L) { | |||
| 215 | */ | 215 | */ |
| 216 | static void init_registry (lua_State *L, global_State *g) { | 216 | static void init_registry (lua_State *L, global_State *g) { |
| 217 | /* create registry */ | 217 | /* create registry */ |
| 218 | TValue aux; | ||
| 218 | Table *registry = luaH_new(L); | 219 | Table *registry = luaH_new(L); |
| 219 | sethvalue(L, &g->l_registry, registry); | 220 | sethvalue(L, &g->l_registry, registry); |
| 220 | luaH_resize(L, registry, LUA_RIDX_LAST, 0); | 221 | luaH_resize(L, registry, LUA_RIDX_LAST, 0); |
| 221 | /* registry[LUA_RIDX_MAINTHREAD] = L */ | 222 | /* registry[LUA_RIDX_MAINTHREAD] = L */ |
| 222 | setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L); | 223 | setthvalue(L, &aux, L); |
| 224 | luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &aux); | ||
| 223 | /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ | 225 | /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ |
| 224 | sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L)); | 226 | sethvalue(L, &aux, luaH_new(L)); |
| 227 | luaH_setint(L, registry, LUA_RIDX_GLOBALS, &aux); | ||
| 225 | } | 228 | } |
| 226 | 229 | ||
| 227 | 230 | ||
| @@ -350,9 +350,10 @@ int luaH_next (lua_State *L, Table *t, StkId key) { | |||
| 350 | unsigned int asize = luaH_realasize(t); | 350 | unsigned int asize = luaH_realasize(t); |
| 351 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ | 351 | unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ |
| 352 | for (; i < asize; i++) { /* try first array part */ | 352 | for (; i < asize; i++) { /* try first array part */ |
| 353 | if (!isempty(&t->array[i])) { /* a non-empty entry? */ | 353 | int tag = *getArrTag(t, i + 1); |
| 354 | if (!tagisempty(tag)) { /* a non-empty entry? */ | ||
| 354 | setivalue(s2v(key), i + 1); | 355 | setivalue(s2v(key), i + 1); |
| 355 | setobj2s(L, key + 1, &t->array[i]); | 356 | farr2val(t, i + 1, tag, s2v(key + 1)); |
| 356 | return 1; | 357 | return 1; |
| 357 | } | 358 | } |
| 358 | } | 359 | } |
| @@ -375,6 +376,41 @@ static void freehash (lua_State *L, Table *t) { | |||
| 375 | 376 | ||
| 376 | 377 | ||
| 377 | /* | 378 | /* |
| 379 | ** Check whether an integer key is in the array part. If 'alimit' is | ||
| 380 | ** not the real size of the array, the key still can be in the array | ||
| 381 | ** part. In this case, do the "Xmilia trick" to check whether 'key-1' | ||
| 382 | ** is smaller than the real size. | ||
| 383 | ** The trick works as follow: let 'p' be an integer such that | ||
| 384 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | ||
| 385 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | ||
| 386 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | ||
| 387 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | ||
| 388 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
| 389 | ** 'key-1 >= 2^(p+1)', then 'res' will have some 1-bit higher than 'p', | ||
| 390 | ** therefore it will be larger or equal to 'alimit', and the check | ||
| 391 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no 1-bit higher than | ||
| 392 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
| 393 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
| 394 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
| 395 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
| 396 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
| 397 | ** if cannot be smaller than alimit. | ||
| 398 | */ | ||
| 399 | static int keyinarray (Table *t, lua_Integer key) { | ||
| 400 | lua_Unsigned alimit = t->alimit; | ||
| 401 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
| 402 | return 1; | ||
| 403 | else if (!isrealasize(t) && /* key still may be in the array part? */ | ||
| 404 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { | ||
| 405 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
| 406 | return 1; | ||
| 407 | } | ||
| 408 | else | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | |||
| 413 | /* | ||
| 378 | ** {============================================================= | 414 | ** {============================================================= |
| 379 | ** Rehash | 415 | ** Rehash |
| 380 | ** ============================================================== | 416 | ** ============================================================== |
| @@ -421,6 +457,12 @@ static int countint (lua_Integer key, unsigned int *nums) { | |||
| 421 | } | 457 | } |
| 422 | 458 | ||
| 423 | 459 | ||
| 460 | l_sinline int arraykeyisempty (const Table *t, lua_Integer key) { | ||
| 461 | int tag = *getArrTag(t, key); | ||
| 462 | return tagisempty(tag); | ||
| 463 | } | ||
| 464 | |||
| 465 | |||
| 424 | /* | 466 | /* |
| 425 | ** Count keys in array part of table 't': Fill 'nums[i]' with | 467 | ** Count keys in array part of table 't': Fill 'nums[i]' with |
| 426 | ** number of keys that will go into corresponding slice and return | 468 | ** number of keys that will go into corresponding slice and return |
| @@ -443,7 +485,7 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) { | |||
| 443 | } | 485 | } |
| 444 | /* count elements in range (2^(lg - 1), 2^lg] */ | 486 | /* count elements in range (2^(lg - 1), 2^lg] */ |
| 445 | for (; i <= lim; i++) { | 487 | for (; i <= lim; i++) { |
| 446 | if (!isempty(&t->array[i-1])) | 488 | if (!arraykeyisempty(t, i)) |
| 447 | lc++; | 489 | lc++; |
| 448 | } | 490 | } |
| 449 | nums[lg] += lc; | 491 | nums[lg] += lc; |
| @@ -555,7 +597,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
| 555 | unsigned int i; | 597 | unsigned int i; |
| 556 | Table newt; /* to keep the new hash part */ | 598 | Table newt; /* to keep the new hash part */ |
| 557 | unsigned int oldasize = setlimittosize(t); | 599 | unsigned int oldasize = setlimittosize(t); |
| 558 | TValue *newarray; | 600 | ArrayCell *newarray; |
| 559 | /* create new hash part with appropriate size into 'newt' */ | 601 | /* create new hash part with appropriate size into 'newt' */ |
| 560 | setnodevector(L, &newt, nhsize); | 602 | setnodevector(L, &newt, nhsize); |
| 561 | if (newasize < oldasize) { /* will array shrink? */ | 603 | if (newasize < oldasize) { /* will array shrink? */ |
| @@ -563,14 +605,18 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
| 563 | exchangehashpart(t, &newt); /* and new hash */ | 605 | exchangehashpart(t, &newt); /* and new hash */ |
| 564 | /* re-insert into the new hash the elements from vanishing slice */ | 606 | /* re-insert into the new hash the elements from vanishing slice */ |
| 565 | for (i = newasize; i < oldasize; i++) { | 607 | for (i = newasize; i < oldasize; i++) { |
| 566 | if (!isempty(&t->array[i])) | 608 | int tag = *getArrTag(t, i + 1); |
| 567 | luaH_setint(L, t, i + 1, &t->array[i]); | 609 | if (!tagisempty(tag)) { /* a non-empty entry? */ |
| 610 | TValue aux; | ||
| 611 | farr2val(t, i + 1, tag, &aux); | ||
| 612 | luaH_setint(L, t, i + 1, &aux); | ||
| 613 | } | ||
| 568 | } | 614 | } |
| 569 | t->alimit = oldasize; /* restore current size... */ | 615 | t->alimit = oldasize; /* restore current size... */ |
| 570 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ | 616 | exchangehashpart(t, &newt); /* and hash (in case of errors) */ |
| 571 | } | 617 | } |
| 572 | /* allocate new array */ | 618 | /* allocate new array */ |
| 573 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); | 619 | newarray = luaM_reallocvector(L, t->array, oldasize, newasize, ArrayCell); |
| 574 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ | 620 | if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ |
| 575 | freehash(L, &newt); /* release new hash part */ | 621 | freehash(L, &newt); /* release new hash part */ |
| 576 | luaM_error(L); /* raise error (with array unchanged) */ | 622 | luaM_error(L); /* raise error (with array unchanged) */ |
| @@ -580,7 +626,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | |||
| 580 | t->array = newarray; /* set new array part */ | 626 | t->array = newarray; /* set new array part */ |
| 581 | t->alimit = newasize; | 627 | t->alimit = newasize; |
| 582 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ | 628 | for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ |
| 583 | setempty(&t->array[i]); | 629 | *getArrTag(t, i + 1) = LUA_VEMPTY; |
| 584 | /* re-insert elements from old hash part into new parts */ | 630 | /* re-insert elements from old hash part into new parts */ |
| 585 | reinsert(L, &newt, t); /* 'newt' now has the old hash */ | 631 | reinsert(L, &newt, t); /* 'newt' now has the old hash */ |
| 586 | freehash(L, &newt); /* free old hash part */ | 632 | freehash(L, &newt); /* free old hash part */ |
| @@ -719,41 +765,6 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { | |||
| 719 | } | 765 | } |
| 720 | 766 | ||
| 721 | 767 | ||
| 722 | /* | ||
| 723 | ** Check whether key is in the array part. If 'alimit' is not the real | ||
| 724 | ** size of the array, the key still can be in the array part. In this | ||
| 725 | ** case, do the "Xmilia trick" to check whether 'key-1' is smaller than | ||
| 726 | ** the real size. | ||
| 727 | ** The trick works as follow: let 'p' be an integer such that | ||
| 728 | ** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. | ||
| 729 | ** That is, 2^(p+1) is the real size of the array, and 'p' is the highest | ||
| 730 | ** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. | ||
| 731 | ** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will | ||
| 732 | ** have the 'p' bit cleared. If the key is outside the array, that is, | ||
| 733 | ** 'key-1 >= 2^(p+1)', then 'res' will have some 1-bit higher than 'p', | ||
| 734 | ** therefore it will be larger or equal to 'alimit', and the check | ||
| 735 | ** will fail. If 'key-1 < 2^(p+1)', then 'res' has no 1-bit higher than | ||
| 736 | ** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller | ||
| 737 | ** than 2^p, therefore smaller than 'alimit', and the check succeeds. | ||
| 738 | ** As special cases, when 'alimit' is 0 the condition is trivially false, | ||
| 739 | ** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. | ||
| 740 | ** If key is 0 or negative, 'res' will have its higher bit on, so that | ||
| 741 | ** if cannot be smaller than alimit. | ||
| 742 | */ | ||
| 743 | static int keyinarray (Table *t, lua_Integer key) { | ||
| 744 | lua_Unsigned alimit = t->alimit; | ||
| 745 | if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ | ||
| 746 | return 1; | ||
| 747 | else if (!isrealasize(t) && /* key still may be in the array part? */ | ||
| 748 | (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { | ||
| 749 | t->alimit = cast_uint(key); /* probably '#t' is here now */ | ||
| 750 | return 1; | ||
| 751 | } | ||
| 752 | else | ||
| 753 | return 0; | ||
| 754 | } | ||
| 755 | |||
| 756 | |||
| 757 | static const TValue *getintfromhash (Table *t, lua_Integer key) { | 768 | static const TValue *getintfromhash (Table *t, lua_Integer key) { |
| 758 | Node *n = hashint(t, key); | 769 | Node *n = hashint(t, key); |
| 759 | lua_assert(l_castS2U(key) - 1u >= luaH_realasize(t)); | 770 | lua_assert(l_castS2U(key) - 1u >= luaH_realasize(t)); |
| @@ -770,15 +781,8 @@ static const TValue *getintfromhash (Table *t, lua_Integer key) { | |||
| 770 | } | 781 | } |
| 771 | 782 | ||
| 772 | 783 | ||
| 773 | l_sinline int arraykeyisempty (Table *t, lua_Integer key) { | ||
| 774 | int tag = *getArrTag(t, key); | ||
| 775 | return tagisempty(tag); | ||
| 776 | } | ||
| 777 | |||
| 778 | |||
| 779 | static int hashkeyisempty (Table *t, lua_Integer key) { | 784 | static int hashkeyisempty (Table *t, lua_Integer key) { |
| 780 | const TValue *val = getintfromhash(t, key); | 785 | const TValue *val = getintfromhash(t, key); |
| 781 | lua_assert(!keyinarray(t, key)); | ||
| 782 | return isempty(val); | 786 | return isempty(val); |
| 783 | } | 787 | } |
| 784 | 788 | ||
| @@ -797,7 +801,7 @@ int luaH_getint (Table *t, lua_Integer key, TValue *res) { | |||
| 797 | if (keyinarray(t, key)) { | 801 | if (keyinarray(t, key)) { |
| 798 | int tag = *getArrTag(t, key); | 802 | int tag = *getArrTag(t, key); |
| 799 | if (!tagisempty(tag)) { | 803 | if (!tagisempty(tag)) { |
| 800 | arr2val(t, key, tag, res); | 804 | farr2val(t, key, tag, res); |
| 801 | return HOK; /* success */ | 805 | return HOK; /* success */ |
| 802 | } | 806 | } |
| 803 | else | 807 | else |
| @@ -900,7 +904,7 @@ int luaH_psetint (Table *t, lua_Integer key, TValue *val) { | |||
| 900 | if (keyinarray(t, key)) { | 904 | if (keyinarray(t, key)) { |
| 901 | lu_byte *tag = getArrTag(t, key); | 905 | lu_byte *tag = getArrTag(t, key); |
| 902 | if (!tagisempty(*tag)) { | 906 | if (!tagisempty(*tag)) { |
| 903 | val2arr(t, key, tag, val); | 907 | fval2arr(t, key, tag, val); |
| 904 | return HOK; /* success */ | 908 | return HOK; /* success */ |
| 905 | } | 909 | } |
| 906 | else | 910 | else |
| @@ -956,7 +960,7 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key, | |||
| 956 | } | 960 | } |
| 957 | else { /* array entry */ | 961 | else { /* array entry */ |
| 958 | hres = ~hres; /* real index */ | 962 | hres = ~hres; /* real index */ |
| 959 | val2arr(t, hres, getArrTag(t, hres), value); | 963 | fval2arr(t, hres, getArrTag(t, hres), value); |
| 960 | } | 964 | } |
| 961 | } | 965 | } |
| 962 | 966 | ||
| @@ -1087,11 +1091,11 @@ lua_Unsigned luaH_getn (Table *t) { | |||
| 1087 | /* 'limit' is zero or present in table */ | 1091 | /* 'limit' is zero or present in table */ |
| 1088 | if (!limitequalsasize(t)) { /* (2)? */ | 1092 | if (!limitequalsasize(t)) { /* (2)? */ |
| 1089 | /* 'limit' > 0 and array has more elements after 'limit' */ | 1093 | /* 'limit' > 0 and array has more elements after 'limit' */ |
| 1090 | if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */ | 1094 | if (arraykeyisempty(t, limit + 1)) /* 'limit + 1' is empty? */ |
| 1091 | return limit; /* this is the boundary */ | 1095 | return limit; /* this is the boundary */ |
| 1092 | /* else, try last element in the array */ | 1096 | /* else, try last element in the array */ |
| 1093 | limit = luaH_realasize(t); | 1097 | limit = luaH_realasize(t); |
| 1094 | if (isempty(&t->array[limit - 1])) { /* empty? */ | 1098 | if (arraykeyisempty(t, limit)) { /* empty? */ |
| 1095 | /* there must be a boundary in the array after old limit, | 1099 | /* there must be a boundary in the array after old limit, |
| 1096 | and it must be a valid new limit */ | 1100 | and it must be a valid new limit */ |
| 1097 | unsigned int boundary = binsearch(t, t->alimit, limit); | 1101 | unsigned int boundary = binsearch(t, t->alimit, limit); |
| @@ -1102,7 +1106,7 @@ lua_Unsigned luaH_getn (Table *t) { | |||
| 1102 | } | 1106 | } |
| 1103 | /* (3) 'limit' is the last element and either is zero or present in table */ | 1107 | /* (3) 'limit' is the last element and either is zero or present in table */ |
| 1104 | lua_assert(limit == luaH_realasize(t) && | 1108 | lua_assert(limit == luaH_realasize(t) && |
| 1105 | (limit == 0 || !isempty(&t->array[limit - 1]))); | 1109 | (limit == 0 || !arraykeyisempty(t, limit))); |
| 1106 | if (isdummy(t) || hashkeyisempty(t, cast(lua_Integer, limit + 1))) | 1110 | if (isdummy(t) || hashkeyisempty(t, cast(lua_Integer, limit + 1))) |
| 1107 | return limit; /* 'limit + 1' is absent */ | 1111 | return limit; /* 'limit + 1' is absent */ |
| 1108 | else /* 'limit + 1' is also present */ | 1112 | else /* 'limit + 1' is also present */ |
| @@ -51,20 +51,33 @@ | |||
| 51 | */ | 51 | */ |
| 52 | 52 | ||
| 53 | 53 | ||
| 54 | struct ArrayCell { | ||
| 55 | lu_byte tt; | ||
| 56 | Value value; | ||
| 57 | }; | ||
| 58 | |||
| 54 | 59 | ||
| 55 | /* fast access to components of array values */ | 60 | /* fast access to components of array values */ |
| 56 | #define getArrTag(t,k) (&(t)->array[k - 1].tt_) | 61 | #define getArrTag(t,k) (&(t)->array[k - 1].tt) |
| 57 | #define getArrVal(t,k) (&(t)->array[k - 1].value_) | 62 | #define getArrVal(t,k) (&(t)->array[k - 1].value) |
| 58 | 63 | ||
| 59 | #define tagisempty(tag) (novariant(tag) == LUA_TNIL) | 64 | #define tagisempty(tag) (novariant(tag) == LUA_TNIL) |
| 60 | 65 | ||
| 61 | #define arr2val(h,k,tag,res) \ | 66 | |
| 67 | #define farr2val(h,k,tag,res) \ | ||
| 62 | ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,k)) | 68 | ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,k)) |
| 63 | 69 | ||
| 64 | #define val2arr(h,k,tag,val) \ | 70 | #define fval2arr(h,k,tag,val) \ |
| 65 | (*tag = (val)->tt_, *getArrVal(h,k) = (val)->value_) | 71 | (*tag = (val)->tt_, *getArrVal(h,k) = (val)->value_) |
| 66 | 72 | ||
| 67 | 73 | ||
| 74 | #define obj2arr(h,k,val) \ | ||
| 75 | (*getArrTag(h,k) = (val)->tt_, *getArrVal(h,k) = (val)->value_) | ||
| 76 | |||
| 77 | #define arr2obj(h,k,val) \ | ||
| 78 | ((val)->tt_ = *getArrTag(h,k), (val)->value_ = *getArrVal(h,k)) | ||
| 79 | |||
| 80 | |||
| 68 | LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res); | 81 | LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res); |
| 69 | LUAI_FUNC int luaH_getstr (Table *t, TString *key, TValue *res); | 82 | LUAI_FUNC int luaH_getstr (Table *t, TString *key, TValue *res); |
| 70 | LUAI_FUNC int luaH_get (Table *t, const TValue *key, TValue *res); | 83 | LUAI_FUNC int luaH_get (Table *t, const TValue *key, TValue *res); |
| @@ -362,8 +362,11 @@ static void checktable (global_State *g, Table *h) { | |||
| 362 | Node *n, *limit = gnode(h, sizenode(h)); | 362 | Node *n, *limit = gnode(h, sizenode(h)); |
| 363 | GCObject *hgc = obj2gco(h); | 363 | GCObject *hgc = obj2gco(h); |
| 364 | checkobjrefN(g, hgc, h->metatable); | 364 | checkobjrefN(g, hgc, h->metatable); |
| 365 | for (i = 0; i < asize; i++) | 365 | for (i = 0; i < asize; i++) { |
| 366 | checkvalref(g, hgc, &h->array[i]); | 366 | TValue aux; |
| 367 | arr2obj(h, i + 1, &aux); | ||
| 368 | checkvalref(g, hgc, &aux); | ||
| 369 | } | ||
| 367 | for (n = gnode(h, 0); n < limit; n++) { | 370 | for (n = gnode(h, 0); n < limit; n++) { |
| 368 | if (!isempty(gval(n))) { | 371 | if (!isempty(gval(n))) { |
| 369 | TValue k; | 372 | TValue k; |
| @@ -1005,7 +1008,8 @@ static int table_query (lua_State *L) { | |||
| 1005 | } | 1008 | } |
| 1006 | else if ((unsigned int)i < asize) { | 1009 | else if ((unsigned int)i < asize) { |
| 1007 | lua_pushinteger(L, i); | 1010 | lua_pushinteger(L, i); |
| 1008 | pushobject(L, &t->array[i]); | 1011 | arr2obj(t, i + 1, s2v(L->top.p)); |
| 1012 | api_incr_top(L); | ||
| 1009 | lua_pushnil(L); | 1013 | lua_pushnil(L); |
| 1010 | } | 1014 | } |
| 1011 | else if ((i -= asize) < sizenode(t)) { | 1015 | else if ((i -= asize) < sizenode(t)) { |
| @@ -1845,7 +1845,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1845 | luaH_resizearray(L, h, last); /* preallocate it at once */ | 1845 | luaH_resizearray(L, h, last); /* preallocate it at once */ |
| 1846 | for (; n > 0; n--) { | 1846 | for (; n > 0; n--) { |
| 1847 | TValue *val = s2v(ra + n); | 1847 | TValue *val = s2v(ra + n); |
| 1848 | setobj2t(L, &h->array[last - 1], val); | 1848 | obj2arr(h, last, val); |
| 1849 | last--; | 1849 | last--; |
| 1850 | luaC_barrierback(L, obj2gco(h), val); | 1850 | luaC_barrierback(L, obj2gco(h), val); |
| 1851 | } | 1851 | } |
| @@ -92,7 +92,7 @@ typedef enum { | |||
| 92 | if ((u - 1u < h->alimit)) { \ | 92 | if ((u - 1u < h->alimit)) { \ |
| 93 | int tag = *getArrTag(h,u); \ | 93 | int tag = *getArrTag(h,u); \ |
| 94 | if (tagisempty(tag)) aux = HNOTFOUND; \ | 94 | if (tagisempty(tag)) aux = HNOTFOUND; \ |
| 95 | else { arr2val(h, u, tag, res); aux = HOK; }} \ | 95 | else { farr2val(h, u, tag, res); aux = HOK; }} \ |
| 96 | else { aux = luaH_getint(h, u, res); }} | 96 | else { aux = luaH_getint(h, u, res); }} |
| 97 | 97 | ||
| 98 | 98 | ||
| @@ -105,7 +105,7 @@ typedef enum { | |||
| 105 | if ((u - 1u < h->alimit)) { \ | 105 | if ((u - 1u < h->alimit)) { \ |
| 106 | lu_byte *tag = getArrTag(h,u); \ | 106 | lu_byte *tag = getArrTag(h,u); \ |
| 107 | if (tagisempty(*tag)) aux = ~cast_int(u); \ | 107 | if (tagisempty(*tag)) aux = ~cast_int(u); \ |
| 108 | else { val2arr(h, u, tag, val); aux = HOK; }} \ | 108 | else { fval2arr(h, u, tag, val); aux = HOK; }} \ |
| 109 | else { aux = luaH_psetint(h, u, val); }} | 109 | else { aux = luaH_psetint(h, u, val); }} |
| 110 | 110 | ||
| 111 | 111 | ||
