aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-10-30 14:25:59 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-10-30 14:25:59 -0300
commit43c8e5bded052801f54a7439d18933b83570eb82 (patch)
tree97f6d1e020110e14c798537c7bbb1f90feed4044
parentb8b709b6d40c5c18d9b8ef33bb50afc55f048ab8 (diff)
downloadlua-43c8e5bded052801f54a7439d18933b83570eb82.tar.gz
lua-43c8e5bded052801f54a7439d18933b83570eb82.tar.bz2
lua-43c8e5bded052801f54a7439d18933b83570eb82.zip
Full abstraction for representation of array values
-rw-r--r--lapi.c31
-rw-r--r--lgc.c25
-rw-r--r--lobject.h5
-rw-r--r--lstate.c7
-rw-r--r--ltable.c116
-rw-r--r--ltable.h21
-rw-r--r--ltests.c10
-rw-r--r--lvm.c2
-rw-r--r--lvm.h4
9 files changed, 128 insertions, 93 deletions
diff --git a/lapi.c b/lapi.c
index 4a3ba724..99c8473e 100644
--- a/lapi.c
+++ b/lapi.c
@@ -653,21 +653,17 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
653} 653}
654 654
655 655
656/* 656static 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
666LUA_API int lua_getglobal (lua_State *L, const char *name) { 662LUA_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, &gt);
670 return auxgetstr(L, G, name); 666 return auxgetstr(L, &gt, 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
842LUA_API void lua_setglobal (lua_State *L, const char *name) { 838LUA_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, &gt);
846 auxsetstr(L, G, name); 842 auxsetstr(L, &gt, 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, &gt);
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, &gt);
1099 luaC_barrier(L, f->upvals[0], gt); 1096 luaC_barrier(L, f->upvals[0], &gt);
1100 } 1097 }
1101 } 1098 }
1102 lua_unlock(L); 1099 lua_unlock(L);
diff --git a/lgc.c b/lgc.c
index a3094ff5..813b08d5 100644
--- a/lgc.c
+++ b/lgc.c
@@ -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? */
diff --git a/lobject.h b/lobject.h
index 556608e4..e91bb0f8 100644
--- a/lobject.h
+++ b/lobject.h
@@ -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
739typedef struct ArrayCell ArrayCell;
740
741
739typedef struct Table { 742typedef 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;
diff --git a/lstate.c b/lstate.c
index 1e925e5a..d10cd88c 100644
--- a/lstate.c
+++ b/lstate.c
@@ -215,13 +215,16 @@ static void freestack (lua_State *L) {
215*/ 215*/
216static void init_registry (lua_State *L, global_State *g) { 216static 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, &registry->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, &registry->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
diff --git a/ltable.c b/ltable.c
index d436cf6e..ddda9a44 100644
--- a/ltable.c
+++ b/ltable.c
@@ -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*/
399static 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
460l_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*/
743static 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
757static const TValue *getintfromhash (Table *t, lua_Integer key) { 768static 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
773l_sinline int arraykeyisempty (Table *t, lua_Integer key) {
774 int tag = *getArrTag(t, key);
775 return tagisempty(tag);
776}
777
778
779static int hashkeyisempty (Table *t, lua_Integer key) { 784static 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 */
diff --git a/ltable.h b/ltable.h
index 5ec7b447..371e721d 100644
--- a/ltable.h
+++ b/ltable.h
@@ -51,20 +51,33 @@
51*/ 51*/
52 52
53 53
54struct 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
68LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res); 81LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res);
69LUAI_FUNC int luaH_getstr (Table *t, TString *key, TValue *res); 82LUAI_FUNC int luaH_getstr (Table *t, TString *key, TValue *res);
70LUAI_FUNC int luaH_get (Table *t, const TValue *key, TValue *res); 83LUAI_FUNC int luaH_get (Table *t, const TValue *key, TValue *res);
diff --git a/ltests.c b/ltests.c
index 7d184c0d..e2bf76bd 100644
--- a/ltests.c
+++ b/ltests.c
@@ -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)) {
diff --git a/lvm.c b/lvm.c
index 96413718..927272df 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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 }
diff --git a/lvm.h b/lvm.h
index 8808c942..32455fba 100644
--- a/lvm.h
+++ b/lvm.h
@@ -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