Skip to content

Commit c6f5ef6

Browse files
author
Mike Pall
committed
Refactor table traversal.
Sponsored by OpenResty Inc.
1 parent 4e0ea65 commit c6f5ef6

File tree

12 files changed

+153
-207
lines changed

12 files changed

+153
-207
lines changed

src/lib_base.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
7979
LJLIB_ASM(next)
8080
{
8181
lj_lib_checktab(L, 1);
82+
lj_err_msg(L, LJ_ERR_NEXTIDX);
8283
return FFH_UNREACHABLE;
8384
}
8485

src/lj_api.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -893,11 +893,13 @@ LUA_API int lua_next(lua_State *L, int idx)
893893
cTValue *t = index2adr(L, idx);
894894
int more;
895895
lj_checkapi(tvistab(t), "stack slot %d is not a table", idx);
896-
more = lj_tab_next(L, tabV(t), L->top-1);
897-
if (more) {
896+
more = lj_tab_next(tabV(t), L->top-1, L->top-1);
897+
if (more > 0) {
898898
incr_top(L); /* Return new key and value slot. */
899-
} else { /* End of traversal. */
899+
} else if (!more) { /* End of traversal. */
900900
L->top--; /* Remove key slot. */
901+
} else {
902+
lj_err_msg(L, LJ_ERR_NEXTIDX);
901903
}
902904
return more;
903905
}

src/lj_obj.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,9 @@ typedef const TValue cTValue;
284284
#define LJ_TISGCV (LJ_TSTR+1)
285285
#define LJ_TISTABUD LJ_TTAB
286286

287+
/* Type marker for slot holding a traversal index. Must be lightuserdata. */
288+
#define LJ_KEYINDEX 0xfffe7fffu
289+
287290
#if LJ_GC64
288291
#define LJ_GCVMASK (((uint64_t)1 << 47) - 1)
289292
#endif

src/lj_tab.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -568,56 +568,66 @@ TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key)
568568

569569
/* -- Table traversal ----------------------------------------------------- */
570570

571-
/* Get the traversal index of a key. */
572-
static uint32_t keyindex(lua_State *L, GCtab *t, cTValue *key)
571+
/* Table traversal indexes:
572+
**
573+
** Array key index: [0 .. t->asize-1]
574+
** Hash key index: [t->asize .. t->asize+t->hmask]
575+
** Invalid key: ~0
576+
*/
577+
578+
/* Get the successor traversal index of a key. */
579+
uint32_t LJ_FASTCALL lj_tab_keyindex(GCtab *t, cTValue *key)
573580
{
574581
TValue tmp;
575582
if (tvisint(key)) {
576583
int32_t k = intV(key);
577584
if ((uint32_t)k < t->asize)
578-
return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */
585+
return (uint32_t)k + 1;
579586
setnumV(&tmp, (lua_Number)k);
580587
key = &tmp;
581588
} else if (tvisnum(key)) {
582589
lua_Number nk = numV(key);
583590
int32_t k = lj_num2int(nk);
584591
if ((uint32_t)k < t->asize && nk == (lua_Number)k)
585-
return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */
592+
return (uint32_t)k + 1;
586593
}
587594
if (!tvisnil(key)) {
588595
Node *n = hashkey(t, key);
589596
do {
590597
if (lj_obj_equal(&n->key, key))
591-
return t->asize + (uint32_t)(n - noderef(t->node));
592-
/* Hash key indexes: [t->asize..t->asize+t->nmask] */
598+
return t->asize + (uint32_t)((n+1) - noderef(t->node));
593599
} while ((n = nextnode(n)));
594-
if (key->u32.hi == 0xfffe7fff) /* ITERN was despecialized while running. */
595-
return key->u32.lo - 1;
596-
lj_err_msg(L, LJ_ERR_NEXTIDX);
597-
return 0; /* unreachable */
600+
if (key->u32.hi == LJ_KEYINDEX) /* Despecialized ITERN while running. */
601+
return key->u32.lo;
602+
return ~0u; /* Invalid key to next. */
598603
}
599-
return ~0u; /* A nil key starts the traversal. */
604+
return 0; /* A nil key starts the traversal. */
600605
}
601606

