[Tarantool-patches] [PATCH luajit 1/2] Fix register mask for stack check in head of side trace.
Sergey Kaplun
skaplun at tarantool.org
Wed Oct 11 18:04:09 MSK 2023
From: Mike Pall <mike>
Analyzed by Sergey Kaplun.
(cherry-picked from commit b7a8c7c184257858699454408420dd5f0b6c8a75)
Assume we have parent and child traces with the following IRs from the
IR dump:
Parent:
| 0009 rax > tab TNEW 0 0
| 0010 p32 FLOAD 0008 tab.node
| 0011 p32 HREFK 0010 "Name" @1
| 0012 {0008} tab HSTORE 0011 0009
| .... SNAP 2 [ ---- 0001 0002 0008 ---- ]
| 0013 {sink} tab TNEW 0 0
| 0014 {0008} fal HSTORE 0011 false
| .... SNAP 3 [ ---- 0001 0002 0008 ---- ]
Child:
| 0001 r15 tab SLOAD 1 PI
| 0002 rbp tab SLOAD 2 PI
| 0003 tab PVAL 9
As we can see from the trace dump above, the `rax` register is missing
in the `0003 PVAL` IR for the side trace -- so it is assumed to be
available in the allow RegSet inside `asm_stack_check()` and its value
is spoiled during this check, so if we are restoring from the 3rd
snapshot by stack overflow -- we are in trouble.
The moment when IR is spoiled is when we set a hint on the register
inherited from the parent trace (see `asm_setup_regsp()` for details).
The 0th register (`rax`) shapeshifts into `RID_NONE`. Hence, when
collecting register dependencies from the parent trace, `0003 PVAL` is
considered the IR with `RID_NONE`, i.e., without an assigned register.
So, this register is considered free (picked as bottom from the free
set) in the `asm_stack_check()` and is used for stack overflow check, so
the table reference is gone.
This patch introduces another register set for the context of the parent
trace to use in the stack check. All registers used on the child trace
are excluded from this set.
The test case for this patch is omitted since it requires specific
register allocation, which is hard to construct and not stable in any
future patches.
Part of tarantool/tarantool#9145
Sergey Kaplun:
* added the description for the problem
---
src/lj_asm.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/lj_asm.c b/src/lj_asm.c
index 3a1909d5..ca06860a 100644
--- a/src/lj_asm.c
+++ b/src/lj_asm.c
@@ -1859,6 +1859,7 @@ static void asm_head_side(ASMState *as)
IRRef1 sloadins[RID_MAX];
RegSet allow = RSET_ALL; /* Inverse of all coalesced registers. */
RegSet live = RSET_EMPTY; /* Live parent registers. */
+ RegSet pallow = RSET_GPR; /* Registers needed by the parent stack check. */
IRIns *irp = &as->parent->ir[REF_BASE]; /* Parent base. */
int32_t spadj, spdelta;
int pass2 = 0;
@@ -1899,6 +1900,7 @@ static void asm_head_side(ASMState *as)
sloadins[rs] = (IRRef1)i;
rset_set(live, rs); /* Block live parent register. */
}
+ if (!ra_hasspill(regsp_spill(rs))) rset_clear(pallow, regsp_reg(rs));
}
/* Calculate stack frame adjustment. */
@@ -2015,7 +2017,7 @@ static void asm_head_side(ASMState *as)
ExitNo exitno = as->J->exitno;
#endif
as->T->topslot = (uint8_t)as->topslot; /* Remember for child traces. */
- asm_stack_check(as, as->topslot, irp, allow & RSET_GPR, exitno);
+ asm_stack_check(as, as->topslot, irp, pallow, exitno);
}
}
--
2.42.0
More information about the Tarantool-patches
mailing list