From d15dd5d609acecf147dc31812ac8ac2dadccf78d Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Wed, 26 Aug 2026 10:04:25 +0200 Subject: [PATCH 1/2] PPC: Fix ipairs() on soft-float targets The soft-float branch of the ipairs_aux fast function loads the second word of the array slot from WORD_HI. On big-endian targets WORD_HI is 0, which is the itype the branch has already loaded into TMP2, so the value word at offset 4 is never read. Every element therefore comes back carrying the itype in its payload. Numbers surface as -14, the LJ_TNUMX tag read as an int32. For GC types the payload is the GCref, so the tag becomes a fabricated pointer that tostring() then dereferences. Restore the hardcoded 4(TMP1) that commit 2763a421 ("Patch for PPC64 support") rewrote as WORD_HI. The two words are stored straight back to 8(RA) and 12(RA), so a raw offset preserves the slot layout and is correct on either endianness. Upstream LuaJIT is unaffected. Reproducer on Turris 1.x (e500v2, 32-bit big-endian, soft-float): $ luajit -e 'local s=0 for i,v in ipairs({10,20,30}) do s=s+v end print(s)' -42 -- expected 60 Signed-off-by: Josef Schlehofer --- src/vm_ppc.dasc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm_ppc.dasc b/src/vm_ppc.dasc index 5f70bb188..53d247a2b 100644 --- a/src/vm_ppc.dasc +++ b/src/vm_ppc.dasc @@ -1833,7 +1833,7 @@ static void build_subroutines(BuildCtx *ctx) | lwz TMP2, WORD_HI(TMP1) |.else | lwzux TMP2, TMP1, TMP3 - | lwz TMP3, WORD_HI(TMP1) + | lwz TMP3, 4(TMP1) |.endif |1: | checknil TMP2 From 60c3d8d3375a5fd97858cf20d46cda10de51e4b1 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Wed, 26 Aug 2026 10:04:38 +0200 Subject: [PATCH 2/2] PPC: Fix pairs() over hash-less tables on soft-float targets BC_ITERN checks the itype of the node value in RB to skip empty slots in the hash part. Upstream loads RB unconditionally before the FPU split. Commit 2763a421 ("Patch for PPC64 support") moved that load into the FPU branch only. On soft-float builds, RB still contains RC*8 from the hash-part setup, so the nil check never succeeds and iterating a table whose hash part is empty yields one extra (nil, nil) pair. Load RB in the soft-float branch as well, mirroring the FPU branch. Taking it from WORD_HI keeps the check correct on either endianness and leaves checknil untouched. Reproducer on Turris 1.x (e500v2, 32-bit big-endian, soft-float): $ luajit -e 'for k,v in pairs({7,8,9}) do print(k,v) end' 1 7 2 8 3 9 nil nil -- spurious Signed-off-by: Josef Schlehofer --- src/vm_ppc.dasc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vm_ppc.dasc b/src/vm_ppc.dasc index 53d247a2b..5203388f7 100644 --- a/src/vm_ppc.dasc +++ b/src/vm_ppc.dasc @@ -5803,6 +5803,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | lwz RB, WORD_HI(TMP3) |.else | add CARG3, TMP2, TMP3 + | lwz RB, WORD_HI(CARG3) | lwz CARG1, 0(CARG3) | lwz CARG2, 4(CARG3) | add NODE:TMP3, TMP2, TMP3