Skip to content

Commit e8ec6fe

Browse files
author
Mike Pall
committed
Prevent patching of the GC exit check branch.
Reported by Arseny Vakhrushev.
1 parent 881d02d commit e8ec6fe

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

src/lj_asm_arm.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,9 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap)
20402040

20412041
/* -- GC handling --------------------------------------------------------- */
20422042

2043+
/* Marker to prevent patching the GC check exit. */
2044+
#define ARM_NOPATCH_GC_CHECK (ARMI_BIC|ARMI_K12)
2045+
20432046
/* Check GC threshold and do one or more GC steps. */
20442047
static void asm_gc_check(ASMState *as)
20452048
{
@@ -2051,6 +2054,7 @@ static void asm_gc_check(ASMState *as)
20512054
l_end = emit_label(as);
20522055
/* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */
20532056
asm_guardcc(as, CC_NE); /* Assumes asm_snap_prep() already done. */
2057+
*--as->mcp = ARM_NOPATCH_GC_CHECK;
20542058
emit_n(as, ARMI_CMP|ARMI_K12|0, RID_RET);
20552059
args[0] = ASMREF_TMP1; /* global_State *g */
20562060
args[1] = ASMREF_TMP2; /* MSize steps */
@@ -2349,7 +2353,8 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
23492353
/* Look for bl_cc exitstub, replace with b_cc target. */
23502354
uint32_t ins = *p;
23512355
if ((ins & 0x0f000000u) == 0x0b000000u && ins < 0xf0000000u &&
2352-
((ins ^ (px-p)) & 0x00ffffffu) == 0) {
2356+
((ins ^ (px-p)) & 0x00ffffffu) == 0 &&
2357+
p[-1] != ARM_NOPATCH_GC_CHECK) {
23532358
*p = (ins & 0xfe000000u) | (((target-p)-2) & 0x00ffffffu);
23542359
cend = p+1;
23552360
if (!cstart) cstart = p;

src/lj_asm_mips.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,9 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap)
16651665

16661666
/* -- GC handling --------------------------------------------------------- */
16671667

1668+
/* Marker to prevent patching the GC check exit. */
1669+
#define MIPS_NOPATCH_GC_CHECK MIPSI_OR
1670+
16681671
/* Check GC threshold and do one or more GC steps. */
16691672
static void asm_gc_check(ASMState *as)
16701673
{
@@ -1680,6 +1683,7 @@ static void asm_gc_check(ASMState *as)
16801683
args[0] = ASMREF_TMP1; /* global_State *g */
16811684
args[1] = ASMREF_TMP2; /* MSize steps */
16821685
asm_gencall(as, ci, args);
1686+
l_end[-3] = MIPS_NOPATCH_GC_CHECK; /* Replace the nop after the call. */
16831687
emit_tsi(as, MIPSI_ADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768);
16841688
tmp = ra_releasetmp(as, ASMREF_TMP2);
16851689
emit_loadi(as, tmp, as->gcsteps);
@@ -1936,7 +1940,8 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
19361940
if (((p[-1] ^ (px-p)) & 0xffffu) == 0 &&
19371941
((p[-1] & 0xf0000000u) == MIPSI_BEQ ||
19381942
(p[-1] & 0xfc1e0000u) == MIPSI_BLTZ ||
1939-
(p[-1] & 0xffe00000u) == MIPSI_BC1F)) {
1943+
(p[-1] & 0xffe00000u) == MIPSI_BC1F) &&
1944+
p[-2] != MIPS_NOPATCH_GC_CHECK) {
19401945
ptrdiff_t delta = target - p;
19411946
if (((delta + 0x8000) >> 16) == 0) { /* Patch in-range branch. */
19421947
patchbranch:

src/lj_asm_ppc.h

+10-3
Original file line numberDiff line numberDiff line change
@@ -1852,6 +1852,9 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap)
18521852

18531853
/* -- GC handling --------------------------------------------------------- */
18541854

1855+
/* Marker to prevent patching the GC check exit. */
1856+
#define PPC_NOPATCH_GC_CHECK PPCI_ORIS
1857+
18551858
/* Check GC threshold and do one or more GC steps. */
18561859
static void asm_gc_check(ASMState *as)
18571860
{
@@ -1863,6 +1866,7 @@ static void asm_gc_check(ASMState *as)
18631866
l_end = emit_label(as);
18641867
/* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */
18651868
asm_guardcc(as, CC_NE); /* Assumes asm_snap_prep() already done. */
1869+
*--as->mcp = PPC_NOPATCH_GC_CHECK;
18661870
emit_ai(as, PPCI_CMPWI, RID_RET, 0);
18671871
args[0] = ASMREF_TMP1; /* global_State *g */
18681872
args[1] = ASMREF_TMP2; /* MSize steps */
@@ -2124,7 +2128,7 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
21242128
MCode *px = exitstub_trace_addr(T, exitno);
21252129
MCode *cstart = NULL;
21262130
MCode *mcarea = lj_mcode_patch(J, p, 0);
2127-
int clearso = 0;
2131+
int clearso = 0, patchlong = 1;
21282132
for (; p < pe; p++) {
21292133
/* Look for exitstub branch, try to replace with branch to target. */
21302134
uint32_t ins = *p;
@@ -2136,7 +2140,9 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
21362140
delta -= sizeof(MCode);
21372141
}
21382142
/* Many, but not all short-range branches can be patched directly. */
2139-
if (((delta + 0x8000) >> 16) == 0) {
2143+
if (p[-1] == PPC_NOPATCH_GC_CHECK) {
2144+
patchlong = 0;
2145+
} else if (((delta + 0x8000) >> 16) == 0) {
21402146
*p = (ins & 0xffdf0000u) | ((uint32_t)delta & 0xffffu) |
21412147
((delta & 0x8000) * (PPCF_Y/0x8000));
21422148
if (!cstart) cstart = p;
@@ -2149,7 +2155,8 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
21492155
if (!cstart) cstart = p;
21502156
}
21512157
}
2152-
{ /* Always patch long-range branch in exit stub itself. */
2158+
/* Always patch long-range branch in exit stub itself. Except, if we can't. */
2159+
if (patchlong) {
21532160
ptrdiff_t delta = (char *)target - (char *)px - clearso;
21542161
lua_assert(((delta + 0x02000000) >> 26) == 0);
21552162
*px = PPCI_B | ((uint32_t)delta & 0x03ffffffu);

src/lj_asm_x86.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -2884,6 +2884,7 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
28842884
MSize len = T->szmcode;
28852885
MCode *px = exitstub_addr(J, exitno) - 6;
28862886
MCode *pe = p+len-6;
2887+
MCode *pgc = NULL;
28872888
uint32_t stateaddr = u32ptr(&J2G(J)->vmstate);
28882889
if (len > 5 && p[len-5] == XI_JMP && p+len-6 + *(int32_t *)(p+len-4) == px)
28892890
*(int32_t *)(p+len-4) = jmprel(p+len, target);
@@ -2892,9 +2893,15 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
28922893
if (*(uint32_t *)(p+(LJ_64 ? 3 : 2)) == stateaddr && p[0] == XI_MOVmi)
28932894
break;
28942895
lua_assert(p < pe);
2895-
for (; p < pe; p += asm_x86_inslen(p))
2896-
if ((*(uint16_t *)p & 0xf0ff) == 0x800f && p + *(int32_t *)(p+2) == px)
2896+
for (; p < pe; p += asm_x86_inslen(p)) {
2897+
if ((*(uint16_t *)p & 0xf0ff) == 0x800f && p + *(int32_t *)(p+2) == px &&
2898+
p != pgc) {
28972899
*(int32_t *)(p+2) = jmprel(p+6, target);
2900+
} else if (*p == XI_CALL &&
2901+
(void *)(p+5+*(int32_t *)(p+1)) == (void *)lj_gc_step_jit) {
2902+
pgc = p+7; /* Do not patch GC check exit. */
2903+
}
2904+
}
28982905
lj_mcode_sync(T->mcode, T->mcode + T->szmcode);
28992906
lj_mcode_patch(J, mcarea, 1);
29002907
}

0 commit comments

Comments
 (0)