Author: Armin Rigo <[email protected]>
Branch: stmgc-c7
Changeset: r70273:0f519ccd4e65
Date: 2014-03-25 08:55 +0100
http://bitbucket.org/pypy/pypy/changeset/0f519ccd4e65/
Log: A better attempt at fixing 31386d1544cb
diff --git a/rpython/jit/backend/x86/arch.py b/rpython/jit/backend/x86/arch.py
--- a/rpython/jit/backend/x86/arch.py
+++ b/rpython/jit/backend/x86/arch.py
@@ -54,10 +54,10 @@
# meaningful. We use ebp, i.e. the word at offset +0, to store the
# resume counter.
-STM_RESUME_BUF_WORDS = 4 # <-- for alignment, it can't be 3
+STM_RESUME_BUF_WORDS = 4
STM_FRAME_FIXED_SIZE = FRAME_FIXED_SIZE + STM_RESUME_BUF_WORDS
STM_JMPBUF_OFS = WORD * FRAME_FIXED_SIZE
STM_JMPBUF_OFS_RBP = STM_JMPBUF_OFS + 0 * WORD
STM_JMPBUF_OFS_RIP = STM_JMPBUF_OFS + 1 * WORD
STM_JMPBUF_OFS_RSP = STM_JMPBUF_OFS + 2 * WORD
-# unused: STM_JMPBUF_OFS + 3 * WORD
+STM_OLD_SHADOWSTACK = STM_JMPBUF_OFS + 3 * WORD
diff --git a/rpython/jit/backend/x86/assembler.py
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -19,7 +19,8 @@
from rpython.jit.backend.x86.arch import (
FRAME_FIXED_SIZE, WORD, IS_X86_64, JITFRAME_FIXED_SIZE, IS_X86_32,
PASS_ON_MY_FRAME, STM_FRAME_FIXED_SIZE, STM_JMPBUF_OFS,
- STM_JMPBUF_OFS_RIP, STM_JMPBUF_OFS_RSP, STM_JMPBUF_OFS_RBP)
+ STM_JMPBUF_OFS_RIP, STM_JMPBUF_OFS_RSP, STM_JMPBUF_OFS_RBP,
+ STM_OLD_SHADOWSTACK)
from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi,
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi,
r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG,
@@ -158,11 +159,17 @@
gcrootmap = self.cpu.gc_ll_descr.gcrootmap
if gcrootmap and gcrootmap.is_shadow_stack:
mc.MOV(ebx, self.heap_shadowstack_top())
+ if self.cpu.gc_ll_descr.stm:
+ # STM: there is a restriction on updating the shadowstack
+ # in-place: never put young objects below what is the
+ # transaction start's shadowstack position! As we might
+ # have started a transction in the same frame with the
+ # same value of shadowstack as now, we have nowhere to put
+ # this new young jitframe object -- so we have to PUSH it.
+ mc.ADD_ri(ebx.value, WORD)
+ mc.MOV(self.heap_shadowstack_top(), ebx)
+ #
mc.MOV_mr((self.SEGMENT_NO, ebx.value, -WORD), eax.value)
- # STM note: this stores the updated jitframe object in the
- # position -WORD, but (in this case) leaves the position
- # -2*WORD untouched. This old jitframe object remains in
- # the shadowstack just in case we do an abort later.
mc.MOV_bi((self.SEGMENT_FRAME, gcmap_ofs), 0)
self._pop_all_regs_from_frame(mc, [], self.cpu.supports_floats)
@@ -804,10 +811,8 @@
# to this frame, because we're about to leave. This is if
# we called a pypy_stm_start_transaction() earlier.
assert IS_X86_64
+ mc = self.mc
#
- # load the shadowstack pointer into ebx (a callee-saved register)
- mc = self.mc
- mc.MOV(ebx, self.heap_shadowstack_top())
# load the address of the jmpbuf
mc.LEA_rs(edi.value, STM_JMPBUF_OFS)
# compare it with the currently-stored jmpbuf
@@ -820,20 +825,17 @@
mc.MOV_ri(edi.value, rstm.adr_jit_default_msg)
mc.CALL(imm(rstm.adr__stm_become_inevitable))
# there could have been a collection in _stm_become_inevitable;
- # reload the frame into ebp
- mc.MOV_rm(ebp.value, (self.SEGMENT_NO, ebx.value, -WORD))
+ # reload the frame into ebp (but we don't need to apply the
+ # write barrier to it now)
+ mc.MOV(ecx, self.heap_shadowstack_top())
+ mc.MOV_rm(ebp.value, (self.SEGMENT_NO, ecx.value, -WORD))
#
# this is where the JNE above jumps
offset = mc.get_relative_pos() - jne_location
assert 0 < offset <= 127
mc.overwrite(jne_location-1, chr(offset))
- #
- # now decrement ebx by 2*WORD and store it back, which will
- # really decrement the shadowstack
- mc.SUB_ri(ebx.value, 2 * WORD)
- mc.MOV(self.heap_shadowstack_top(), ebx)
- elif gcrootmap and gcrootmap.is_shadow_stack:
+ if gcrootmap and gcrootmap.is_shadow_stack:
self._call_footer_shadowstack()
# the return value is the jitframe
@@ -860,23 +862,20 @@
self.mc.MOV_mr((self.SEGMENT_NO, ebx.value, 0), ebp.value)
# MOV [ebx], ebp
if self.cpu.gc_ll_descr.stm:
- # With stm, we push the jitframe twice on the shadowstack.
- # If we break transaction inside this frame, we'll do it
- # with only one item on the shadowstack, and then we'll
- # duplicate it again. The point is to store both the
- # old and the new copy when case we do a realloc_frame,
- # just for the case where we later abort.
- self.mc.MOV_mr((self.SEGMENT_NO, ebx.value, WORD), ebp.value)
- self.mc.ADD_ri(ebx.value, 2 * WORD)
- else:
- self.mc.ADD_ri(ebx.value, WORD)
+ self.mc.MOV_sr(STM_OLD_SHADOWSTACK, ebx.value)
+ self.mc.ADD_ri(ebx.value, WORD)
self.mc.MOV(self.heap_shadowstack_top(), ebx) # MOV [rootstacktop], ebx
def _call_footer_shadowstack(self):
- # SUB [rootstacktop], WORD (or 2 * WORD with STM)
if self.cpu.gc_ll_descr.stm:
- self.mc.SUB(self.heap_shadowstack_top(), 2 * WORD)
+ # STM: in the rare case where we need realloc_frame, the new
+ # frame is pushed on top of the old one. It's even possible
+ # that this occurs more than once. So we have to restore
+ # the old shadowstack by looking up its original saved value.
+ self.mc.MOV_rs(ecx.value, STM_OLD_SHADOWSTACK)
+ self.mc.MOV(self.heap_shadowstack_top(), ecx)
else:
+ # SUB [rootstacktop], WORD
self.mc.SUB(self.heap_shadowstack_top(), WORD)
def redirect_call_assembler(self, oldlooptoken, newlooptoken):
@@ -1148,10 +1147,7 @@
if gcrootmap.is_shadow_stack:
mc.MOV(ecx, self.heap_shadowstack_top())
mc.MOV(ebp, mem(self.SEGMENT_NO, ecx, -WORD))
- self._reload_frame_wb(mc, align_stack)
-
- def _reload_frame_wb(self, mc, align_stack=False):
- gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ #
wbdescr = self.cpu.gc_ll_descr.write_barrier_descr
if gcrootmap and wbdescr:
# frame never uses card marking, so we enforce this is not
@@ -2551,12 +2547,6 @@
# call stm_commit_transaction()
mc.CALL(imm(rstm.adr_stm_commit_transaction))
#
- # copy shadowstack[-1] into shadowstack[-2]: the latter is
- # not going to be used any more, now that we committed
- mc.MOV(ebx, self.heap_shadowstack_top())
- mc.MOV_rm(eax.value, (self.SEGMENT_NO, ebx.value, -WORD))
- mc.MOV_mr((self.SEGMENT_NO, ebx.value, -2 * WORD), eax.value)
- #
# update the two words in the STM_RESUME_BUF, as described
# in arch.py. The "learip" pseudo-instruction turns into
# what is, in gnu as syntax: lea 0(%rip), %rax (the 0 is
@@ -2583,13 +2573,8 @@
mc.LEA_rs(esi.value, STM_JMPBUF_OFS_RBP)
mc.CALL(imm(rstm.adr_pypy_stm_start_transaction))
#
- # reload ebp with the frame now, picking the value from
- # shadowstack[-2] and duplicating it into shadowstack[-1].
- # Only realloc_frame can make these values different again.
- mc.MOV(ebx, self.heap_shadowstack_top())
- mc.MOV_rm(ebp.value, (self.SEGMENT_NO, ebx.value, -2 * WORD))
- mc.MOV_mr((self.SEGMENT_NO, ebx.value, -WORD), ebp.value)
- self._reload_frame_wb(self.mc)
+ # reload ebp with the frame now
+ self._reload_frame_if_necessary(self.mc)
#
# restore regs
self._push_pop_regs_to_frame(False, mc, grp_regs, xmm_regs)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit