Refactor table traversal.

Sponsored by OpenResty Inc.
This commit is contained in:
Mike Pall 2021-09-19 17:38:49 +02:00
parent 4e0ea654a8
commit c6f5ef649b
12 changed files with 156 additions and 210 deletions

View File

@ -79,6 +79,7 @@ LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
LJLIB_ASM(next) LJLIB_ASM(next)
{ {
lj_lib_checktab(L, 1); lj_lib_checktab(L, 1);
lj_err_msg(L, LJ_ERR_NEXTIDX);
return FFH_UNREACHABLE; return FFH_UNREACHABLE;
} }

View File

@ -893,11 +893,13 @@ LUA_API int lua_next(lua_State *L, int idx)
cTValue *t = index2adr(L, idx); cTValue *t = index2adr(L, idx);
int more; int more;
lj_checkapi(tvistab(t), "stack slot %d is not a table", idx); lj_checkapi(tvistab(t), "stack slot %d is not a table", idx);
more = lj_tab_next(L, tabV(t), L->top-1); more = lj_tab_next(tabV(t), L->top-1, L->top-1);
if (more) { if (more > 0) {
incr_top(L); /* Return new key and value slot. */ incr_top(L); /* Return new key and value slot. */
} else { /* End of traversal. */ } else if (!more) { /* End of traversal. */
L->top--; /* Remove key slot. */ L->top--; /* Remove key slot. */
} else {
lj_err_msg(L, LJ_ERR_NEXTIDX);
} }
return more; return more;
} }

View File

@ -284,6 +284,9 @@ typedef const TValue cTValue;
#define LJ_TISGCV (LJ_TSTR+1) #define LJ_TISGCV (LJ_TSTR+1)
#define LJ_TISTABUD LJ_TTAB #define LJ_TISTABUD LJ_TTAB
/* Type marker for slot holding a traversal index. Must be lightuserdata. */
#define LJ_KEYINDEX 0xfffe7fffu
#if LJ_GC64 #if LJ_GC64
#define LJ_GCVMASK (((uint64_t)1 << 47) - 1) #define LJ_GCVMASK (((uint64_t)1 << 47) - 1)
#endif #endif

View File

@ -568,56 +568,66 @@ TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key)
/* -- Table traversal ----------------------------------------------------- */ /* -- Table traversal ----------------------------------------------------- */
/* Get the traversal index of a key. */ /* Table traversal indexes:
static uint32_t keyindex(lua_State *L, GCtab *t, cTValue *key) **
** Array key index: [0 .. t->asize-1]
** Hash key index: [t->asize .. t->asize+t->hmask]
** Invalid key: ~0
*/
/* Get the successor traversal index of a key. */
uint32_t LJ_FASTCALL lj_tab_keyindex(GCtab *t, cTValue *key)
{ {
TValue tmp; TValue tmp;
if (tvisint(key)) { if (tvisint(key)) {
int32_t k = intV(key); int32_t k = intV(key);
if ((uint32_t)k < t->asize) if ((uint32_t)k < t->asize)
return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */ return (uint32_t)k + 1;
setnumV(&tmp, (lua_Number)k); setnumV(&tmp, (lua_Number)k);
key = &tmp; key = &tmp;
} else if (tvisnum(key)) { } else if (tvisnum(key)) {
lua_Number nk = numV(key); lua_Number nk = numV(key);
int32_t k = lj_num2int(nk); int32_t k = lj_num2int(nk);
if ((uint32_t)k < t->asize && nk == (lua_Number)k) if ((uint32_t)k < t->asize && nk == (lua_Number)k)
return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */ return (uint32_t)k + 1;
} }
if (!tvisnil(key)) { if (!tvisnil(key)) {
Node *n = hashkey(t, key); Node *n = hashkey(t, key);
do { do {
if (lj_obj_equal(&n->key, key)) if (lj_obj_equal(&n->key, key))
return t->asize + (uint32_t)(n - noderef(t->node)); return t->asize + (uint32_t)((n+1) - noderef(t->node));
/* Hash key indexes: [t->asize..t->asize+t->nmask] */
} while ((n = nextnode(n))); } while ((n = nextnode(n)));
if (key->u32.hi == 0xfffe7fff) /* ITERN was despecialized while running. */ if (key->u32.hi == LJ_KEYINDEX) /* Despecialized ITERN while running. */
return key->u32.lo - 1; return key->u32.lo;
lj_err_msg(L, LJ_ERR_NEXTIDX); return ~0u; /* Invalid key to next. */
return 0; /* unreachable */
} }
return ~0u; /* A nil key starts the traversal. */ return 0; /* A nil key starts the traversal. */
} }
/* Advance to the next step in a table traversal. */ /* Get the next key/value pair of a table traversal. */
int lj_tab_next(lua_State *L, GCtab *t, TValue *key) int lj_tab_next(GCtab *t, cTValue *key, TValue *o)
{ {
uint32_t i = keyindex(L, t, key); /* Find predecessor key index. */ uint32_t idx = lj_tab_keyindex(t, key); /* Find successor index of key. */
for (i++; i < t->asize; i++) /* First traverse the array keys. */ /* First traverse the array part. */
if (!tvisnil(arrayslot(t, i))) { for (; idx < t->asize; idx++) {
setintV(key, i); cTValue *a = arrayslot(t, idx);
copyTV(L, key+1, arrayslot(t, i)); if (LJ_LIKELY(!tvisnil(a))) {
setintV(o, idx);
o[1] = *a;
return 1; return 1;
} }
for (i -= t->asize; i <= t->hmask; i++) { /* Then traverse the hash keys. */ }
Node *n = &noderef(t->node)[i]; idx -= t->asize;
/* Then traverse the hash part. */
for (; idx <= t->hmask; idx++) {
Node *n = &noderef(t->node)[idx];
if (!tvisnil(&n->val)) { if (!tvisnil(&n->val)) {
copyTV(L, key, &n->key); o[0] = n->key;
copyTV(L, key+1, &n->val); o[1] = n->val;
return 1; return 1;
} }
} }
return 0; /* End of traversal. */ return (int32_t)idx < 0 ? -1 : 0; /* Invalid key or end of traversal. */
} }
/* -- Table length calculation -------------------------------------------- */ /* -- Table length calculation -------------------------------------------- */

