aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2021-09-19 17:38:49 +0200
committerMike Pall <mike>2021-09-19 17:38:49 +0200
commitc6f5ef649b645db9cf3d11d1b5c63602c49c6411 (patch)
tree4d299528ff4e77c2f9059b8e24c50755ff638d2d
parent4e0ea654a81e68b1bcd20ddc2026ff1bc9288b84 (diff)
downloadluajit-c6f5ef649b645db9cf3d11d1b5c63602c49c6411.tar.gz
luajit-c6f5ef649b645db9cf3d11d1b5c63602c49c6411.tar.bz2
luajit-c6f5ef649b645db9cf3d11d1b5c63602c49c6411.zip
Refactor table traversal.
Sponsored by OpenResty Inc.
-rw-r--r--src/lib_base.c1
-rw-r--r--src/lj_api.c8
-rw-r--r--src/lj_obj.h3
-rw-r--r--src/lj_tab.c56
-rw-r--r--src/lj_tab.h3
-rw-r--r--src/vm_arm.dasc28
-rw-r--r--src/vm_arm64.dasc24
-rw-r--r--src/vm_mips.dasc38
-rw-r--r--src/vm_mips64.dasc36
-rw-r--r--src/vm_ppc.dasc49
-rw-r--r--src/vm_x64.dasc52
-rw-r--r--src/vm_x86.dasc62
12 files changed, 153 insertions, 207 deletions
diff --git a/src/lib_base.c b/src/lib_base.c
index 1c8816f0..f16c66f5 100644
--- a/src/lib_base.c
+++ b/src/lib_base.c
@@ -79,6 +79,7 @@ LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
79LJLIB_ASM(next) 79LJLIB_ASM(next)
80{ 80{
81 lj_lib_checktab(L, 1); 81 lj_lib_checktab(L, 1);
82 lj_err_msg(L, LJ_ERR_NEXTIDX);
82 return FFH_UNREACHABLE; 83 return FFH_UNREACHABLE;
83} 84}
84 85
diff --git a/src/lj_api.c b/src/lj_api.c
index 18a7ecbc..8c60c058 100644
--- a/src/lj_api.c
+++ b/src/lj_api.c
@@ -893,11 +893,13 @@ LUA_API int lua_next(lua_State *L, int idx)
893 cTValue *t = index2adr(L, idx); 893 cTValue *t = index2adr(L, idx);
894 int more; 894 int more;
895 lj_checkapi(tvistab(t), "stack slot %d is not a table", idx); 895 lj_checkapi(tvistab(t), "stack slot %d is not a table", idx);
896 more = lj_tab_next(L, tabV(t), L->top-1); 896 more = lj_tab_next(tabV(t), L->top-1, L->top-1);
897 if (more) { 897 if (more > 0) {
898 incr_top(L); /* Return new key and value slot. */ 898 incr_top(L); /* Return new key and value slot. */
899 } else { /* End of traversal. */ 899 } else if (!more) { /* End of traversal. */
900 L->top--; /* Remove key slot. */ 900 L->top--; /* Remove key slot. */
901 } else {
902 lj_err_msg(L, LJ_ERR_NEXTIDX);
901 } 903 }
902 return more; 904 return more;
903} 905}
diff --git a/src/lj_obj.h b/src/lj_obj.h
index 5547a79b..1a6445fc 100644
--- a/src/lj_obj.h
+++ b/src/lj_obj.h
@@ -284,6 +284,9 @@ typedef const TValue cTValue;
284#define LJ_TISGCV (LJ_TSTR+1) 284#define LJ_TISGCV (LJ_TSTR+1)
285#define LJ_TISTABUD LJ_TTAB 285#define LJ_TISTABUD LJ_TTAB
286 286
287/* Type marker for slot holding a traversal index. Must be lightuserdata. */
288#define LJ_KEYINDEX 0xfffe7fffu
289
287#if LJ_GC64 290#if LJ_GC64
288#define LJ_GCVMASK (((uint64_t)1 << 47) - 1) 291#define LJ_GCVMASK (((uint64_t)1 << 47) - 1)
289#endif 292#endif
diff --git a/src/lj_tab.c b/src/lj_tab.c
index ed5fd2dd..4113839f 100644
--- a/src/lj_tab.c
+++ b/src/lj_tab.c
@@ -568,56 +568,66 @@ TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key)
568 568
569/* -- Table traversal ----------------------------------------------------- */ 569/* -- Table traversal ----------------------------------------------------- */
570 570
571/* Get the traversal index of a key. */ 571/* Table traversal indexes:
572static uint32_t keyindex(lua_State *L, GCtab *t, cTValue *key) 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. */
579uint32_t LJ_FASTCALL lj_tab_keyindex(GCtab *t, cTValue *key)
573{ 580{
574 TValue tmp; 581 TValue tmp;
575 if (tvisint(key)) { 582 if (tvisint(key)) {
576 int32_t k = intV(key); 583 int32_t k = intV(key);
577 if ((uint32_t)k < t->asize) 584 if ((uint32_t)k < t->asize)
578 return (uint32_t)k; /* Array key indexes: [0..t->asize-1] */ 585 return (uint32_t)k + 1;
579 setnumV(&tmp, (lua_Number)k); 586 setnumV(&tmp, (lua_Number)k);
580 key = &tmp; 587 key = &tmp;
581 } else if (tvisnum(key)) { 588 } else if (tvisnum(key)) {
582 lua_Number nk = numV(key); 589 lua_Number nk = numV(key);
583 int32_t k = lj_num2int(nk); 590 int32_t k = lj_num2int(nk);
584 if ((uint32_t)k < t->asize && nk == (lua_Number)k) 591 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;
586 } 593 }
587 if (!tvisnil(key)) { 594 if (!tvisnil(key)) {
588 Node *n = hashkey(t, key); 595 Node *n = hashkey(t, key);
589 do { 596 do {
590 if (lj_obj_equal(&n->key, key)) 597 if (lj_obj_equal(&n->key, key))
591 return t->asize + (uint32_t)(n - noderef(t->node)); 598 return t->asize + (uint32_t)((n+1) - noderef(t->node));
592 /* Hash key indexes: [t->asize..t->asize+t->nmask] */
593 } while ((n = nextnode(n))); 599 } while ((n = nextnode(n)));
594 if (key->u32.hi == 0xfffe7fff) /* ITERN was despecialized while running. */ 600 if (key->u32.hi == LJ_KEYINDEX) /* Despecialized ITERN while running. */
595 return key->u32.lo - 1; 601 return key->u32.lo;
596 lj_err_msg(L, LJ_ERR_NEXTIDX); 602 return ~0u; /* Invalid key to next. */
597 return 0; /* unreachable */
598 } 603 }
599 return ~0u; /* A nil key starts the traversal. */ 604 return 0; /* A nil key starts the traversal. */
600} 605}
601 606
602/* Advance to the next step in a table traversal. */ 607/* Get the next key/value pair of a table traversal. */
603int lj_tab_next(lua_State *L, GCtab *t, TValue *key) 608int lj_tab_next(GCtab *t, cTValue *key, TValue *o)
604{ 609{
605 uint32_t i = keyindex(L, t, key); /* Find predecessor key index. */ 610 uint32_t idx = lj_tab_keyindex(t, key); /* Find successor index of key. */
606 for (i++; i < t->asize; i++) /* First traverse the array keys. */ 611 /* First traverse the array part. */
607 if (!tvisnil(arrayslot(t, i))) { 612 for (; idx < t->asize; idx++) {
608 setintV(key, i); 613 cTValue *a = arrayslot(t, idx);
609 copyTV(L, key+1, arrayslot(t, i)); 614 if (LJ_LIKELY(!tvisnil(a))) {
615 setintV(o, idx);
616 o[1] = *a;
610 return 1; 617 return 1;
611 } 618 }
612 for (i -= t->asize; i <= t->hmask; i++) { /* Then traverse the hash keys. */ 619 }
613 Node *n = &noderef(t->node)[i]; 620 idx -= t->asize;
621 /* Then traverse the hash part. */
622 for (; idx <= t->hmask; idx++) {
623 Node *n = &noderef(t->node)[idx];
614 if (!tvisnil(&n->val)) { 624 if (!tvisnil(&n->val)) {
615 copyTV(L, key, &n->key); 625 o[0] = n->key;
616 copyTV(L, key+1, &n->val); 626 o[1] = n->val;
617 return 1; 627 return 1;
618 } 628 }
619 } 629 }
620 return 0; /* End of traversal. */ 630 return (int32_t)idx < 0 ? -1 : 0; /* Invalid key or end of traversal. */
621} 631}
622 632
623/* -- Table length calculation -------------------------------------------- */ 633/* -- Table length calculation -------------------------------------------- */
diff --git a/src/lj_tab.h b/src/lj_tab.h
index 1efa9506..e0e81ff7 100644
--- a/src/lj_tab.h
+++ b/src/lj_tab.h
@@ -86,7 +86,8 @@ LJ_FUNC TValue *lj_tab_set(lua_State *L, GCtab *t, cTValue *key);
86#define lj_tab_setint(L, t, key) \ 86#define lj_tab_setint(L, t, key) \
87 (inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_setinth(L, (t), (key))) 87 (inarray((t), (key)) ? arrayslot((t), (key)) : lj_tab_setinth(L, (t), (key)))
88 88
89LJ_FUNCA int lj_tab_next(lua_State *L, GCtab *t, TValue *key); 89LJ_FUNC uint32_t LJ_FASTCALL lj_tab_keyindex(GCtab *t, cTValue *key);
90LJ_FUNCA int lj_tab_next(GCtab *t, cTValue *key, TValue *o);
90LJ_FUNCA MSize LJ_FASTCALL lj_tab_len(GCtab *t); 91LJ_FUNCA MSize LJ_FASTCALL lj_tab_len(GCtab *t);
91#if LJ_HASJIT 92#if LJ_HASJIT
92LJ_FUNC MSize LJ_FASTCALL lj_tab_len_hint(GCtab *t, size_t hint); 93LJ_FUNC MSize LJ_FASTCALL lj_tab_len_hint(GCtab *t, size_t hint);
diff --git a/src/vm_arm.dasc b/src/vm_arm.dasc
index 35ba0e36..0e80bf00 100644
--- a/src/vm_arm.dasc
+++ b/src/vm_arm.dasc
@@ -1111,24 +1111,18 @@ static void build_subroutines(BuildCtx *ctx)
1111 | checktab CARG2, ->fff_fallback 1111 | checktab CARG2, ->fff_fallback
1112 | strd CARG34, [BASE, NARGS8:RC] // Set missing 2nd arg to nil. 1112 | strd CARG34, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
1113 | ldr PC, [BASE, FRAME_PC] 1113 | ldr PC, [BASE, FRAME_PC]
1114 | mov CARG2, CARG1 1114 | add CARG2, BASE, #8
1115 | str BASE, L->base // Add frame since C call can throw. 1115 | sub CARG3, BASE, #8
1116 | mov CARG1, L 1116 | bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1117 | str BASE, L->top // Dummy frame length is ok. 1117 | // Returns 1=found, 0=end, -1=error.
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.
1122 | .IOS ldr BASE, L->base 1118 | .IOS ldr BASE, L->base
1123 | cmp CRET1, #0 1119 | cmp CRET1, #0
1124 | mvneq CRET2, #~LJ_TNIL 1120 | mov RC, #(2+1)*8
1125 | beq ->fff_restv // End of traversal: return nil. 1121 | bgt ->fff_res // Found key/value.
1126 | ldrd CARG12, [BASE, #8] // Copy key and value to results. 1122 | bmi ->fff_fallback // Invalid key.
1127 | ldrd CARG34, [BASE, #16] 1123 | // End of traversal: return nil.
1128 | mov RC, #(2+1)*8 1124 | mvn CRET2, #~LJ_TNIL
1129 | strd CARG12, [BASE, #-8] 1125 | b ->fff_restv
1130 | strd CARG34, [BASE]
1131 | b ->fff_res
1132 | 1126 |
1133 |.ffunc_1 pairs 1127 |.ffunc_1 pairs
1134 | checktab CARG2, ->fff_fallback 1128 | checktab CARG2, ->fff_fallback
@@ -3989,7 +3983,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
3989 | ins_next1 3983 | ins_next1
3990 | ins_next2 3984 | ins_next2
3991 | mov CARG1, #0 3985 | mov CARG1, #0
3992 | mvn CARG2, #0x00018000 3986 | mvn CARG2, #~LJ_KEYINDEX
3993 | strd CARG1, [RA, #-8] // Initialize control var. 3987 | strd CARG1, [RA, #-8] // Initialize control var.
3994 |1: 3988 |1:
3995 | ins_next3 3989 | ins_next3
diff --git a/src/vm_arm64.dasc b/src/vm_arm64.dasc
index 92f89cd6..2a2e3a9a 100644
--- a/src/vm_arm64.dasc
+++ b/src/vm_arm64.dasc
@@ -1086,21 +1086,19 @@ static void build_subroutines(BuildCtx *ctx)
1086 |//-- Base library: iterators ------------------------------------------- 1086 |//-- Base library: iterators -------------------------------------------
1087 | 1087 |
1088 |.ffunc_1 next 1088 |.ffunc_1 next
1089 | checktp CARG2, CARG1, LJ_TTAB, ->fff_fallback 1089 | checktp CARG1, LJ_TTAB, ->fff_fallback
1090 | str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil. 1090 | str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
1091 | ldr PC, [BASE, FRAME_PC] 1091 | ldr PC, [BASE, FRAME_PC]
1092 | stp BASE, BASE, L->base // Add frame since C call can throw. 1092 | add CARG2, BASE, #8
1093 | mov CARG1, L 1093 | sub CARG3, BASE, #16
1094 | add CARG3, BASE, #8 1094 | bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1095 | str PC, SAVE_PC 1095 | // Returns 1=found, 0=end, -1=error.
1096 | bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) 1096 | mov RC, #(2+1)*8
1097 | // Returns 0 at end of traversal. 1097 | tbnz CRET1w, #31, ->fff_fallback // Invalid key.
1098 | cbnz CRET1, ->fff_res // Found key/value.
1099 | // End of traversal: return nil.
1098 | str TISNIL, [BASE, #-16] 1100 | str TISNIL, [BASE, #-16]
1099 | cbz CRET1, ->fff_res1 // End of traversal: return nil. 1101 | b ->fff_res1
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
1104 | 1102 |
1105 |.ffunc_1 pairs 1103 |.ffunc_1 pairs
1106 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback 1104 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
@@ -3384,7 +3382,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
3384 | ccmp CARG4, TISNIL, #0, eq 3382 | ccmp CARG4, TISNIL, #0, eq
3385 | ccmp TMP1w, #FF_next_N, #0, eq 3383 | ccmp TMP1w, #FF_next_N, #0, eq
3386 | bne >5 3384 | bne >5
3387 | mov TMP0w, #0xfffe7fff 3385 | mov TMP0w, #0xfffe7fff // LJ_KEYINDEX
3388 | lsl TMP0, TMP0, #32 3386 | lsl TMP0, TMP0, #32
3389 | str TMP0, [RA, #-8] // Initialize control var. 3387 | str TMP0, [RA, #-8] // Initialize control var.
3390 |1: 3388 |1:
diff --git a/src/vm_mips.dasc b/src/vm_mips.dasc
index 7bd86514..3b0ea4a2 100644
--- a/src/vm_mips.dasc
+++ b/src/vm_mips.dasc
@@ -1262,35 +1262,27 @@ static void build_subroutines(BuildCtx *ctx)
1262 |//-- Base library: iterators ------------------------------------------- 1262 |//-- Base library: iterators -------------------------------------------
1263 | 1263 |
1264 |.ffunc next 1264 |.ffunc next
1265 | lw CARG1, HI(BASE) 1265 | lw CARG2, HI(BASE)
1266 | lw TAB:CARG2, LO(BASE) 1266 | lw TAB:CARG1, LO(BASE)
1267 | beqz NARGS8:RC, ->fff_fallback 1267 | beqz NARGS8:RC, ->fff_fallback
1268 |. addu TMP2, BASE, NARGS8:RC 1268 |. addu TMP2, BASE, NARGS8:RC
1269 | li AT, LJ_TTAB 1269 | li AT, LJ_TTAB
1270 | sw TISNIL, HI(TMP2) // Set missing 2nd arg to nil. 1270 | sw TISNIL, HI(TMP2) // Set missing 2nd arg to nil.
1271 | bne CARG1, AT, ->fff_fallback 1271 | bne CARG2, AT, ->fff_fallback
1272 |. lw PC, FRAME_PC(BASE) 1272 |. lw PC, FRAME_PC(BASE)
1273 | load_got lj_tab_next 1273 | load_got lj_tab_next
1274 | sw BASE, L->base // Add frame since C call can throw. 1274 | addiu CARG2, BASE, 8
1275 | sw BASE, L->top // Dummy frame length is ok. 1275 | call_intern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1276 | addiu CARG3, BASE, 8 1276 |. addiu CARG3, BASE, -8
1277 | sw PC, SAVE_PC 1277 | // Returns 1=found, 0=end, -1=error.
1278 | call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) 1278 | addiu RA, BASE, -8
1279 |. move CARG1, L 1279 | bgtz CRET1, ->fff_res // Found key/value.
1280 | // Returns 0 at end of traversal. 1280 |. li RD, (2+1)*8
1281 | beqz CRET1, ->fff_restv // End of traversal: return nil. 1281 | beqz CRET1, ->fff_restv // End of traversal: return nil.
1282 |. li SFARG1HI, LJ_TNIL 1282 |. li SFARG1HI, LJ_TNIL
1283 | lw TMP0, 8+HI(BASE) 1283 | lw CFUNC:RB, FRAME_FUNC(BASE)
1284 | lw TMP1, 8+LO(BASE) 1284 | b ->fff_fallback // Invalid key.
1285 | addiu RA, BASE, -8 1285 |. li RC, 2*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
1294 | 1286 |
1295 |.ffunc_1 pairs 1287 |.ffunc_1 pairs
1296 | li AT, LJ_TTAB 1288 | li AT, LJ_TTAB
@@ -4611,9 +4603,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
4611 | addiu CARG2, CARG2, -FF_next_N 4603 | addiu CARG2, CARG2, -FF_next_N
4612 | or CARG2, CARG2, CARG3 4604 | or CARG2, CARG2, CARG3
4613 | bnez CARG2, >5 4605 | bnez CARG2, >5
4614 |. lui TMP1, 0xfffe 4606 |. lui TMP1, (LJ_KEYINDEX >> 16)
4615 | addu PC, TMP0, TMP2 4607 | addu PC, TMP0, TMP2
4616 | ori TMP1, TMP1, 0x7fff 4608 | ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
4617 | sw r0, -8+LO(RA) // Initialize control var. 4609 | sw r0, -8+LO(RA) // Initialize control var.
4618 | sw TMP1, -8+HI(RA) 4610 | sw TMP1, -8+HI(RA)
4619 |1: 4611 |1:
diff --git a/src/vm_mips64.dasc b/src/vm_mips64.dasc
index 05395ffd..0d28326a 100644
--- a/src/vm_mips64.dasc
+++ b/src/vm_mips64.dasc
@@ -1322,27 +1322,24 @@ static void build_subroutines(BuildCtx *ctx)
1322 |//-- Base library: iterators ------------------------------------------- 1322 |//-- Base library: iterators -------------------------------------------
1323 | 1323 |
1324 |.ffunc_1 next 1324 |.ffunc_1 next
1325 | checktp CARG2, CARG1, -LJ_TTAB, ->fff_fallback 1325 | checktp CARG1, -LJ_TTAB, ->fff_fallback
1326 | daddu TMP2, BASE, NARGS8:RC 1326 | daddu TMP2, BASE, NARGS8:RC
1327 | sd TISNIL, 0(TMP2) // Set missing 2nd arg to nil. 1327 | sd TISNIL, 0(TMP2) // Set missing 2nd arg to nil.
1328 | ld PC, FRAME_PC(BASE)
1329 | load_got lj_tab_next 1328 | load_got lj_tab_next
1330 | sd BASE, L->base // Add frame since C call can throw. 1329 | ld PC, FRAME_PC(BASE)
1331 | sd BASE, L->top // Dummy frame length is ok. 1330 | daddiu CARG2, BASE, 8
1332 | daddiu CARG3, BASE, 8 1331 | call_intern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1333 | sd PC, SAVE_PC 1332 |. daddiu CARG3, BASE, -16
1334 | call_intern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) 1333 | // Returns 1=found, 0=end, -1=error.
1335 |. move CARG1, L 1334 | daddiu RA, BASE, -16
1336 | // Returns 0 at end of traversal. 1335 | bgtz CRET1, ->fff_res // Found key/value.
1336 |. li RD, (2+1)*8
1337 | beqz CRET1, ->fff_restv // End of traversal: return nil. 1337 | beqz CRET1, ->fff_restv // End of traversal: return nil.
1338 |. move CARG1, TISNIL 1338 |. move CARG1, TISNIL
1339 | ld TMP0, 8(BASE) 1339 | ld CFUNC:RB, FRAME_FUNC(BASE)
1340 | daddiu RA, BASE, -16 1340 | cleartp CFUNC:RB
1341 | ld TMP2, 16(BASE) 1341 | b ->fff_fallback // Invalid key.
1342 | sd TMP0, 0(RA) 1342 |. li RC, 2*8
1343 | sd TMP2, 8(RA)
1344 | b ->fff_res
1345 |. li RD, (2+1)*8
1346 | 1343 |
1347 |.ffunc_1 pairs 1344 |.ffunc_1 pairs
1348 | checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback 1345 | checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback
@@ -4727,11 +4724,10 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
4727 |. addiu RC, RC, 1 4724 |. addiu RC, RC, 1
4728 | sd TMP2, 0(RA) 4725 | sd TMP2, 0(RA)
4729 | sd CARG1, 8(RA) 4726 | sd CARG1, 8(RA)
4730 | or TMP0, RC, CARG3
4731 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535) 4727 | lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
4732 | decode_RD4b RD 4728 | decode_RD4b RD
4733 | daddu RD, RD, TMP3 4729 | daddu RD, RD, TMP3
4734 | sw TMP0, -8+LO(RA) // Update control var. 4730 | sw RC, -8+LO(RA) // Update control var.
4735 | daddu PC, PC, RD 4731 | daddu PC, PC, RD
4736 |3: 4732 |3:
4737 | ins_next 4733 | ins_next
@@ -4781,9 +4777,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
4781 | daddiu TMP1, TMP1, -FF_next_N 4777 | daddiu TMP1, TMP1, -FF_next_N
4782 | or AT, AT, TMP1 4778 | or AT, AT, TMP1
4783 | bnez AT, >5 4779 | bnez AT, >5
4784 |. lui TMP1, 0xfffe 4780 |. lui TMP1, (LJ_KEYINDEX >> 16)
4785 | daddu PC, TMP0, TMP2 4781 | daddu PC, TMP0, TMP2
4786 | ori TMP1, TMP1, 0x7fff 4782 | ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
4787 | dsll TMP1, TMP1, 32 4783 | dsll TMP1, TMP1, 32
4788 | sd TMP1, -8(RA) 4784 | sd TMP1, -8(RA)
4789 |1: 4785 |1:
diff --git a/src/vm_ppc.dasc b/src/vm_ppc.dasc
index 6aa00c5b..d4133a65 100644
--- a/src/vm_ppc.dasc
+++ b/src/vm_ppc.dasc
@@ -1559,43 +1559,24 @@ static void build_subroutines(BuildCtx *ctx)
1559 | 1559 |
1560 |//-- Base library: iterators ------------------------------------------- 1560 |//-- Base library: iterators -------------------------------------------
1561 | 1561 |
1562 |.ffunc next 1562 |.ffunc_1 next
1563 | cmplwi NARGS8:RC, 8
1564 | lwz CARG1, 0(BASE)
1565 | lwz TAB:CARG2, 4(BASE)
1566 | blt ->fff_fallback
1567 | stwx TISNIL, BASE, NARGS8:RC // Set missing 2nd arg to nil. 1563 | stwx TISNIL, BASE, NARGS8:RC // Set missing 2nd arg to nil.
1568 | checktab CARG1 1564 | checktab CARG3
1569 | lwz PC, FRAME_PC(BASE) 1565 | lwz PC, FRAME_PC(BASE)
1570 | bne ->fff_fallback 1566 | bne ->fff_fallback
1571 | stp BASE, L->base // Add frame since C call can throw. 1567 | la CARG2, 8(BASE)
1572 | mr CARG1, L 1568 | la CARG3, -8(BASE)
1573 | stp BASE, L->top // Dummy frame length is ok. 1569 | bl extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1574 | la CARG3, 8(BASE) 1570 | // Returns 1=found, 0=end, -1=error.
1575 | stw PC, SAVE_PC 1571 | cmpwi CRET1, 0
1576 | bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
1577 | // Returns 0 at end of traversal.
1578 | cmplwi CRET1, 0
1579 | li CARG3, LJ_TNIL
1580 | beq ->fff_restv // End of traversal: return nil.
1581 | la RA, -8(BASE) 1572 | la RA, -8(BASE)
1582 |.if FPU
1583 | lfd f0, 8(BASE) // Copy key and value to results.
1584 | lfd f1, 16(BASE)
1585 | stfd f0, 0(RA)
1586 | stfd f1, 8(RA)
1587 |.else
1588 | lwz CARG1, 8(BASE)
1589 | lwz CARG2, 12(BASE)
1590 | lwz CARG3, 16(BASE)
1591 | lwz CARG4, 20(BASE)
1592 | stw CARG1, 0(RA)
1593 | stw CARG2, 4(RA)
1594 | stw CARG3, 8(RA)
1595 | stw CARG4, 12(RA)
1596 |.endif
1597 | li RD, (2+1)*8 1573 | li RD, (2+1)*8
1598 | b ->fff_res 1574 | bgt ->fff_res // Found key/value.
1575 | li CARG3, LJ_TNIL
1576 | beq ->fff_restv // End of traversal: return nil.
1577 | lwz CFUNC:RB, FRAME_FUNC(BASE)
1578 | li NARGS8:RC, 2*8
1579 | b ->fff_fallback // Invalid key.
1599 | 1580 |
1600 |.ffunc_1 pairs 1581 |.ffunc_1 pairs
1601 | checktab CARG3 1582 | checktab CARG3
@@ -5251,8 +5232,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
5251 | crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq 5232 | crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
5252 | add TMP3, PC, TMP0 5233 | add TMP3, PC, TMP0
5253 | bne cr0, >5 5234 | bne cr0, >5
5254 | lus TMP1, 0xfffe 5235 | lus TMP1, (LJ_KEYINDEX >> 16)
5255 | ori TMP1, TMP1, 0x7fff 5236 | ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
5256 | stw ZERO, -4(RA) // Initialize control var. 5237 | stw ZERO, -4(RA) // Initialize control var.
5257 | stw TMP1, -8(RA) 5238 | stw TMP1, -8(RA)
5258 | addis PC, TMP3, -(BCBIAS_J*4 >> 16) 5239 | addis PC, TMP3, -(BCBIAS_J*4 >> 16)
diff --git a/src/vm_x64.dasc b/src/vm_x64.dasc
index 76ce071d..d2119bc4 100644
--- a/src/vm_x64.dasc
+++ b/src/vm_x64.dasc
@@ -1346,44 +1346,28 @@ static void build_subroutines(BuildCtx *ctx)
1346 |.ffunc_1 next 1346 |.ffunc_1 next
1347 | je >2 // Missing 2nd arg? 1347 | je >2 // Missing 2nd arg?
1348 |1: 1348 |1:
1349 |.if X64WIN 1349 | mov CARG1, [BASE]
1350 | mov RA, [BASE]
1351 | checktab RA, ->fff_fallback
1352 |.else
1353 | mov CARG2, [BASE]
1354 | checktab CARG2, ->fff_fallback
1355 |.endif
1356 | mov L:RB, SAVE_L
1357 | mov L:RB->base, BASE // Add frame since C call can throw.
1358 | mov L:RB->top, BASE // Dummy frame length is ok.
1359 | mov PC, [BASE-8] 1350 | mov PC, [BASE-8]
1351 | checktab CARG1, ->fff_fallback
1352 | mov RB, BASE // Save BASE.
1360 |.if X64WIN 1353 |.if X64WIN
1361 | lea CARG3, [BASE+8] 1354 | lea CARG3, [BASE-16]
1362 | mov CARG2, RA // Caveat: CARG2 == BASE. 1355 | lea CARG2, [BASE+8] // Caveat: CARG2 == BASE.
1363 | mov CARG1, L:RB
1364 |.else 1356 |.else
1365 | lea CARG3, [BASE+8] // Caveat: CARG3 == BASE. 1357 | lea CARG2, [BASE+8]
1366 | mov CARG1, L:RB 1358 | lea CARG3, [BASE-16] // Caveat: CARG3 == BASE.
1367 |.endif 1359 |.endif
1368 | mov SAVE_PC, PC // Needed for ITERN fallback. 1360 | call extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1369 | call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) 1361 | // 1=found, 0=end, -1=error returned in eax (RD).
1370 | // Flag returned in eax (RD). 1362 | mov BASE, RB // Restore BASE.
1371 | mov BASE, L:RB->base 1363 | test RDd, RDd; jg ->fff_res2 // Found key/value.
1372 | test RDd, RDd; jz >3 // End of traversal? 1364 | js ->fff_fallback_2 // Invalid key.
1373 | // Copy key and value to results. 1365 | // End of traversal: return nil.
1374 | mov RB, [BASE+8] 1366 | mov aword [BASE-16], LJ_TNIL
1375 | mov RD, [BASE+16] 1367 | jmp ->fff_res1
1376 | mov [BASE-16], RB
1377 | mov [BASE-8], RD
1378 |->fff_res2:
1379 | mov RDd, 1+2
1380 | jmp ->fff_res
1381 |2: // Set missing 2nd arg to nil. 1368 |2: // Set missing 2nd arg to nil.
1382 | mov aword [BASE+8], LJ_TNIL 1369 | mov aword [BASE+8], LJ_TNIL
1383 | jmp <1 1370 | jmp <1
1384 |3: // End of traversal: return nil.
1385 | mov aword [BASE-16], LJ_TNIL
1386 | jmp ->fff_res1
1387 | 1371 |
1388 |.ffunc_1 pairs 1372 |.ffunc_1 pairs
1389 | mov TAB:RB, [BASE] 1373 | mov TAB:RB, [BASE]
@@ -1432,7 +1416,9 @@ static void build_subroutines(BuildCtx *ctx)
1432 | // Copy array slot. 1416 | // Copy array slot.
1433 | mov RB, [RD] 1417 | mov RB, [RD]
1434 | mov [BASE-8], RB 1418 | mov [BASE-8], RB
1435 | jmp ->fff_res2 1419 |->fff_res2:
1420 | mov RDd, 1+2
1421 | jmp ->fff_res
1436 |2: // Check for empty hash part first. Otherwise call C function. 1422 |2: // Check for empty hash part first. Otherwise call C function.
1437 | cmp dword TAB:RB->hmask, 0; je ->fff_res0 1423 | cmp dword TAB:RB->hmask, 0; je ->fff_res0
1438 |.if X64WIN 1424 |.if X64WIN
@@ -4125,7 +4111,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
4125 | cmp aword [BASE+RA*8-8], LJ_TNIL; jne >5 4111 | cmp aword [BASE+RA*8-8], LJ_TNIL; jne >5
4126 | cmp byte CFUNC:RB->ffid, FF_next_N; jne >5 4112 | cmp byte CFUNC:RB->ffid, FF_next_N; jne >5
4127 | branchPC RD 4113 | branchPC RD
4128 | mov64 TMPR, U64x(fffe7fff, 00000000) 4114 | mov64 TMPR, ((uint64_t)LJ_KEYINDEX << 32)
4129 | mov [BASE+RA*8-8], TMPR // Initialize control var. 4115 | mov [BASE+RA*8-8], TMPR // Initialize control var.
4130 |1: 4116 |1:
4131 | ins_next 4117 | ins_next
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc
index 81b899fa..718cb8f0 100644
--- a/src/vm_x86.dasc
+++ b/src/vm_x86.dasc
@@ -1673,55 +1673,35 @@ static void build_subroutines(BuildCtx *ctx)
1673 | je >2 // Missing 2nd arg? 1673 | je >2 // Missing 2nd arg?
1674 |1: 1674 |1:
1675 | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback 1675 | cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
1676 | mov L:RB, SAVE_L
1677 | mov L:RB->base, BASE // Add frame since C call can throw.
1678 | mov L:RB->top, BASE // Dummy frame length is ok.
1679 | mov PC, [BASE-4] 1676 | mov PC, [BASE-4]
1677 | mov RB, BASE // Save BASE.
1680 |.if X64WIN 1678 |.if X64WIN
1681 | lea CARG3d, [BASE+8] 1679 | mov CARG1d, [BASE]
1682 | mov CARG2d, [BASE] // Caveat: CARG2d == BASE. 1680 | lea CARG3d, [BASE-8]
1683 | mov CARG1d, L:RB 1681 | lea CARG2d, [BASE+8] // Caveat: CARG2d == BASE.
1684 |.elif X64 1682 |.elif X64
1685 | mov CARG2d, [BASE] 1683 | mov CARG1d, [BASE]
1686 | lea CARG3d, [BASE+8] // Caveat: CARG3d == BASE. 1684 | lea CARG2d, [BASE+8]
1687 | mov CARG1d, L:RB 1685 | lea CARG3d, [BASE-8] // Caveat: CARG3d == BASE.
1688 |.else 1686 |.else
1689 | mov TAB:RD, [BASE] 1687 | mov TAB:RD, [BASE]
1690 | mov ARG2, TAB:RD 1688 | mov ARG1, TAB:RD
1691 | mov ARG1, L:RB
1692 | add BASE, 8 1689 | add BASE, 8
1690 | mov ARG2, BASE
1691 | sub BASE, 8+8
1693 | mov ARG3, BASE 1692 | mov ARG3, BASE
1694 |.endif 1693 |.endif
1695 | mov SAVE_PC, PC // Needed for ITERN fallback. 1694 | call extern lj_tab_next // (GCtab *t, cTValue *key, TValue *o)
1696 | call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key) 1695 | // 1=found, 0=end, -1=error returned in eax (RD).
1697 | // Flag returned in eax (RD). 1696 | mov BASE, RB // Restore BASE.
1698 | mov BASE, L:RB->base 1697 | test RD, RD; jg ->fff_res2 // Found key/value.
1699 | test RD, RD; jz >3 // End of traversal? 1698 | js ->fff_fallback_2 // Invalid key.
1700 | // Copy key and value to results. 1699 | // End of traversal: return nil.
1701 |.if X64 1700 | mov dword [BASE-4], LJ_TNIL
1702 | mov RBa, [BASE+8] 1701 | jmp ->fff_res1
1703 | mov RDa, [BASE+16]
1704 | mov [BASE-8], RBa
1705 | mov [BASE], RDa
1706 |.else
1707 | mov RB, [BASE+8]
1708 | mov RD, [BASE+12]
1709 | mov [BASE-8], RB
1710 | mov [BASE-4], RD
1711 | mov RB, [BASE+16]
1712 | mov RD, [BASE+20]
1713 | mov [BASE], RB
1714 | mov [BASE+4], RD
1715 |.endif
1716 |->fff_res2:
1717 | mov RD, 1+2
1718 | jmp ->fff_res
1719 |2: // Set missing 2nd arg to nil. 1702 |2: // Set missing 2nd arg to nil.
1720 | mov dword [BASE+12], LJ_TNIL 1703 | mov dword [BASE+12], LJ_TNIL
1721 | jmp <1 1704 | jmp <1
1722 |3: // End of traversal: return nil.
1723 | mov dword [BASE-4], LJ_TNIL
1724 | jmp ->fff_res1
1725 | 1705 |
1726 |.ffunc_1 pairs 1706 |.ffunc_1 pairs
1727 | mov TAB:RB, [BASE] 1707 | mov TAB:RB, [BASE]
@@ -1775,7 +1755,9 @@ static void build_subroutines(BuildCtx *ctx)
1775 | mov [BASE], RB 1755 | mov [BASE], RB
1776 | mov [BASE+4], RD 1756 | mov [BASE+4], RD
1777 |.endif 1757 |.endif
1778 | jmp ->fff_res2 1758 |->fff_res2:
1759 | mov RD, 1+2
1760 | jmp ->fff_res
1779 |2: // Check for empty hash part first. Otherwise call C function. 1761 |2: // Check for empty hash part first. Otherwise call C function.
1780 | cmp dword TAB:RB->hmask, 0; je ->fff_res0 1762 | cmp dword TAB:RB->hmask, 0; je ->fff_res0
1781 | mov FCARG1, TAB:RB 1763 | mov FCARG1, TAB:RB
@@ -4880,7 +4862,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
4880 | cmp byte CFUNC:RB->ffid, FF_next_N; jne >5 4862 | cmp byte CFUNC:RB->ffid, FF_next_N; jne >5
4881 | branchPC RD 4863 | branchPC RD
4882 | mov dword [BASE+RA*8-8], 0 // Initialize control var. 4864 | mov dword [BASE+RA*8-8], 0 // Initialize control var.
4883 | mov dword [BASE+RA*8-4], 0xfffe7fff 4865 | mov dword [BASE+RA*8-4], LJ_KEYINDEX
4884 |1: 4866 |1:
4885 | ins_next 4867 | ins_next
4886 |5: // Despecialize bytecode if any of the checks fail. 4868 |5: // Despecialize bytecode if any of the checks fail.