[pypy-commit] pypy custom-trace: Change a detail: when running a JIT-generated piece of code
arigo
noreply at buildbot.pypy.org
Wed Aug 10 13:50:59 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: custom-trace
Changeset: r46417:5b749b6efd85
Date: 2011-08-09 15:31 +0200
http://bitbucket.org/pypy/pypy/changeset/5b749b6efd85/
Log: Change a detail: when running a JIT-generated piece of code with
shadowstack, we used to push two words on the shadowstack, namely a
MARKER followed by the address of the frame. Now we push only one
word, which points inside the frame to a MARKER, chosen such that
it's clearly a MARKER and not possibly a valid header of a GC
object.
The advantage of doing this will become apparent in the following
checkin: the shadowstack can be split at any place, and we don't
have to worry about keeping a MARKER word together with a frame
address. That would be hard to test and (in case we did it wrong)
would lead to rare bugs.
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -336,18 +336,18 @@
This is the class supporting --gcrootfinder=shadowstack.
"""
is_shadow_stack = True
- MARKER = 8
+ MARKER = -43 # cannot possibly be a valid header for a gc object
# The "shadowstack" is a portable way in which the GC finds the
# roots that live in the stack. Normally it is just a list of
# pointers to GC objects. The pointers may be moved around by a GC
- # collection. But with the JIT, an entry can also be MARKER, in
- # which case the next entry points to an assembler stack frame.
- # During a residual CALL from the assembler (which may indirectly
- # call the GC), we use the force_index stored in the assembler
- # stack frame to identify the call: we can go from the force_index
- # to a list of where the GC pointers are in the frame (this is the
- # purpose of the present class).
+ # collection. But with the JIT, an entry can also points to an
+ # assembler stack frame --- more precisely, to a MARKER word in it,
+ # so that we can tell. During a residual CALL from the assembler
+ # (which may indirectly call the GC), we use the force_index stored
+ # in the assembler stack frame to identify the call: we can go from
+ # the force_index to a list of where the GC pointers are in the
+ # frame (this is the purpose of the present class).
#
# Note that across CALL_MAY_FORCE or CALL_ASSEMBLER, we can also go
# from the force_index to a ResumeGuardForcedDescr instance, which
@@ -363,27 +363,36 @@
self._callshapes = lltype.nullptr(self.CALLSHAPES_ARRAY)
self._callshapes_maxlength = 0
self.force_index_ofs = gcdescr.force_index_ofs
+ self.marker_ofs = gcdescr.marker_ofs
def add_jit2gc_hooks(self, jit2gc):
#
def collect_jit_stack_root(callback, gc, addr):
- if addr.signed[0] != GcRootMap_shadowstack.MARKER:
- # common case
- if gc.points_to_valid_gc_object(addr):
+ # Note: first check with 'points_to_valid_gc_object' if the
+ # addr.address[0] appears to be a valid pointer. It returns
+ # False if it's NULL, and may also check for tagged integers.
+ # The important part here is that it will return True for a
+ # pointer to a MARKER (which is word-aligned), even though it's
+ # not pointing to a valid GC object.
+ if gc.points_to_valid_gc_object(addr):
+ if addr.address[0].signed[0] != GcRootMap_shadowstack.MARKER:
+ # common case
callback(gc, addr)
- return WORD
- else:
- # case of a MARKER followed by an assembler stack frame
- follow_stack_frame_of_assembler(callback, gc, addr)
- return 2 * WORD
+ else:
+ # points to a MARKER
+ follow_stack_frame_of_assembler(callback, gc, addr)
#
def follow_stack_frame_of_assembler(callback, gc, addr):
- frame_addr = addr.signed[1]
+ frame_addr = addr.signed[0] - self.marker_ofs
addr = llmemory.cast_int_to_adr(frame_addr + self.force_index_ofs)
force_index = addr.signed[0]
if force_index < 0:
force_index = ~force_index
callshape = self._callshapes[force_index]
+ # NB: the previous line reads a still-alive _callshapes,
+ # because we ensure that just before we called this piece of
+ # assembler, we put on the (same) stack a pointer to a
+ # loop_token that keeps the force_index alive.
n = 0
while True:
offset = rffi.cast(lltype.Signed, callshape[n])
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -218,6 +218,7 @@
class TestGcRootMapShadowStack:
class FakeGcDescr:
force_index_ofs = 92
+ marker_ofs = 80
def test_make_shapes(self):
gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py
--- a/pypy/jit/backend/x86/arch.py
+++ b/pypy/jit/backend/x86/arch.py
@@ -8,18 +8,21 @@
import sys
if sys.maxint == (2**31 - 1):
WORD = 4
- # ebp + ebx + esi + edi + 4 extra words + force_index = 9 words
- FRAME_FIXED_SIZE = 9
- FORCE_INDEX_OFS = -8*WORD
- MY_COPY_OF_REGS = -7*WORD
+ # ebp + ebx + esi + edi + MARKER + force_index + 4 extra words = 10 words
+ FRAME_FIXED_SIZE = 10
+ MARKER_OFS = -4*WORD
+ FORCE_INDEX_OFS = -5*WORD
+ MY_COPY_OF_REGS = -9*WORD
IS_X86_32 = True
IS_X86_64 = False
else:
WORD = 8
- # rbp + rbx + r12 + r13 + r14 + r15 + 11 extra words + force_index = 18
- FRAME_FIXED_SIZE = 18
- FORCE_INDEX_OFS = -17*WORD
- MY_COPY_OF_REGS = -16*WORD
+ # rbp + rbx + r12 + r13 + r14 + r15 + MARKER + force_index + 11 extra words
+ # = 19
+ FRAME_FIXED_SIZE = 19
+ MARKER_OFS = -6*WORD
+ FORCE_INDEX_OFS = -7*WORD
+ MY_COPY_OF_REGS = -18*WORD
IS_X86_32 = False
IS_X86_64 = True
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -762,8 +762,10 @@
self.mc.RET()
def _call_header_shadowstack(self, gcrootmap):
- # we need to put two words into the shadowstack: the MARKER
- # and the address of the frame (ebp, actually)
+ # we need to push a MARKER here, and to put into the shadowstack
+ # the address of this MARKER.
+ self.mc.PUSH_i32(gcrootmap.MARKER)
+ #
rst = gcrootmap.get_root_stack_top_addr()
if rx86.fits_in_32bits(rst):
self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop]
@@ -771,9 +773,8 @@
self.mc.MOV_ri(r13.value, rst) # MOV r13, rootstacktop
self.mc.MOV_rm(eax.value, (r13.value, 0)) # MOV eax, [r13]
#
- self.mc.LEA_rm(ebx.value, (eax.value, 2*WORD)) # LEA ebx, [eax+2*WORD]
- self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER
- self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp
+ self.mc.LEA_rm(ebx.value, (eax.value, WORD)) # LEA ebx, [eax+WORD]
+ self.mc.MOV_mr((eax.value, 0), esp.value) # MOV [eax], esp
#
if rx86.fits_in_32bits(rst):
self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx
@@ -783,10 +784,10 @@
def _call_footer_shadowstack(self, gcrootmap):
rst = gcrootmap.get_root_stack_top_addr()
if rx86.fits_in_32bits(rst):
- self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD
+ self.mc.SUB_ji8(rst, WORD) # SUB [rootstacktop], WORD
else:
self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop
- self.mc.SUB_mi8((ebx.value, 0), 2*WORD) # SUB [ebx], 2*WORD
+ self.mc.SUB_mi8((ebx.value, 0), WORD) # SUB [ebx], WORD
def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth):
if IS_X86_64:
diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -5,7 +5,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp import history, compile
from pypy.jit.backend.x86.assembler import Assembler386
-from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS
+from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS, MARKER_OFS
from pypy.jit.backend.x86.profagent import ProfileAgent
from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU
from pypy.jit.backend.x86 import regloc
@@ -29,6 +29,7 @@
gcdescr=None):
if gcdescr is not None:
gcdescr.force_index_ofs = FORCE_INDEX_OFS
+ gcdescr.marker_ofs = MARKER_OFS # only useful for shadowstack
AbstractLLCPU.__init__(self, rtyper, stats, opts,
translate_support_code, gcdescr)
diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py
--- a/pypy/rpython/memory/gctransform/shadowstack.py
+++ b/pypy/rpython/memory/gctransform/shadowstack.py
@@ -32,7 +32,6 @@
def collect_stack_root(callback, gc, addr):
if gc.points_to_valid_gc_object(addr):
callback(gc, addr)
- return sizeofaddr
self.rootstackhook = collect_stack_root
def push_stack(self, addr):
@@ -60,7 +59,8 @@
addr = gcdata.root_stack_base
end = gcdata.root_stack_top
while addr != end:
- addr += rootstackhook(collect_stack_root, gc, addr)
+ rootstackhook(collect_stack_root, gc, addr)
+ addr += sizeofaddr
if self.collect_stacks_from_other_threads is not None:
self.collect_stacks_from_other_threads(collect_stack_root)
@@ -172,7 +172,8 @@
end = stacktop - sizeofaddr
addr = end.address[0]
while addr != end:
- addr += rootstackhook(callback, gc, addr)
+ rootstackhook(callback, gc, addr)
+ addr += sizeofaddr
def collect_more_stacks(callback):
ll_assert(get_aid() == gcdata.active_thread,
More information about the pypy-commit
mailing list