[pypy-commit] pypy stacklet: merge heads

arigo noreply at buildbot.pypy.org
Wed Aug 10 11:21:21 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46406:c4f948c39d83
Date: 2011-08-10 11:22 +0200
http://bitbucket.org/pypy/pypy/changeset/c4f948c39d83/

Log:	merge heads

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)
 
@@ -175,7 +175,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