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 | ||