View File

@ -86,7 +86,8 @@ LJ_FUNC TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key);
#define lj_tab_setint(L, t, key) \ #define lj_tab_setint(L, t, key) \
(inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_setinth(L, (t), (key))) (inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_setinth(L, (t), (key)))
LJ_FUNCA int lj_tab_next(lua_State *L, GCtab *t, TValue *key); LJ_FUNC uint32_t LJ_FASTCALL lj_tab_keyindex(GCtab *t, cTValue *key);
LJ_FUNCA int lj_tab_next(GCtab *t, cTValue *key, TValue *o);
LJ_FUNCA MSize LJ_FASTCALL lj_tab_len(GCtab *t); LJ_FUNCA MSize LJ_FASTCALL lj_tab_len(GCtab *t);
#if LJ_HASJIT #if LJ_HASJIT
LJ_FUNC MSize LJ_FASTCALL lj_tab_len_hint(GCtab *t, size_t hint); LJ_FUNC MSize LJ_FASTCALL lj_tab_len_hint(GCtab *t, size_t hint);

View File

@ -1111,24 +1111,18 @@ static void build_subroutines(BuildCtx *ctx)
| checktab CARG2, ->fff_fallback | checktab CARG2, ->fff_fallback
| strd CARG34, [BASE, NARGS8:RC] // Set missing 2nd arg to nil. | strd CARG34, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
| ldr PC, [BASE, FRAME_PC] | ldr PC, [BASE, FRAME_PC]
| mov CARG2, CARG1 | add CARG2, BASE, #8
| str BASE, L->base // Add frame since C call can throw. | sub CARG3, BASE, #8
| mov CARG1, L | bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
| str BASE, L->top // Dummy frame length is ok. | // Returns 1=found, 0=end, -1=error.
| add CARG3, BASE, #8
| str PC, SAVE_PC
| bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
| // Returns 0 at end of traversal.
| .IOS ldr BASE, L->base | .IOS ldr BASE, L->base
| cmp CRET1, #0 | cmp CRET1, #0
| mvneq CRET2, #~LJ_TNIL
| beq ->fff_restv // End of traversal: return nil.
| ldrd CARG12, [BASE, #8] // Copy key and value to results.
| ldrd CARG34, [BASE, #16]
| mov RC, #(2+1)*8 | mov RC, #(2+1)*8
| strd CARG12, [BASE, #-8] | bgt ->fff_res // Found key/value.
| strd CARG34, [BASE] | bmi ->fff_fallback // Invalid key.
| b ->fff_res | // End of traversal: return nil.
| mvn CRET2, #~LJ_TNIL
| b ->fff_restv
| |
|.ffunc_1 pairs |.ffunc_1 pairs
| checktab CARG2, ->fff_fallback | checktab CARG2, ->fff_fallback
@ -3989,7 +3983,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| ins_next1 | ins_next1
| ins_next2 | ins_next2
| mov CARG1, #0 | mov CARG1, #0
| mvn CARG2, #0x00018000 | mvn CARG2, #~LJ_KEYINDEX
| strd CARG1, [RA, #-8] // Initialize control var. | strd CARG1, [RA, #-8] // Initialize control var.
|1: |1:
| ins_next3 | ins_next3

View File

@ -1086,21 +1086,19 @@ static void build_subroutines(BuildCtx *ctx)
|//-- Base library: iterators ------------------------------------------- |//-- Base library: iterators -------------------------------------------
| |
|.ffunc_1 next |.ffunc_1 next
| checktp CARG2, CARG1, LJ_TTAB, ->fff_fallback | checktp CARG1, LJ_TTAB, ->fff_fallback
| str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil. | str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
| ldr PC, [BASE, FRAME_PC] | ldr PC, [BASE, FRAME_PC]
| stp BASE, BASE, L->base // Add frame since C call can throw. | add CARG2, BASE, #8
| mov CARG1, L | sub CARG3, BASE, #16
| add CARG3, BASE, #8 | bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
| str PC, SAVE_PC | // Returns 1=found, 0=end, -1=error.
| bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
| // Returns 0 at end of traversal.
| str TISNIL, [BASE, #-16]
| cbz CRET1, ->fff_res1 // End of traversal: return nil.
| ldp CARG1, CARG2, [BASE, #8] // Copy key and value to results.
| mov RC, #(2+1)*8 | mov RC, #(2+1)*8
| stp CARG1, CARG2, [BASE, #-16] | tbnz CRET1w, #31, ->fff_fallback // Invalid key.
| b ->fff_res | cbnz CRET1, ->fff_res // Found key/value.
| // End of traversal: return nil.
| str TISNIL, [BASE, #-16]
| b ->fff_res1
| |
|.ffunc_1 pairs |.ffunc_1 pairs
| checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
@ -3384,7 +3382,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| ccmp CARG4, TISNIL, #0, eq | ccmp CARG4, TISNIL, #0, eq
| ccmp TMP1w, #FF_next_N, #0, eq | ccmp TMP1w, #FF_next_N, #0, eq
| bne >5 | bne >5
| mov TMP0w, #0xfffe7fff | mov TMP0w, #0xfffe7fff // LJ_KEYINDEX
| lsl TMP0, TMP0, #32 | lsl TMP0, TMP0, #32
| str TMP0, [RA, #-8] // Initialize control var. | str TMP0, [RA, #-8] // Initialize control var.
|1: |1:

View File

@ -1262,35 +1262,27 @@ static void build_subroutines(BuildCtx *ctx)
|//-- Base library: iterators ------------------------------------------- |//-- Base library: iterators -------------------------------------------
| |
|.ffunc next |.ffunc next
| lw CARG1, HI(BASE) | lw CARG2, HI(BASE)
| lw TAB:CARG2, LO(BASE) | lw TAB:CARG1, LO(BASE)
| beqz NARGS8:RC, ->fff_fallback | beqz NARGS8:RC, ->fff_fallback
|. addu TMP2, BASE, NARGS8:RC |. addu TMP2, BASE, NARGS8:RC
| li AT, LJ_TTAB | li AT, LJ_TTAB
| sw TISNIL, HI(TMP2) // Set missing 2nd arg to nil. | sw TISNIL, HI(TMP2) // Set missing 2nd arg to nil.
| bne CARG1, AT, ->fff_fallback | bne CARG2, AT, ->fff_fallback
|. lw PC, FRAME_PC(BASE) |. lw PC, FRAME_PC(BASE)
| load_got lj_tab_next | load_got lj_tab_next
| sw BASE, L->base // Add frame since C call can throw. | addiu CARG2, BASE, 8
| sw BASE, L->top // Dummy frame length is ok. | call_intern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
| addiu CARG3, BASE, 8 |. addiu CARG3, BASE, -8
| sw PC, SAVE_PC | // Returns 1=found, 0=end, -1=error.
| call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) | addiu RA, BASE, -8
|. move CARG1, L | bgtz CRET1, ->fff_res // Found key/value.
| // Returns 0 at end of traversal. |. li RD, (2+1)*8
| beqz CRET1, ->fff_restv // End of traversal: return nil. | beqz CRET1, ->fff_restv // End of traversal: return nil.
|. li SFARG1HI, LJ_TNIL |. li SFARG1HI, LJ_TNIL
| lw TMP0, 8+HI(BASE) | lw CFUNC:RB, FRAME_FUNC(BASE)
| lw TMP1, 8+LO(BASE) | b ->fff_fallback // Invalid key.
| addiu RA, BASE, -8 |. li RC, 2*8
| lw TMP2, 16+HI(BASE)
| lw TMP3, 16+LO(BASE)
| sw TMP0, HI(RA)
| sw TMP1, LO(RA)
| sw TMP2, 8+HI(RA)
| sw TMP3, 8+LO(RA)
| b ->fff_res
|. li RD, (2+1)*8
| |
|.ffunc_1 pairs |.ffunc_1 pairs
| li AT, LJ_TTAB | li AT, LJ_TTAB
@ -4611,9 +4603,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| addiu CARG2, CARG2, -FF_next_N | addiu CARG2, CARG2, -FF_next_N
| or CARG2, CARG2, CARG3 | or CARG2, CARG2, CARG3
| bnez CARG2, >5 | bnez CARG2, >5
|. lui TMP1, 0xfffe |. lui TMP1, (LJ_KEYINDEX >> 16)
| addu PC, TMP0, TMP2 | addu PC, TMP0, TMP2
| ori TMP1, TMP1, 0x7fff | ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
| sw r0, -8+LO(RA) // Initialize control var. | sw r0, -8+LO(RA) // Initialize control var.
| sw TMP1, -8+HI(RA) | sw TMP1, -8+HI(RA)
|1: |1:

View File

@ -1322,27 +1322,24 @@ static void build_subroutines(BuildCtx *ctx)
|//-- Base library: iterators ------------------------------------------- |//-- Base library: iterators -------------------------------------------
| |
|.ffunc_1 next |.ffunc_1 next
| checktp CARG2, CARG1, -LJ_TTAB, ->fff_fallback | checktp CARG1, -LJ_TTAB, ->fff_fallback
| daddu TMP2, BASE, NARGS8:RC | daddu TMP2, BASE, NARGS8:RC
| sd TISNIL, 0(TMP2) // Set missing 2nd arg to nil. | sd TISNIL, 0(TMP2) // Set missing 2nd arg to nil.
| ld PC, FRAME_PC(BASE)
| load_got lj_tab_next | load_got lj_tab_next
| sd BASE, L->base // Add frame since C call can throw. | ld PC, FRAME_PC(BASE)
| sd BASE, L->top // Dummy frame length is ok. | daddiu CARG2, BASE, 8
| daddiu CARG3, BASE, 8 | call_intern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
| sd PC, SAVE_PC |. daddiu CARG3, BASE, -16
| call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) | // Returns 1=found, 0=end, -1=error.
|. move CARG1, L | daddiu RA, BASE, -16
| // Returns 0 at end of traversal. | bgtz CRET1, ->fff_res // Found key/value.
|. li RD, (2+1)*8
| beqz CRET1, ->fff_restv // End of traversal: return nil. | beqz CRET1, ->fff_restv // End of traversal: return nil.
|. move CARG1, TISNIL |. move CARG1, TISNIL
| ld TMP0, 8(BASE) | ld CFUNC:RB, FRAME_FUNC(BASE)
| daddiu RA, BASE, -16 | cleartp CFUNC:RB
| ld TMP2, 16(BASE) | b ->fff_fallback // Invalid key.
| sd TMP0, 0(RA) |. li RC, 2*8
| sd TMP2, 8(RA)
| b ->fff_res
|. li RD, (2+1)*8
| |
|.ffunc_1 pairs |.ffunc_1 pairs
| checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback | checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback
@ -4727,11 +4724,10 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
|. addiu RC, RC, 1 |. addiu RC, RC, 1
| sd TMP2, 0(RA) | sd TMP2, 0(RA)
| sd CARG1, 8(RA) | sd CARG1, 8(RA)
| or TMP0, RC, CARG3
| lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
| decode_RD4b RD | decode_RD4b RD
| daddu RD, RD, TMP3 | daddu RD, RD, TMP3
| sw TMP0, -8+LO(RA) // Update control var. | sw RC, -8+LO(RA) // Update control var.
| daddu PC, PC, RD | daddu PC, PC, RD
|3: |3:
| ins_next | ins_next
@ -4781,9 +4777,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| daddiu TMP1, TMP1, -FF_next_N | daddiu TMP1, TMP1, -FF_next_N
| or AT, AT, TMP1 | or AT, AT, TMP1
| bnez AT, >5 | bnez AT, >5
|. lui TMP1, 0xfffe |. lui TMP1, (LJ_KEYINDEX >> 16)
| daddu PC, TMP0, TMP2 | daddu PC, TMP0, TMP2
| ori TMP1, TMP1, 0x7fff | ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
| dsll TMP1, TMP1, 32 | dsll TMP1, TMP1, 32
| sd TMP1, -8(RA) | sd TMP1, -8(RA)
|1: |1:

View File

@ -1559,43 +1559,24 @@ static void build_subroutines(BuildCtx *ctx)
| |
|//-- Base library: iterators ------------------------------------------- |//-- Base library: iterators -------------------------------------------
| |
|.ffunc next |.ffunc_1 next
| cmplwi NARGS8:RC, 8
| lwz CARG1, 0(BASE)
| lwz TAB:CARG2, 4(BASE)
| blt ->fff_fallback
| stwx TISNIL, BASE, NARGS8:RC // Set missing 2nd arg to nil. | stwx TISNIL, BASE, NARGS8:RC // Set missing 2nd arg to nil.
| checktab CARG1 | checktab CARG3
| lwz PC, FRAME_PC(BASE) | lwz PC, FRAME_PC(BASE)
| bne ->fff_fallback | bne ->fff_fallback
| stp BASE, L->base // Add frame since C call can throw. | la CARG2, 8(BASE)
| mr CARG1, L | la CARG3, -8(BASE)
| stp BASE, L->top // Dummy frame length is ok. | bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
| la CARG3, 8(BASE) | // Returns 1=found, 0=end, -1=error.
| stw PC, SAVE_PC | cmpwi CRET1, 0
| bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) | la RA, -8(BASE)
| // Returns 0 at end of traversal. | li RD, (2+1)*8
| cmplwi CRET1, 0 | bgt ->fff_res // Found key/value.
| li CARG3, LJ_TNIL | li CARG3, LJ_TNIL
| beq ->fff_restv // End of traversal: return nil. | beq ->fff_restv // End of traversal: return nil.
| la RA, -8(BASE) | lwz CFUNC:RB, FRAME_FUNC(BASE)
|.if FPU | li NARGS8:RC, 2*8
| lfd f0, 8(BASE) // Copy key and value to results. | b ->fff_fallback // Invalid key.
| lfd f1, 16(BASE)
| stfd f0, 0(RA)
| stfd f1, 8(RA)
|.else
| lwz CARG1, 8(BASE)
| lwz CARG2, 12(BASE)
| lwz CARG3, 16(BASE)
| lwz CARG4, 20(BASE)
| stw CARG1, 0(RA)
| stw CARG2, 4(RA)
| stw CARG3, 8(RA)
| stw CARG4, 12(RA)
|.endif
| li RD, (2+1)*8
| b ->fff_res
| |
|.ffunc_1 pairs |.ffunc_1 pairs
| checktab CARG3 | checktab CARG3
@ -5251,8 +5232,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq | crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
| add TMP3, PC, TMP0 | add TMP3, PC, TMP0
| bne cr0, >5 | bne cr0, >5
| lus TMP1, 0xfffe | lus TMP1, (LJ_KEYINDEX >> 16)
| ori TMP1, TMP1, 0x7fff | ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
| stw ZERO, -4(RA) // Initialize control var. | stw ZERO, -4(RA) // Initialize control var.
| stw TMP1, -8(RA) | stw TMP1, -8(RA)
| addis PC, TMP3, -(BCBIAS_J*4 >> 16) | addis PC, TMP3, -(BCBIAS_J*4 >> 16)

View File

@ -1346,44 +1346,28 @@ static void build_subroutines(BuildCtx *ctx)
|.ffunc_1 next |.ffunc_1 next
| je >2 // Missing 2nd arg? | je >2 // Missing 2nd arg?
|1: |1:
|.if X64WIN | mov CARG1, [BASE]
| mov RA, [BASE]
| checktab RA, ->fff_fallback
|.else
| mov CARG2, [BASE]
| checktab CARG2, ->fff_fallback
|.endif
| mov L:RB, SAVE_L
| mov L:RB->base, BASE // Add frame since C call can throw.
| mov L:RB->top, BASE // Dummy frame length is ok.
| mov PC, [BASE-8] | mov PC, [BASE-8]
| checktab CARG1, ->fff_fallback
| mov RB, BASE // Save BASE.
|.if X64WIN |.if X64WIN
| lea CARG3, [BASE+8] | lea CARG3, [BASE-16]
| mov CARG2, RA // Caveat: CARG2 == BASE. | lea CARG2, [BASE+8] // Caveat: CARG2 == BASE.
| mov CARG1, L:RB
|.else |.else
| lea CARG3, [BASE+8] // Caveat: CARG3 == BASE. | lea CARG2, [BASE+8]
| mov CARG1, L:RB | lea CARG3, [BASE-16] // Caveat: CARG3 == BASE.
|.endif |.endif
| mov SAVE_PC, PC // Needed for ITERN fallback. | call extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
| call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) | // 1=found, 0=end, -1=error returned in eax (RD).
| // Flag returned in eax (RD). | mov BASE, RB // Restore BASE.
| mov BASE, L:RB->base | test RDd, RDd; jg ->fff_res2 // Found key/value.
| test RDd, RDd; jz >3 // End of traversal? | js ->fff_fallback_2 // Invalid key.
| // Copy key and value to results. | // End of traversal: return nil.
| mov RB, [BASE+8] | mov aword [BASE-16], LJ_TNIL
| mov RD, [BASE+16] | jmp ->fff_res1
| mov [BASE-16], RB
| mov [BASE-8], RD
|->fff_res2:
| mov RDd, 1+2
| jmp ->fff_res
|2: // Set missing 2nd arg to nil. |2: // Set missing 2nd arg to nil.
| mov aword [BASE+8], LJ_TNIL | mov aword [BASE+8], LJ_TNIL
| jmp <1 | jmp <1
|3: // End of traversal: return nil.
| mov aword [BASE-16], LJ_TNIL
| jmp ->fff_res1
| |
|.ffunc_1 pairs |.ffunc_1 pairs
| mov TAB:RB, [BASE] | mov TAB:RB, [BASE]
@ -1432,7 +1416,9 @@ static void build_subroutines(BuildCtx *ctx)
| // Copy array slot. | // Copy array slot.
| mov RB, [RD] | mov RB, [RD]
| mov [BASE-8], RB | mov [BASE-8], RB
| jmp ->fff_res2 |->fff_res2:
| mov RDd, 1+2
| jmp ->fff_res
|2: // Check for empty hash part first. Otherwise call C function. |2: // Check for empty hash part first. Otherwise call C function.
| cmp dword TAB:RB->hmask, 0; je ->fff_res0 | cmp dword TAB:RB->hmask, 0; je ->fff_res0
|.if X64WIN |.if X64WIN
@ -4125,7 +4111,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| cmp aword [BASE+RA*8-8], LJ_TNIL; jne >5 | cmp aword [BASE+RA*8-8], LJ_TNIL; jne >5
| cmp byte CFUNC:RB->ffid, FF_next_N; jne >5 | cmp byte CFUNC:RB->ffid, FF_next_N; jne >5
| branchPC RD | branchPC RD
| mov64 TMPR, U64x(fffe7fff, 00000000) | mov64 TMPR, ((uint64_t)LJ_KEYINDEX << 32)
| mov [BASE+RA*8-8], TMPR // Initialize control var. | mov [BASE+RA*8-8], TMPR // Initialize control var.
|1: |1:
| ins_next | ins_next

View File

@ -1673,55 +1673,35 @@ static void build_subroutines(BuildCtx *ctx)
| je >2 // Missing 2nd arg? | je >2 // Missing 2nd arg?
|1: |1:
| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
| mov L:RB, SAVE_L
| mov L:RB->base, BASE // Add frame since C call can throw.
| mov L:RB->top, BASE // Dummy frame length is ok.
| mov PC, [BASE-4] | mov PC, [BASE-4]
| mov RB, BASE // Save BASE.
|.if X64WIN |.if X64WIN
| lea CARG3d, [BASE+8] | mov CARG1d, [BASE]
| mov CARG2d, [BASE] // Caveat: CARG2d == BASE. | lea CARG3d, [BASE-8]
| mov CARG1d, L:RB | lea CARG2d, [BASE+8] // Caveat: CARG2d == BASE.
|.elif X64 |.elif X64
| mov CARG2d, [BASE] | mov CARG1d, [BASE]
| lea CARG3d, [BASE+8] // Caveat: CARG3d == BASE. | lea CARG2d, [BASE+8]
| mov CARG1d, L:RB | lea CARG3d, [BASE-8] // Caveat: CARG3d == BASE.
|.else |.else
| mov TAB:RD, [BASE] | mov TAB:RD, [BASE]
| mov ARG2, TAB:RD | mov ARG1, TAB:RD
| mov ARG1, L:RB
| add BASE, 8 | add BASE, 8
| mov ARG2, BASE
| sub BASE, 8+8
| mov ARG3, BASE | mov ARG3, BASE
|.endif |.endif
| mov SAVE_PC, PC // Needed for ITERN fallback. | call extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
| call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) | // 1=found, 0=end, -1=error returned in eax (RD).
| // Flag returned in eax (RD). | mov BASE, RB // Restore BASE.
| mov BASE, L:RB->base | test RD, RD; jg ->fff_res2 // Found key/value.
| test RD, RD; jz >3 // End of traversal? | js ->fff_fallback_2 // Invalid key.
| // Copy key and value to results. | // End of traversal: return nil.
|.if X64 | mov dword [BASE-4], LJ_TNIL
| mov RBa, [BASE+8] | jmp ->fff_res1
| mov RDa, [BASE+16]
| mov [BASE-8], RBa
| mov [BASE], RDa
|.else
| mov RB, [BASE+8]
| mov RD, [BASE+12]
| mov [BASE-8], RB
| mov [BASE-4], RD
| mov RB, [BASE+16]
| mov RD, [BASE+20]
| mov [BASE], RB
| mov [BASE+4], RD
|.endif
|->fff_res2:
| mov RD, 1+2
| jmp ->fff_res
|2: // Set missing 2nd arg to nil. |2: // Set missing 2nd arg to nil.
| mov dword [BASE+12], LJ_TNIL | mov dword [BASE+12], LJ_TNIL
| jmp <1 | jmp <1
|3: // End of traversal: return nil.
| mov dword [BASE-4], LJ_TNIL
| jmp ->fff_res1
| |
|.ffunc_1 pairs |.ffunc_1 pairs
| mov TAB:RB, [BASE] | mov TAB:RB, [BASE]
@ -1775,7 +1755,9 @@ static void build_subroutines(BuildCtx *ctx)
| mov [BASE], RB | mov [BASE], RB
| mov [BASE+4], RD | mov [BASE+4], RD
|.endif |.endif
| jmp ->fff_res2 |->fff_res2:
| mov RD, 1+2
| jmp ->fff_res
|2: // Check for empty hash part first. Otherwise call C function. |2: // Check for empty hash part first. Otherwise call C function.
| cmp dword TAB:RB->hmask, 0; je ->fff_res0 | cmp dword TAB:RB->hmask, 0; je ->fff_res0
| mov FCARG1, TAB:RB | mov FCARG1, TAB:RB
@ -4880,7 +4862,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| cmp byte CFUNC:RB->ffid, FF_next_N; jne >5 | cmp byte CFUNC:RB->ffid, FF_next_N; jne >5
| branchPC RD | branchPC RD
| mov dword [BASE+RA*8-8], 0 // Initialize control var. | mov dword [BASE+RA*8-8], 0 // Initialize control var.
| mov dword [BASE+RA*8-4], 0xfffe7fff | mov dword [BASE+RA*8-4], LJ_KEYINDEX
|1: |1:
| ins_next | ins_next
|5: // Despecialize bytecode if any of the checks fail. |5: // Despecialize bytecode if any of the checks fail.