Ensure forward progress on trace exit to BC_ITERN.

Also use a safer way to force a static dispatch for BC_RET*.
Reported by Bartel Eerdekens. Analyzed by Peter Cawley. #1000 #1045
This commit is contained in:
Mike Pall
2023-08-13 02:25:12 +02:00
parent 27af72e66f
commit 119fd1fab0
8 changed files with 146 additions and 35 deletions

View File

@@ -431,6 +431,12 @@ static void trace_start(jit_State *J)
return;
}
/* Ensuring forward progress for BC_ITERN can trigger hotcount again. */
if (!J->parent && bc_op(*J->pc) == BC_JLOOP) { /* Already compiled. */
J->state = LJ_TRACE_IDLE; /* Silently ignored. */
return;
}
/* Get a new trace number. */
traceno = trace_findfree(J);
if (LJ_UNLIKELY(traceno == 0)) { /* No free trace? */
@@ -867,7 +873,7 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
ExitDataCP exd;
int errcode, exitcode = J->exitcode;
TValue exiterr;
const BCIns *pc;
const BCIns *pc, *retpc;
void *cf;
GCtrace *T;
@@ -919,22 +925,7 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
} else {
trace_hotside(J, pc);
}
if (bc_op(*pc) == BC_JLOOP) {
BCIns *retpc = &traceref(J, bc_d(*pc))->startins;
int isret = bc_isret(bc_op(*retpc));
if (isret || bc_op(*retpc) == BC_ITERN) {
if (J->state == LJ_TRACE_RECORD) {
J->patchins = *pc;
J->patchpc = (BCIns *)pc;
*J->patchpc = *retpc;
J->bcskip = 1;
} else if (isret) {
pc = retpc;
setcframe_pc(cf, pc);
}
}
}
/* Return MULTRES or 0. */
/* Return MULTRES or 0 or -17. */
ERRNO_RESTORE
switch (bc_op(*pc)) {
case BC_CALLM: case BC_CALLMT:
@@ -943,6 +934,18 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
return (int)((BCReg)(L->top - L->base) + 1 - bc_a(*pc) - bc_d(*pc));
case BC_TSETM:
return (int)((BCReg)(L->top - L->base) + 1 - bc_a(*pc));
case BC_JLOOP:
retpc = &traceref(J, bc_d(*pc))->startins;
if (bc_isret(bc_op(*retpc)) || bc_op(*retpc) == BC_ITERN) {
/* Dispatch to original ins to ensure forward progress. */
if (J->state != LJ_TRACE_RECORD) return -17;
/* Unpatch bytecode when recording. */
J->patchins = *pc;
J->patchpc = (BCIns *)pc;
*J->patchpc = *retpc;
J->bcskip = 1;
}
return 0;
default:
if (bc_op(*pc) >= BC_FUNCF)
return (int)((BCReg)(L->top - L->base) + 1);