diff options
author | Mike Pall <mike> | 2020-05-27 19:20:44 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2020-05-27 19:20:44 +0200 |
commit | 1a4ff1311740aa6c85f7a9101b6aa9bfaafa3f8e (patch) | |
tree | c0bb622eb6a70b71c58d83d4cceed4e4b3279300 /src/lj_tab.c | |
parent | b2307c8ad817e350d65cc909a579ca2f77439682 (diff) | |
download | luajit-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.c | 79 |
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 | ||
642 | static MSize unbound_search(GCtab *t, MSize j) | 642 | /* Compute table length. Slow path with mixed array/hash lookups. */ |
643 | LJ_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 | */ | ||
671 | MSize LJ_FASTCALL lj_tab_len(GCtab *t) | 668 | MSize 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. */ | ||
688 | MSize 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 | ||