602-
/* Advance to the next step in a table traversal. */
603-
int lj_tab_next(lua_State *L, GCtab *t, TValue *key)
607+
/* Get the next key/value pair of a table traversal. */
608+
int lj_tab_next(GCtab *t, cTValue *key, TValue *o)
604609
{
605-
uint32_t i = keyindex(L, t, key); /* Find predecessor key index. */
606-
for (i++; i < t->asize; i++) /* First traverse the array keys. */
607-
if (!tvisnil(arrayslot(t, i))) {
608-
setintV(key, i);
609-
copyTV(L, key+1, arrayslot(t, i));
610+
uint32_t idx = lj_tab_keyindex(t, key); /* Find successor index of key. */
611+
/* First traverse the array part. */
612+
for (; idx < t->asize; idx++) {
613+
cTValue *a = arrayslot(t, idx);
614+
if (LJ_LIKELY(!tvisnil(a))) {
615+
setintV(o, idx);
616+
o[1] = *a;
610617
return 1;
611618
}
612-
for (i -= t->asize; i <= t->hmask; i++) { /* Then traverse the hash keys. */
613-
Node *n = &noderef(t->node)[i];
619+
}
620+
idx -= t->asize;
621+
/* Then traverse the hash part. */
622+
for (; idx <= t->hmask; idx++) {
623+
Node *n = &noderef(t->node)[idx];
614624
if (!tvisnil(&n->val)) {
615-
copyTV(L, key, &n->key);
616-
copyTV(L, key+1, &n->val);
625+
o[0] = n->key;
626+
o[1] = n->val;
617627
return 1;
618628
}
619629
}
620-
return 0; /* End of traversal. */
630+
return (int32_t)idx < 0 ? -1 : 0; /* Invalid key or end of traversal. */
621631
}
622632

623633
/* -- Table length calculation -------------------------------------------- */

src/lj_tab.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ LJ_FUNC TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key);
8686
#define lj_tab_setint(L, t, key) \
8787
(inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_setinth(L, (t), (key)))
8888

89-
LJ_FUNCA int lj_tab_next(lua_State *L, GCtab *t, TValue *key);
89+
LJ_FUNC uint32_t LJ_FASTCALL lj_tab_keyindex(GCtab *t, cTValue *key);
90+
LJ_FUNCA int lj_tab_next(GCtab *t, cTValue *key, TValue *o);
9091
LJ_FUNCA MSize LJ_FASTCALL lj_tab_len(GCtab *t);
9192
#if LJ_HASJIT
9293
LJ_FUNC MSize LJ_FASTCALL lj_tab_len_hint(GCtab *t, size_t hint);

src/vm_arm.dasc

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,24 +1111,18 @@ static void build_subroutines(BuildCtx *ctx)
11111111
| checktab CARG2, ->fff_fallback
11121112
| strd CARG34, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
11131113
| ldr PC, [BASE, FRAME_PC]
1114-
| mov CARG2, CARG1
1115-
| str BASE, L->base // Add frame since C call can throw.
1116-
| mov CARG1, L
1117-
| str BASE, L->top // Dummy frame length is ok.
1118-
| add CARG3, BASE, #8
1119-
| str PC, SAVE_PC
1120-
| bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
1121-
| // Returns 0 at end of traversal.
1114+
| add CARG2, BASE, #8
1115+
| sub CARG3, BASE, #8
1116+
| bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1117+
| // Returns 1=found, 0=end, -1=error.
11221118
| .IOS ldr BASE, L->base
11231119
| cmp CRET1, #0
1124-
| mvneq CRET2, #~LJ_TNIL
1125-
| beq ->fff_restv // End of traversal: return nil.
1126-
| ldrd CARG12, [BASE, #8] // Copy key and value to results.
1127-
| ldrd CARG34, [BASE, #16]
1128-
| mov RC, #(2+1)*8
1129-
| strd CARG12, [BASE, #-8]
1130-
| strd CARG34, [BASE]
1131-
| b ->fff_res
1120+
| mov RC, #(2+1)*8
1121+
| bgt ->fff_res // Found key/value.
1122+
| bmi ->fff_fallback // Invalid key.
1123+
| // End of traversal: return nil.
1124+
| mvn CRET2, #~LJ_TNIL
1125+
| b ->fff_restv
11321126
|
11331127
|.ffunc_1 pairs
11341128
| checktab CARG2, ->fff_fallback
@@ -3989,7 +3983,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
39893983
| ins_next1
39903984
| ins_next2
39913985
| mov CARG1, #0
3992-
| mvn CARG2, #0x00018000
3986+
| mvn CARG2, #~LJ_KEYINDEX
39933987
| strd CARG1, [RA, #-8] // Initialize control var.
39943988
|1:
39953989
| ins_next3

src/vm_arm64.dasc

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,21 +1086,19 @@ static void build_subroutines(BuildCtx *ctx)
10861086
|//-- Base library: iterators -------------------------------------------
10871087
|
10881088
|.ffunc_1 next
1089-
| checktp CARG2, CARG1, LJ_TTAB, ->fff_fallback
1089+
| checktp CARG1, LJ_TTAB, ->fff_fallback
10901090
| str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
10911091
| ldr PC, [BASE, FRAME_PC]
1092-
| stp BASE, BASE, L->base // Add frame since C call can throw.
1093-
| mov CARG1, L
1094-
| add CARG3, BASE, #8
1095-
| str PC, SAVE_PC
1096-
| bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
1097-
| // Returns 0 at end of traversal.
1092+
| add CARG2, BASE, #8
1093+
| sub CARG3, BASE, #16
1094+
| bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1095+
| // Returns 1=found, 0=end, -1=error.
1096+
| mov RC, #(2+1)*8
1097+
| tbnz CRET1w, #31, ->fff_fallback // Invalid key.
1098+
| cbnz CRET1, ->fff_res // Found key/value.
1099+
| // End of traversal: return nil.
10981100
| str TISNIL, [BASE, #-16]
1099-
| cbz CRET1, ->fff_res1 // End of traversal: return nil.
1100-
| ldp CARG1, CARG2, [BASE, #8] // Copy key and value to results.
1101-
| mov RC, #(2+1)*8
1102-
| stp CARG1, CARG2, [BASE, #-16]
1103-
| b ->fff_res
1101+
| b ->fff_res1
11041102
|
11051103
|.ffunc_1 pairs
11061104
| checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
@@ -3384,7 +3382,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
33843382
| ccmp CARG4, TISNIL, #0, eq
33853383
| ccmp TMP1w, #FF_next_N, #0, eq
33863384
| bne >5
3387-
| mov TMP0w, #0xfffe7fff
3385+
| mov TMP0w, #0xfffe7fff // LJ_KEYINDEX
33883386
| lsl TMP0, TMP0, #32
33893387
| str TMP0, [RA, #-8] // Initialize control var.
33903388
|1:

src/vm_mips.dasc

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,35 +1262,27 @@ static void build_subroutines(BuildCtx *ctx)
12621262
|//-- Base library: iterators -------------------------------------------
12631263
|
12641264
|.ffunc next
1265-
| lw CARG1, HI(BASE)
1266-
| lw TAB:CARG2, LO(BASE)
1265+
| lw CARG2, HI(BASE)
1266+
| lw TAB:CARG1, LO(BASE)
12671267
| beqz NARGS8:RC, ->fff_fallback
12681268
|. addu TMP2, BASE, NARGS8:RC
12691269
| li AT, LJ_TTAB
12701270
| sw TISNIL, HI(TMP2) // Set missing 2nd arg to nil.
1271-
| bne CARG1, AT, ->fff_fallback
1271+
| bne CARG2, AT, ->fff_fallback
12721272
|. lw PC, FRAME_PC(BASE)
12731273
| load_got lj_tab_next
1274-
| sw BASE, L->base // Add frame since C call can throw.
1275-
| sw BASE, L->top // Dummy frame length is ok.
1276-
| addiu CARG3, BASE, 8
1277-
| sw PC, SAVE_PC
1278-
| call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
1279-
|. move CARG1, L
1280-
| // Returns 0 at end of traversal.
1274+
| addiu CARG2, BASE, 8
1275+
| call_intern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1276+
|. addiu CARG3, BASE, -8
1277+
| // Returns 1=found, 0=end, -1=error.
1278+
| addiu RA, BASE, -8
1279+
| bgtz CRET1, ->fff_res // Found key/value.
1280+
|. li RD, (2+1)*8
12811281
| beqz CRET1, ->fff_restv // End of traversal: return nil.
12821282
|. li SFARG1HI, LJ_TNIL
1283-
| lw TMP0, 8+HI(BASE)
1284-
| lw TMP1, 8+LO(BASE)
1285-
| addiu RA, BASE, -8
1286-
| lw TMP2, 16+HI(BASE)
1287-
| lw TMP3, 16+LO(BASE)
1288-
| sw TMP0, HI(RA)
1289-
| sw TMP1, LO(RA)
1290-
| sw TMP2, 8+HI(RA)
1291-
| sw TMP3, 8+LO(RA)
1292-
| b ->fff_res
1293-
|. li RD, (2+1)*8
1283+
| lw CFUNC:RB, FRAME_FUNC(BASE)
1284+
| b ->fff_fallback // Invalid key.
1285+
|. li RC, 2*8
12941286
|
12951287
|.ffunc_1 pairs
12961288
| li AT, LJ_TTAB
@@ -4611,9 +4603,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
46114603
| addiu CARG2, CARG2, -FF_next_N
46124604
| or CARG2, CARG2, CARG3
46134605
| bnez CARG2, >5
4614-
|. lui TMP1, 0xfffe
4606+
|. lui TMP1, (LJ_KEYINDEX >> 16)
46154607
| addu PC, TMP0, TMP2
4616-
| ori TMP1, TMP1, 0x7fff
4608+
| ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
46174609
| sw r0, -8+LO(RA) // Initialize control var.
46184610
| sw TMP1, -8+HI(RA)
46194611
|1:

src/vm_mips64.dasc

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,27 +1322,24 @@ static void build_subroutines(BuildCtx *ctx)
13221322
|//-- Base library: iterators -------------------------------------------
13231323
|
13241324
|.ffunc_1 next
1325-
| checktp CARG2, CARG1, -LJ_TTAB, ->fff_fallback
1325+
| checktp CARG1, -LJ_TTAB, ->fff_fallback
13261326
| daddu TMP2, BASE, NARGS8:RC
13271327
| sd TISNIL, 0(TMP2) // Set missing 2nd arg to nil.
1328-
| ld PC, FRAME_PC(BASE)
13291328
| load_got lj_tab_next
1330-
| sd BASE, L->base // Add frame since C call can throw.
1331-
| sd BASE, L->top // Dummy frame length is ok.
1332-
| daddiu CARG3, BASE, 8
1333-
| sd PC, SAVE_PC
1334-
| call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
1335-
|. move CARG1, L
1336-
| // Returns 0 at end of traversal.
1329+
| ld PC, FRAME_PC(BASE)
1330+
| daddiu CARG2, BASE, 8
1331+
| call_intern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1332+
|. daddiu CARG3, BASE, -16
1333+
| // Returns 1=found, 0=end, -1=error.
1334+
| daddiu RA, BASE, -16
1335+
| bgtz CRET1, ->fff_res // Found key/value.
1336+
|. li RD, (2+1)*8
13371337
| beqz CRET1, ->fff_restv // End of traversal: return nil.
13381338
|. move CARG1, TISNIL
1339-
| ld TMP0, 8(BASE)
1340-
| daddiu RA, BASE, -16
1341-
| ld TMP2, 16(BASE)
1342-
| sd TMP0, 0(RA)
1343-
| sd TMP2, 8(RA)
1344-
| b ->fff_res
1345-
|. li RD, (2+1)*8
1339+
| ld CFUNC:RB, FRAME_FUNC(BASE)
1340+
| cleartp CFUNC:RB
1341+
| b ->fff_fallback // Invalid key.
1342+
|. li RC, 2*8
13461343
|
13471344
|.ffunc_1 pairs
13481345
| checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback
@@ -4727,11 +4724,10 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
47274724
|. addiu RC, RC, 1
47284725
| sd TMP2, 0(RA)
47294726
| sd CARG1, 8(RA)
4730-
| or TMP0, RC, CARG3
47314727
| lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
47324728
| decode_RD4b RD
47334729
| daddu RD, RD, TMP3
4734-
| sw TMP0, -8+LO(RA) // Update control var.
4730+
| sw RC, -8+LO(RA) // Update control var.
47354731
| daddu PC, PC, RD
47364732
|3:
47374733
| ins_next
@@ -4781,9 +4777,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
47814777
| daddiu TMP1, TMP1, -FF_next_N
47824778
| or AT, AT, TMP1
47834779
| bnez AT, >5
4784-
|. lui TMP1, 0xfffe
4780+
|. lui TMP1, (LJ_KEYINDEX >> 16)
47854781
| daddu PC, TMP0, TMP2
4786-
| ori TMP1, TMP1, 0x7fff
4782+
| ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
47874783
| dsll TMP1, TMP1, 32
47884784
| sd TMP1, -8(RA)
47894785
|1:

0 commit comments

Comments
 (0)