diff options
Diffstat (limited to '')
-rw-r--r-- | src/lj_asm_ppc.h | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/src/lj_asm_ppc.h b/src/lj_asm_ppc.h index 77ab09d6..0952ca26 100644 --- a/src/lj_asm_ppc.h +++ b/src/lj_asm_ppc.h | |||
@@ -2067,6 +2067,9 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap) | |||
2067 | 2067 | ||
2068 | /* -- GC handling --------------------------------------------------------- */ | 2068 | /* -- GC handling --------------------------------------------------------- */ |
2069 | 2069 | ||
2070 | /* Marker to prevent patching the GC check exit. */ | ||
2071 | #define PPC_NOPATCH_GC_CHECK PPCI_ORIS | ||
2072 | |||
2070 | /* Check GC threshold and do one or more GC steps. */ | 2073 | /* Check GC threshold and do one or more GC steps. */ |
2071 | static void asm_gc_check(ASMState *as) | 2074 | static void asm_gc_check(ASMState *as) |
2072 | { | 2075 | { |
@@ -2078,6 +2081,7 @@ static void asm_gc_check(ASMState *as) | |||
2078 | l_end = emit_label(as); | 2081 | l_end = emit_label(as); |
2079 | /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */ | 2082 | /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */ |
2080 | asm_guardcc(as, CC_NE); /* Assumes asm_snap_prep() already done. */ | 2083 | asm_guardcc(as, CC_NE); /* Assumes asm_snap_prep() already done. */ |
2084 | *--as->mcp = PPC_NOPATCH_GC_CHECK; | ||
2081 | emit_ai(as, PPCI_CMPWI, RID_RET, 0); | 2085 | emit_ai(as, PPCI_CMPWI, RID_RET, 0); |
2082 | args[0] = ASMREF_TMP1; /* global_State *g */ | 2086 | args[0] = ASMREF_TMP1; /* global_State *g */ |
2083 | args[1] = ASMREF_TMP2; /* MSize steps */ | 2087 | args[1] = ASMREF_TMP2; /* MSize steps */ |
@@ -2217,7 +2221,7 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) | |||
2217 | MCode *px = exitstub_trace_addr(T, exitno); | 2221 | MCode *px = exitstub_trace_addr(T, exitno); |
2218 | MCode *cstart = NULL; | 2222 | MCode *cstart = NULL; |
2219 | MCode *mcarea = lj_mcode_patch(J, p, 0); | 2223 | MCode *mcarea = lj_mcode_patch(J, p, 0); |
2220 | int clearso = 0; | 2224 | int clearso = 0, patchlong = 1; |
2221 | for (; p < pe; p++) { | 2225 | for (; p < pe; p++) { |
2222 | /* Look for exitstub branch, try to replace with branch to target. */ | 2226 | /* Look for exitstub branch, try to replace with branch to target. */ |
2223 | uint32_t ins = *p; | 2227 | uint32_t ins = *p; |
@@ -2229,7 +2233,9 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) | |||
2229 | delta -= sizeof(MCode); | 2233 | delta -= sizeof(MCode); |
2230 | } | 2234 | } |
2231 | /* Many, but not all short-range branches can be patched directly. */ | 2235 | /* Many, but not all short-range branches can be patched directly. */ |
2232 | if (((delta + 0x8000) >> 16) == 0) { | 2236 | if (p[-1] == PPC_NOPATCH_GC_CHECK) { |
2237 | patchlong = 0; | ||
2238 | } else if (((delta + 0x8000) >> 16) == 0) { | ||
2233 | *p = (ins & 0xffdf0000u) | ((uint32_t)delta & 0xffffu) | | 2239 | *p = (ins & 0xffdf0000u) | ((uint32_t)delta & 0xffffu) | |
2234 | ((delta & 0x8000) * (PPCF_Y/0x8000)); | 2240 | ((delta & 0x8000) * (PPCF_Y/0x8000)); |
2235 | if (!cstart) cstart = p; | 2241 | if (!cstart) cstart = p; |
@@ -2243,7 +2249,8 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) | |||
2243 | if (!cstart) cstart = p; | 2249 | if (!cstart) cstart = p; |
2244 | } | 2250 | } |
2245 | } | 2251 | } |
2246 | { /* Always patch long-range branch in exit stub itself. */ | 2252 | /* Always patch long-range branch in exit stub itself. Except, if we can't. */ |
2253 | if (patchlong) { | ||
2247 | ptrdiff_t delta = (char *)target - (char *)px - clearso; | 2254 | ptrdiff_t delta = (char *)target - (char *)px - clearso; |
2248 | lj_assertJ(((delta + 0x02000000) >> 26) == 0, | 2255 | lj_assertJ(((delta + 0x02000000) >> 26) == 0, |
2249 | "branch target out of range"); | 2256 | "branch target out of range"); |