mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 15:14:08 +00:00
Refactor table traversal.
Sponsored by OpenResty Inc.
This commit is contained in:
parent
4e0ea654a8
commit
c6f5ef649b
@ -79,6 +79,7 @@ LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
|
||||
LJLIB_ASM(next)
|
||||
{
|
||||
lj_lib_checktab(L, 1);
|
||||
lj_err_msg(L, LJ_ERR_NEXTIDX);
|
||||
return FFH_UNREACHABLE;
|
||||
}
|
||||
|
||||
|
@ -893,11 +893,13 @@ LUA_API int lua_next(lua_State *L, int idx)
|
||||
cTValue *t = index2adr(L, idx);
|
||||
int more;
|
||||
lj_checkapi(tvistab(t), "stack slot %d is not a table", idx);
|
||||
more = lj_tab_next(L, tabV(t), L->top-1);
|
||||
if (more) {
|
||||
more = lj_tab_next(tabV(t), L->top-1, L->top-1);
|
||||
if (more > 0) {
|
||||
incr_top(L); /* Return new key and value slot. */
|
||||
} else { /* End of traversal. */
|
||||
} else if (!more) { /* End of traversal. */
|
||||
L->top--; /* Remove key slot. */
|
||||
} else {
|
||||
lj_err_msg(L, LJ_ERR_NEXTIDX);
|
||||
}
|
||||
return more;
|
||||
}
|
||||
|
@ -284,6 +284,9 @@ typedef const TValue cTValue;
|
||||
#define LJ_TISGCV (LJ_TSTR+1)
|
||||
#define LJ_TISTABUD LJ_TTAB
|
||||
|
||||
/* Type marker for slot holding a traversal index. Must be lightuserdata. */
|
||||
#define LJ_KEYINDEX 0xfffe7fffu
|
||||
|
||||
#if LJ_GC64
|
||||
#define LJ_GCVMASK (((uint64_t)1 << 47) - 1)
|
||||
#endif
|
||||
|
62
src/lj_tab.c
62
src/lj_tab.c
@ -568,56 +568,66 @@ TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key)
|
||||
|
||||
/* -- Table traversal ----------------------------------------------------- */
|
||||
|
||||
/* Get the traversal index of a key. */
|
||||
static uint32_t keyindex(lua_State *L, GCtab *t, cTValue *key)
|
||||
/* Table traversal indexes:
|
||||
**
|
||||
** 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;
|
||||
if (tvisint(key)) {
|
||||
int32_t k = intV(key);
|
||||
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);
|
||||
key = &tmp;
|
||||
} else if (tvisnum(key)) {
|
||||
lua_Number nk = numV(key);
|
||||
int32_t k = lj_num2int(nk);
|
||||
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)) {
|
||||
Node *n = hashkey(t, key);
|
||||
do {
|
||||
if (lj_obj_equal(&n->key, key))
|
||||
return t->asize + (uint32_t)(n - noderef(t->node));
|
||||
/* Hash key indexes: [t->asize..t->asize+t->nmask] */
|
||||
return t->asize + (uint32_t)((n+1) - noderef(t->node));
|
||||
} while ((n = nextnode(n)));
|
||||
if (key->u32.hi == 0xfffe7fff) /* ITERN was despecialized while running. */
|
||||
return key->u32.lo - 1;
|
||||
lj_err_msg(L, LJ_ERR_NEXTIDX);
|
||||
return 0; /* unreachable */
|
||||
if (key->u32.hi == LJ_KEYINDEX) /* Despecialized ITERN while running. */
|
||||
return key->u32.lo;
|
||||
return ~0u; /* Invalid key to next. */
|
||||
}
|
||||
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. */
|
||||
int lj_tab_next(lua_State *L, GCtab *t, TValue *key)
|
||||
/* Get the next key/value pair of a table traversal. */
|
||||
int lj_tab_next(GCtab *t, cTValue *key, TValue *o)
|
||||
{
|
||||
uint32_t i = keyindex(L, t, key); /* Find predecessor key index. */
|
||||
for (i++; i < t->asize; i++) /* First traverse the array keys. */
|
||||
if (!tvisnil(arrayslot(t, i))) {
|
||||
setintV(key, i);
|
||||
copyTV(L, key+1, arrayslot(t, i));
|
||||
return 1;
|
||||
}
|
||||
for (i -= t->asize; i <= t->hmask; i++) { /* Then traverse the hash keys. */
|
||||
Node *n = &noderef(t->node)[i];
|
||||
if (!tvisnil(&n->val)) {
|
||||
copyTV(L, key, &n->key);
|
||||
copyTV(L, key+1, &n->val);
|
||||
uint32_t idx = lj_tab_keyindex(t, key); /* Find successor index of key. */
|
||||
/* First traverse the array part. */
|
||||
for (; idx < t->asize; idx++) {
|
||||
cTValue *a = arrayslot(t, idx);
|
||||
if (LJ_LIKELY(!tvisnil(a))) {
|
||||
setintV(o, idx);
|
||||
o[1] = *a;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0; /* End of traversal. */
|
||||
idx -= t->asize;
|
||||
/* Then traverse the hash part. */
|
||||
for (; idx <= t->hmask; idx++) {
|
||||
Node *n = &noderef(t->node)[idx];
|
||||
if (!tvisnil(&n->val)) {
|
||||
o[0] = n->key;
|
||||
o[1] = n->val;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return (int32_t)idx < 0 ? -1 : 0; /* Invalid key or end of traversal. */
|
||||
}
|
||||
|
||||
/* -- Table length calculation -------------------------------------------- */
|
||||
|
@ -86,7 +86,8 @@ LJ_FUNC TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key);
|
||||
#define lj_tab_setint(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);
|
||||
#if LJ_HASJIT
|
||||
LJ_FUNC MSize LJ_FASTCALL lj_tab_len_hint(GCtab *t, size_t hint);
|
||||
|
@ -1111,24 +1111,18 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| checktab CARG2, ->fff_fallback
|
||||
| strd CARG34, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
|
||||
| ldr PC, [BASE, FRAME_PC]
|
||||
| mov CARG2, CARG1
|
||||
| str BASE, L->base // Add frame since C call can throw.
|
||||
| mov CARG1, L
|
||||
| str BASE, L->top // Dummy frame length is ok.
|
||||
| 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.
|
||||
| add CARG2, BASE, #8
|
||||
| sub CARG3, BASE, #8
|
||||
| bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
|
||||
| // Returns 1=found, 0=end, -1=error.
|
||||
| .IOS ldr BASE, L->base
|
||||
| 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
|
||||
| strd CARG12, [BASE, #-8]
|
||||
| strd CARG34, [BASE]
|
||||
| b ->fff_res
|
||||
| mov RC, #(2+1)*8
|
||||
| bgt ->fff_res // Found key/value.
|
||||
| bmi ->fff_fallback // Invalid key.
|
||||
| // End of traversal: return nil.
|
||||
| mvn CRET2, #~LJ_TNIL
|
||||
| b ->fff_restv
|
||||
|
|
||||
|.ffunc_1 pairs
|
||||
| checktab CARG2, ->fff_fallback
|
||||
@ -3989,7 +3983,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
|
||||
| ins_next1
|
||||
| ins_next2
|
||||
| mov CARG1, #0
|
||||
| mvn CARG2, #0x00018000
|
||||
| mvn CARG2, #~LJ_KEYINDEX
|
||||
| strd CARG1, [RA, #-8] // Initialize control var.
|
||||
|1:
|
||||
| ins_next3
|
||||
|
@ -1086,21 +1086,19 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
|//-- Base library: iterators -------------------------------------------
|
||||
|
|
||||
|.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.
|
||||
| ldr PC, [BASE, FRAME_PC]
|
||||
| stp BASE, BASE, L->base // Add frame since C call can throw.
|
||||
| mov CARG1, L
|
||||
| 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.
|
||||
| add CARG2, BASE, #8
|
||||
| sub CARG3, BASE, #16
|
||||
| bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
|
||||
| // Returns 1=found, 0=end, -1=error.
|
||||
| mov RC, #(2+1)*8
|
||||
| tbnz CRET1w, #31, ->fff_fallback // Invalid key.
|
||||
| cbnz CRET1, ->fff_res // Found key/value.
|
||||
| // End of traversal: return nil.
|
||||
| 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
|
||||
| stp CARG1, CARG2, [BASE, #-16]
|
||||
| b ->fff_res
|
||||
| b ->fff_res1
|
||||
|
|
||||
|.ffunc_1 pairs
|
||||
| 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 TMP1w, #FF_next_N, #0, eq
|
||||
| bne >5
|
||||
| mov TMP0w, #0xfffe7fff
|
||||
| mov TMP0w, #0xfffe7fff // LJ_KEYINDEX
|
||||
| lsl TMP0, TMP0, #32
|
||||
| str TMP0, [RA, #-8] // Initialize control var.
|
||||
|1:
|
||||
|
@ -1262,35 +1262,27 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
|//-- Base library: iterators -------------------------------------------
|
||||
|
|
||||
|.ffunc next
|
||||
| lw CARG1, HI(BASE)
|
||||
| lw TAB:CARG2, LO(BASE)
|
||||
| lw CARG2, HI(BASE)
|
||||
| lw TAB:CARG1, LO(BASE)
|
||||
| beqz NARGS8:RC, ->fff_fallback
|
||||
|. addu TMP2, BASE, NARGS8:RC
|
||||
| li AT, LJ_TTAB
|
||||
| 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)
|
||||
| load_got lj_tab_next
|
||||
| sw BASE, L->base // Add frame since C call can throw.
|
||||
| sw BASE, L->top // Dummy frame length is ok.
|
||||
| addiu CARG3, BASE, 8
|
||||
| sw PC, SAVE_PC
|
||||
| call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
|
||||
|. move CARG1, L
|
||||
| // Returns 0 at end of traversal.
|
||||
| addiu CARG2, BASE, 8
|
||||
| call_intern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
|
||||
|. addiu CARG3, BASE, -8
|
||||
| // Returns 1=found, 0=end, -1=error.
|
||||
| addiu RA, BASE, -8
|
||||
| bgtz CRET1, ->fff_res // Found key/value.
|
||||
|. li RD, (2+1)*8
|
||||
| beqz CRET1, ->fff_restv // End of traversal: return nil.
|
||||
|. li SFARG1HI, LJ_TNIL
|
||||
| lw TMP0, 8+HI(BASE)
|
||||
| lw TMP1, 8+LO(BASE)
|
||||
| addiu RA, BASE, -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
|
||||
| lw CFUNC:RB, FRAME_FUNC(BASE)
|
||||
| b ->fff_fallback // Invalid key.
|
||||
|. li RC, 2*8
|
||||
|
|
||||
|.ffunc_1 pairs
|
||||
| li AT, LJ_TTAB
|
||||
@ -4611,9 +4603,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
|
||||
| addiu CARG2, CARG2, -FF_next_N
|
||||
| or CARG2, CARG2, CARG3
|
||||
| bnez CARG2, >5
|
||||
|. lui TMP1, 0xfffe
|
||||
|. lui TMP1, (LJ_KEYINDEX >> 16)
|
||||
| addu PC, TMP0, TMP2
|
||||
| ori TMP1, TMP1, 0x7fff
|
||||
| ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
|
||||
| sw r0, -8+LO(RA) // Initialize control var.
|
||||
| sw TMP1, -8+HI(RA)
|
||||
|1:
|
||||
|
@ -1322,27 +1322,24 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
|//-- Base library: iterators -------------------------------------------
|
||||
|
|
||||
|.ffunc_1 next
|
||||
| checktp CARG2, CARG1, -LJ_TTAB, ->fff_fallback
|
||||
| checktp CARG1, -LJ_TTAB, ->fff_fallback
|
||||
| daddu TMP2, BASE, NARGS8:RC
|
||||
| sd TISNIL, 0(TMP2) // Set missing 2nd arg to nil.
|
||||
| ld PC, FRAME_PC(BASE)
|
||||
| load_got lj_tab_next
|
||||
| sd BASE, L->base // Add frame since C call can throw.
|
||||
| sd BASE, L->top // Dummy frame length is ok.
|
||||
| daddiu CARG3, BASE, 8
|
||||
| sd PC, SAVE_PC
|
||||
| call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
|
||||
|. move CARG1, L
|
||||
| // Returns 0 at end of traversal.
|
||||
| ld PC, FRAME_PC(BASE)
|
||||
| daddiu CARG2, BASE, 8
|
||||
| call_intern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
|
||||
|. daddiu CARG3, BASE, -16
|
||||
| // Returns 1=found, 0=end, -1=error.
|
||||
| daddiu RA, BASE, -16
|
||||
| bgtz CRET1, ->fff_res // Found key/value.
|
||||
|. li RD, (2+1)*8
|
||||
| beqz CRET1, ->fff_restv // End of traversal: return nil.
|
||||
|. move CARG1, TISNIL
|
||||
| ld TMP0, 8(BASE)
|
||||
| daddiu RA, BASE, -16
|
||||
| ld TMP2, 16(BASE)
|
||||
| sd TMP0, 0(RA)
|
||||
| sd TMP2, 8(RA)
|
||||
| b ->fff_res
|
||||
|. li RD, (2+1)*8
|
||||
| ld CFUNC:RB, FRAME_FUNC(BASE)
|
||||
| cleartp CFUNC:RB
|
||||
| b ->fff_fallback // Invalid key.
|
||||
|. li RC, 2*8
|
||||
|
|
||||
|.ffunc_1 pairs
|
||||
| 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
|
||||
| sd TMP2, 0(RA)
|
||||
| sd CARG1, 8(RA)
|
||||
| or TMP0, RC, CARG3
|
||||
| lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
|
||||
| decode_RD4b RD
|
||||
| daddu RD, RD, TMP3
|
||||
| sw TMP0, -8+LO(RA) // Update control var.
|
||||
| sw RC, -8+LO(RA) // Update control var.
|
||||
| daddu PC, PC, RD
|
||||
|3:
|
||||
| ins_next
|
||||
@ -4781,9 +4777,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
|
||||
| daddiu TMP1, TMP1, -FF_next_N
|
||||
| or AT, AT, TMP1
|
||||
| bnez AT, >5
|
||||
|. lui TMP1, 0xfffe
|
||||
|. lui TMP1, (LJ_KEYINDEX >> 16)
|
||||
| daddu PC, TMP0, TMP2
|
||||
| ori TMP1, TMP1, 0x7fff
|
||||
| ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
|
||||
| dsll TMP1, TMP1, 32
|
||||
| sd TMP1, -8(RA)
|
||||
|1:
|
||||
|
@ -1559,43 +1559,24 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
|
|
||||
|//-- Base library: iterators -------------------------------------------
|
||||
|
|
||||
|.ffunc next
|
||||
| cmplwi NARGS8:RC, 8
|
||||
| lwz CARG1, 0(BASE)
|
||||
| lwz TAB:CARG2, 4(BASE)
|
||||
| blt ->fff_fallback
|
||||
|.ffunc_1 next
|
||||
| stwx TISNIL, BASE, NARGS8:RC // Set missing 2nd arg to nil.
|
||||
| checktab CARG1
|
||||
| checktab CARG3
|
||||
| lwz PC, FRAME_PC(BASE)
|
||||
| bne ->fff_fallback
|
||||
| stp BASE, L->base // Add frame since C call can throw.
|
||||
| mr CARG1, L
|
||||
| stp BASE, L->top // Dummy frame length is ok.
|
||||
| la CARG3, 8(BASE)
|
||||
| stw PC, SAVE_PC
|
||||
| bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
|
||||
| // Returns 0 at end of traversal.
|
||||
| cmplwi CRET1, 0
|
||||
| la CARG2, 8(BASE)
|
||||
| la CARG3, -8(BASE)
|
||||
| bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
|
||||
| // Returns 1=found, 0=end, -1=error.
|
||||
| cmpwi CRET1, 0
|
||||
| la RA, -8(BASE)
|
||||
| li RD, (2+1)*8
|
||||
| bgt ->fff_res // Found key/value.
|
||||
| li CARG3, LJ_TNIL
|
||||
| beq ->fff_restv // End of traversal: return nil.
|
||||
| la RA, -8(BASE)
|
||||
|.if FPU
|
||||
| lfd f0, 8(BASE) // Copy key and value to results.
|
||||
| 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
|
||||
| lwz CFUNC:RB, FRAME_FUNC(BASE)
|
||||
| li NARGS8:RC, 2*8
|
||||
| b ->fff_fallback // Invalid key.
|
||||
|
|
||||
|.ffunc_1 pairs
|
||||
| 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
|
||||
| add TMP3, PC, TMP0
|
||||
| bne cr0, >5
|
||||
| lus TMP1, 0xfffe
|
||||
| ori TMP1, TMP1, 0x7fff
|
||||
| lus TMP1, (LJ_KEYINDEX >> 16)
|
||||
| ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
|
||||
| stw ZERO, -4(RA) // Initialize control var.
|
||||
| stw TMP1, -8(RA)
|
||||
| addis PC, TMP3, -(BCBIAS_J*4 >> 16)
|
||||
|
@ -1346,44 +1346,28 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
|.ffunc_1 next
|
||||
| je >2 // Missing 2nd arg?
|
||||
|1:
|
||||
|.if X64WIN
|
||||
| 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 CARG1, [BASE]
|
||||
| mov PC, [BASE-8]
|
||||
| checktab CARG1, ->fff_fallback
|
||||
| mov RB, BASE // Save BASE.
|
||||
|.if X64WIN
|
||||
| lea CARG3, [BASE+8]
|
||||
| mov CARG2, RA // Caveat: CARG2 == BASE.
|
||||
| mov CARG1, L:RB
|
||||
| lea CARG3, [BASE-16]
|
||||
| lea CARG2, [BASE+8] // Caveat: CARG2 == BASE.
|
||||
|.else
|
||||
| lea CARG3, [BASE+8] // Caveat: CARG3 == BASE.
|
||||
| mov CARG1, L:RB
|
||||
| lea CARG2, [BASE+8]
|
||||
| lea CARG3, [BASE-16] // Caveat: CARG3 == BASE.
|
||||
|.endif
|
||||
| mov SAVE_PC, PC // Needed for ITERN fallback.
|
||||
| call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
|
||||
| // Flag returned in eax (RD).
|
||||
| mov BASE, L:RB->base
|
||||
| test RDd, RDd; jz >3 // End of traversal?
|
||||
| // Copy key and value to results.
|
||||
| mov RB, [BASE+8]
|
||||
| mov RD, [BASE+16]
|
||||
| mov [BASE-16], RB
|
||||
| mov [BASE-8], RD
|
||||
|->fff_res2:
|
||||
| mov RDd, 1+2
|
||||
| jmp ->fff_res
|
||||
| call extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
|
||||
| // 1=found, 0=end, -1=error returned in eax (RD).
|
||||
| mov BASE, RB // Restore BASE.
|
||||
| test RDd, RDd; jg ->fff_res2 // Found key/value.
|
||||
| js ->fff_fallback_2 // Invalid key.
|
||||
| // End of traversal: return nil.
|
||||
| mov aword [BASE-16], LJ_TNIL
|
||||
| jmp ->fff_res1
|
||||
|2: // Set missing 2nd arg to nil.
|
||||
| mov aword [BASE+8], LJ_TNIL
|
||||
| jmp <1
|
||||
|3: // End of traversal: return nil.
|
||||
| mov aword [BASE-16], LJ_TNIL
|
||||
| jmp ->fff_res1
|
||||
|
|
||||
|.ffunc_1 pairs
|
||||
| mov TAB:RB, [BASE]
|
||||
@ -1432,7 +1416,9 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| // Copy array slot.
|
||||
| mov RB, [RD]
|
||||
| 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.
|
||||
| cmp dword TAB:RB->hmask, 0; je ->fff_res0
|
||||
|.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 byte CFUNC:RB->ffid, FF_next_N; jne >5
|
||||
| branchPC RD
|
||||
| mov64 TMPR, U64x(fffe7fff, 00000000)
|
||||
| mov64 TMPR, ((uint64_t)LJ_KEYINDEX << 32)
|
||||
| mov [BASE+RA*8-8], TMPR // Initialize control var.
|
||||
|1:
|
||||
| ins_next
|
||||
|
@ -1673,55 +1673,35 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| je >2 // Missing 2nd arg?
|
||||
|1:
|
||||
| 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 RB, BASE // Save BASE.
|
||||
|.if X64WIN
|
||||
| lea CARG3d, [BASE+8]
|
||||
| mov CARG2d, [BASE] // Caveat: CARG2d == BASE.
|
||||
| mov CARG1d, L:RB
|
||||
| mov CARG1d, [BASE]
|
||||
| lea CARG3d, [BASE-8]
|
||||
| lea CARG2d, [BASE+8] // Caveat: CARG2d == BASE.
|
||||
|.elif X64
|
||||
| mov CARG2d, [BASE]
|
||||
| lea CARG3d, [BASE+8] // Caveat: CARG3d == BASE.
|
||||
| mov CARG1d, L:RB
|
||||
| mov CARG1d, [BASE]
|
||||
| lea CARG2d, [BASE+8]
|
||||
| lea CARG3d, [BASE-8] // Caveat: CARG3d == BASE.
|
||||
|.else
|
||||
| mov TAB:RD, [BASE]
|
||||
| mov ARG2, TAB:RD
|
||||
| mov ARG1, L:RB
|
||||
| mov ARG1, TAB:RD
|
||||
| add BASE, 8
|
||||
| mov ARG2, BASE
|
||||
| sub BASE, 8+8
|
||||
| mov ARG3, BASE
|
||||
|.endif
|
||||
| mov SAVE_PC, PC // Needed for ITERN fallback.
|
||||
| call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
|
||||
| // Flag returned in eax (RD).
|
||||
| mov BASE, L:RB->base
|
||||
| test RD, RD; jz >3 // End of traversal?
|
||||
| // Copy key and value to results.
|
||||
|.if X64
|
||||
| mov RBa, [BASE+8]
|
||||
| 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
|
||||
| call extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
|
||||
| // 1=found, 0=end, -1=error returned in eax (RD).
|
||||
| mov BASE, RB // Restore BASE.
|
||||
| test RD, RD; jg ->fff_res2 // Found key/value.
|
||||
| js ->fff_fallback_2 // Invalid key.
|
||||
| // End of traversal: return nil.
|
||||
| mov dword [BASE-4], LJ_TNIL
|
||||
| jmp ->fff_res1
|
||||
|2: // Set missing 2nd arg to nil.
|
||||
| mov dword [BASE+12], LJ_TNIL
|
||||
| jmp <1
|
||||
|3: // End of traversal: return nil.
|
||||
| mov dword [BASE-4], LJ_TNIL
|
||||
| jmp ->fff_res1
|
||||
|
|
||||
|.ffunc_1 pairs
|
||||
| mov TAB:RB, [BASE]
|
||||
@ -1775,7 +1755,9 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| mov [BASE], RB
|
||||
| mov [BASE+4], RD
|
||||
|.endif
|
||||
| jmp ->fff_res2
|
||||
|->fff_res2:
|
||||
| mov RD, 1+2
|
||||
| jmp ->fff_res
|
||||
|2: // Check for empty hash part first. Otherwise call C function.
|
||||
| cmp dword TAB:RB->hmask, 0; je ->fff_res0
|
||||
| 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
|
||||
| branchPC RD
|
||||
| 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:
|
||||
| ins_next
|
||||
|5: // Despecialize bytecode if any of the checks fail.
|
||||
|
Loading…
Reference in New Issue
Block a user