ARM64: only patch exits if within apropriate ranges. always patch stub too

conditional branches have much smaller ranges than unconditional ones.  If a
side trace is beyond range, leave the exit unmodified; for these cases the
exit stub (an unconditional branch) is patched too.
This commit is contained in:
Javier Guerra 2018-06-20 21:51:48 +01:00
parent c3c54ce1ae
commit 5bbd92290d

View File

@ -1975,6 +1975,10 @@ static void asm_mcode_fixup(MCode *mcode, MSize size)
#define LJ_TARGET_MCODE_FIXUP 1
#endif
#define valid_S26(d) ((((d) + (1<<25)) >> 26) == 0)
#define valid_S19(d) ((((d) + (1<<18)) >> 19) == 0)
#define valid_S14(d) ((((d) + (1<<13)) >> 14) == 0)
/* -- Trace patching ------------------------------------------------------ */
/* Patch exit jumps of existing machine code to a new target. */
@ -1982,7 +1986,7 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
{
MCode *p = T->mcode;
MCode *pe = (MCode *)((char *)p + T->szmcode);
MCode *cstart = NULL, *cend = p;
MCode *cstart = NULL;
MCode *mcarea = lj_mcode_patch(J, p, 0);
MCode *px = exitstub_trace_addr(T, exitno);
for (; p < pe; p++) {
@ -1990,32 +1994,43 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
MCode ins = A64I_LE(*p);
if ((ins & 0xff000000u) == 0x54000000u &&
((ins ^ ((px-p)<<5)) & 0x00ffffe0u) == 0) {
/* Patch bcc exitstub. */
*p = A64I_LE((ins & 0xff00001fu) | (((target-p)<<5) & 0x00ffffe0u));
cend = p+1;
/* Patch bcc exitstub if within 1MB */
ptrdiff_t delta = target - p;
if (valid_S19(delta)) {
*p = A64I_LE((ins & 0xff00001fu) | A64F_S19(delta));
if (!cstart) cstart = p;
}
} else if ((ins & 0xfc000000u) == 0x14000000u &&
((ins ^ (px-p)) & 0x03ffffffu) == 0) {
/* Patch b exitstub. */
lua_assert(valid_S26(target-p));
*p = A64I_LE((ins & 0xfc000000u) | ((target-p) & 0x03ffffffu));
cend = p+1;
if (!cstart) cstart = p;
} else if ((ins & 0x7e000000u) == 0x34000000u &&
((ins ^ ((px-p)<<5)) & 0x00ffffe0u) == 0) {
/* Patch cbz/cbnz exitstub. */
*p = A64I_LE((ins & 0xff00001f) | (((target-p)<<5) & 0x00ffffe0u));
cend = p+1;
/* Patch cbz/cbnz exitstub if within 1MB. */
ptrdiff_t delta = target - p;
if (valid_S19(delta)) {
*p = A64I_LE((ins & 0xff00001f) | A64F_S19(delta));
if (!cstart) cstart = p;
}
} else if ((ins & 0x7e000000u) == 0x36000000u &&
((ins ^ ((px-p)<<5)) & 0x0007ffe0u) == 0) {
/* Patch tbz/tbnz exitstub. */
*p = A64I_LE((ins & 0xfff8001fu) | (((target-p)<<5) & 0x0007ffe0u));
cend = p+1;
/* Patch tbz/tbnz exitstub if within 32kB. */
ptrdiff_t delta = target - p;
if (valid_S14(delta)) {
*p = A64I_LE((ins & 0xfff8001fu) | ((delta<<5) & 0x0007ffe0u));
if (!cstart) cstart = p;
}
}
lua_assert(cstart != NULL);
lj_mcode_sync(cstart, cend);
}
{
ptrdiff_t delta = target - px;
lua_assert(valid_S26(delta));
*px = A64I_B | ((uint32_t)delta & 0x03ffffffu);
if (!cstart) cstart = px;
}
lj_mcode_sync(cstart, px + 1);
lj_mcode_patch(J, mcarea, 1);
}