aboutsummaryrefslogtreecommitdiff
path: root/src/lj_tab.c
diff options
context:
space:
mode:
authorMike Pall <mike>2020-05-27 19:20:44 +0200
committerMike Pall <mike>2020-05-27 19:20:44 +0200
commit1a4ff1311740aa6c85f7a9101b6aa9bfaafa3f8e (patch)
treec0bb622eb6a70b71c58d83d4cceed4e4b3279300 /src/lj_tab.c
parentb2307c8ad817e350d65cc909a579ca2f77439682 (diff)
downloadluajit-1a4ff1311740aa6c85f7a9101b6aa9bfaafa3f8e.tar.gz
luajit-1a4ff1311740aa6c85f7a9101b6aa9bfaafa3f8e.tar.bz2
luajit-1a4ff1311740aa6c85f7a9101b6aa9bfaafa3f8e.zip
Optimize table length computation with hinting.
10x faster on loop with t[#t+1] = x idiom. Also used by table.insert.
Diffstat (limited to 'src/lj_tab.c')
-rw-r--r--src/lj_tab.c79
1 files changed, 46 insertions, 33 deletions
diff --git a/src/lj_tab.c b/src/lj_tab.c
index dcd24d31..eb9ef4af 100644
--- a/src/lj_tab.c
+++ b/src/lj_tab.c
@@ -639,49 +639,62 @@ int lj_tab_next(lua_State *L, GCtab *t, TValue *key)
639 639
640/* -- Table length calculation -------------------------------------------- */ 640/* -- Table length calculation -------------------------------------------- */
641 641
642static MSize unbound_search(GCtab *t, MSize j) 642/* Compute table length. Slow path with mixed array/hash lookups. */
643LJ_NOINLINE static MSize tab_len_slow(GCtab *t, size_t hi)
643{ 644{
644 cTValue *tv; 645 cTValue *tv;
645 MSize i = j; /* i is zero or a present index */ 646 size_t lo = hi;
646 j++; 647 hi++;
647 /* find `i' and `j' such that i is present and j is not */ 648 /* Widening search for an upper bound. */
648 while ((tv = lj_tab_getint(t, (int32_t)j)) && !tvisnil(tv)) { 649 while ((tv = lj_tab_getint(t, (int32_t)hi)) && !tvisnil(tv)) {
649 i = j; 650 lo = hi;
650 j *= 2; 651 hi += hi;
651 if (j > (MSize)(INT_MAX-2)) { /* overflow? */ 652 if (hi > (size_t)(INT_MAX-2)) { /* Punt and do a linear search. */
652 /* table was built with bad purposes: resort to linear search */ 653 lo = 1;
653 i = 1; 654 while ((tv = lj_tab_getint(t, (int32_t)lo)) && !tvisnil(tv)) lo++;
654 while ((tv = lj_tab_getint(t, (int32_t)i)) && !tvisnil(tv)) i++; 655 return (MSize)(lo - 1);
655 return i - 1;
656 } 656 }
657 } 657 }
658 /* now do a binary search between them */ 658 /* Binary search to find a non-nil to nil transition. */
659 while (j - i > 1) { 659 while (hi - lo > 1) {
660 MSize m = (i+j)/2; 660 size_t mid = (lo+hi) >> 1;
661 cTValue *tvb = lj_tab_getint(t, (int32_t)m); 661 cTValue *tvb = lj_tab_getint(t, (int32_t)mid);
662 if (tvb && !tvisnil(tvb)) i = m; else j = m; 662 if (tvb && !tvisnil(tvb)) lo = mid; else hi = mid;
663 } 663 }
664 return i; 664 return (MSize)lo;
665} 665}
666 666
667/* 667/* Compute table length. Fast path. */
668** Try to find a boundary in table `t'. A `boundary' is an integer index
669** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
670*/
671MSize LJ_FASTCALL lj_tab_len(GCtab *t) 668MSize LJ_FASTCALL lj_tab_len(GCtab *t)
672{ 669{
673 MSize j = (MSize)t->asize; 670 size_t hi = (size_t)t->asize;
674 if (j > 1 && tvisnil(arrayslot(t, j-1))) { 671 if (hi) hi--;
675 MSize i = 1; 672 /* In a growing array the last array element is very likely nil. */
676 while (j - i > 1) { 673 if (hi > 0 && LJ_LIKELY(tvisnil(arrayslot(t, hi)))) {
677 MSize m = (i+j)/2; 674 /* Binary search to find a non-nil to nil transition in the array. */
678 if (tvisnil(arrayslot(t, m-1))) j = m; else i = m; 675 size_t lo = 0;
676 while (hi - lo > 1) {
677 size_t mid = (lo+hi) >> 1;
678 if (tvisnil(arrayslot(t, mid))) hi = mid; else lo = mid;
679 } 679 }
680 return i-1; 680 return (MSize)lo;
681 }
682 /* Without a hash part, there's an implicit nil after the last element. */
683 return t->hmask ? tab_len_slow(t, hi) : (MSize)hi;
684}
685
686#if LJ_HASJIT
687/* Verify hinted table length or compute it. */
688MSize LJ_FASTCALL lj_tab_len_hint(GCtab *t, size_t hint)
689{
690 size_t asize = (size_t)t->asize;
691 cTValue *tv = arrayslot(t, hint);
692 if (LJ_LIKELY(hint+1 < asize)) {
693 if (LJ_LIKELY(!tvisnil(tv) && tvisnil(tv+1))) return (MSize)hint;
694 } else if (hint+1 <= asize && LJ_LIKELY(t->hmask == 0) && !tvisnil(tv)) {
695 return (MSize)hint;
681 } 696 }
682 if (j) j--; 697 return lj_tab_len(t);
683 if (t->hmask <= 0)
684 return j;
685 return unbound_search(t, j);
686} 698}
699#endif
687 700