[pypy-svn] pypy jit-shadowstack: In-progress.

arigo commits-noreply at bitbucket.org
Thu Mar 31 13:55:52 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: jit-shadowstack
Changeset: r43042:cf2056d85fa5
Date: 2011-03-31 13:24 +0200
http://bitbucket.org/pypy/pypy/changeset/cf2056d85fa5/

Log:	In-progress.

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
@@ -75,8 +75,8 @@
         num2a = ((-num2|3) >> 7) | 128
         num2b = (-num2|3) & 127
         shape = gcrootmap.get_basic_shape()
-        gcrootmap.add_ebp_offset(shape, num1)
-        gcrootmap.add_ebp_offset(shape, num2)
+        gcrootmap.add_frame_offset(shape, num1)
+        gcrootmap.add_frame_offset(shape, num2)
         assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a])
         gcrootmap.add_callee_save_reg(shape, 1)
         assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
@@ -181,51 +181,74 @@
                 p = rffi.cast(rffi.CArrayPtr(llmemory.Address), gcmapstart)
                 p = rffi.ptradd(p, 2*i)
                 return llmemory.cast_ptr_to_adr(p)
-        saved = gc.asmgcroot
-        try:
-            gc.asmgcroot = Asmgcroot()
-            #
-            gcrootmap = GcRootMap_asmgcc()
-            gcrootmap._gcmap = lltype.malloc(gcrootmap.GCMAP_ARRAY,
-                                             1400, flavor='raw',
-                                             immortal=True)
-            for i in range(700):
-                gcrootmap._gcmap[i*2] = 1200000 + i
-                gcrootmap._gcmap[i*2+1] = i * 100 + 1
-            assert gcrootmap._gcmap_deadentries == 0
-            assert gc.asmgcroot.sort_count == 0
-            gcrootmap._gcmap_maxlength = 1400
-            gcrootmap._gcmap_curlength = 1400
-            gcrootmap._gcmap_sorted = False
-            #
-            gcrootmap.freeing_block(1200000 - 100, 1200000)
-            assert gcrootmap._gcmap_deadentries == 0
-            assert gc.asmgcroot.sort_count == 1
-            #
-            gcrootmap.freeing_block(1200000 + 100, 1200000 + 200)
-            assert gcrootmap._gcmap_deadentries == 100
-            assert gc.asmgcroot.sort_count == 1
-            for i in range(700):
-                if 100 <= i < 200:
-                    expected = 0
-                else:
-                    expected = i * 100 + 1
-                assert gcrootmap._gcmap[i*2] == 1200000 + i
-                assert gcrootmap._gcmap[i*2+1] == expected
-            #
-            gcrootmap.freeing_block(1200000 + 650, 1200000 + 750)
-            assert gcrootmap._gcmap_deadentries == 150
-            assert gc.asmgcroot.sort_count == 1
-            for i in range(700):
-                if 100 <= i < 200 or 650 <= i:
-                    expected = 0
-                else:
-                    expected = i * 100 + 1
-                assert gcrootmap._gcmap[i*2] == 1200000 + i
-                assert gcrootmap._gcmap[i*2+1] == expected
+        asmgcroot = Asmgcroot()
         #
-        finally:
-            gc.asmgcroot = saved
+        gcrootmap = GcRootMap_asmgcc()
+        gcrootmap._gcmap = lltype.malloc(gcrootmap.GCMAP_ARRAY,
+                                         1400, flavor='raw',
+                                         immortal=True)
+        for i in range(700):
+            gcrootmap._gcmap[i*2] = 1200000 + i
+            gcrootmap._gcmap[i*2+1] = i * 100 + 1
+        assert gcrootmap._gcmap_deadentries == 0
+        assert asmgcroot.sort_count == 0
+        gcrootmap._gcmap_maxlength = 1400
+        gcrootmap._gcmap_curlength = 1400
+        gcrootmap._gcmap_sorted = False
+        #
+        gcrootmap.freeing_block(1200000 - 100, 1200000, asmgcroot=asmgcroot)
+        assert gcrootmap._gcmap_deadentries == 0
+        assert asmgcroot.sort_count == 1
+        #
+        gcrootmap.freeing_block(1200000 + 100, 1200000 + 200,
+                                asmgcroot=asmgcroot)
+        assert gcrootmap._gcmap_deadentries == 100
+        assert asmgcroot.sort_count == 1
+        for i in range(700):
+            if 100 <= i < 200:
+                expected = 0
+            else:
+                expected = i * 100 + 1
+            assert gcrootmap._gcmap[i*2] == 1200000 + i
+            assert gcrootmap._gcmap[i*2+1] == expected
+        #
+        gcrootmap.freeing_block(1200000 + 650, 1200000 + 750,
+                                asmgcroot=asmgcroot)
+        assert gcrootmap._gcmap_deadentries == 150
+        assert asmgcroot.sort_count == 1
+        for i in range(700):
+            if 100 <= i < 200 or 650 <= i:
+                expected = 0
+            else:
+                expected = i * 100 + 1
+            assert gcrootmap._gcmap[i*2] == 1200000 + i
+            assert gcrootmap._gcmap[i*2+1] == expected
+
+class TestGcRootMapShadowStack:
+    class FakeGcDescr:
+        force_index_ofs = 92
+
+    def test_make_shapes(self):
+        gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
+        shape = gcrootmap.get_basic_shape()
+        gcrootmap.add_frame_offset(shape, 16)
+        gcrootmap.add_frame_offset(shape, -24)
+        assert shape == [16, -24]
+
+    def test_compress_callshape(self):
+        class FakeDataBlockWrapper:
+            def malloc_aligned(self, size, alignment):
+                assert alignment == 4    # even on 64-bits
+                assert size == 12        # 4*3, even on 64-bits
+                return rffi.cast(lltype.Signed, p)
+        datablockwrapper = FakeDataBlockWrapper()
+        p = lltype.malloc(rffi.CArray(rffi.INT), 3, immortal=True)
+        gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
+        shape = [16, -24]
+        gcrootmap.compress_callshape(shape, datablockwrapper)
+        assert rffi.cast(lltype.Signed, p[0]) == 16
+        assert rffi.cast(lltype.Signed, p[1]) == -24
+        assert rffi.cast(lltype.Signed, p[2]) == 0
 
 
 class FakeLLOp(object):

diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -1,5 +1,5 @@
 
-from pypy.jit.metainterp.history import Const, Box
+from pypy.jit.metainterp.history import Const, Box, REF
 from pypy.rlib.objectmodel import we_are_translated
 
 class TempBox(Box):
@@ -313,11 +313,12 @@
             self.assembler.regalloc_mov(reg, to)
         # otherwise it's clean
 
-    def before_call(self, force_store=[], save_all_regs=False):
+    def before_call(self, force_store=[], save_all_regs=0):
         """ Spill registers before a call, as described by
         'self.save_around_call_regs'.  Registers are not spilled if
         they don't survive past the current operation, unless they
-        are listed in 'force_store'.
+        are listed in 'force_store'.  'save_all_regs' can be 0 (default),
+        1 (save all), or 2 (save default+PTRs).
         """
         for v, reg in self.reg_bindings.items():
             if v not in force_store and self.longevity[v][1] <= self.position:
@@ -325,9 +326,11 @@
                 del self.reg_bindings[v]
                 self.free_regs.append(reg)
                 continue
-            if not save_all_regs and reg not in self.save_around_call_regs:
-                # we don't have to
-                continue
+            if save_all_regs != 1 and reg not in self.save_around_call_regs:
+                if save_all_regs == 0:
+                    continue    # we don't have to
+                if v.type != REF:
+                    continue    # only save GC pointers
             self._sync_var(v)
             del self.reg_bindings[v]
             self.free_regs.append(reg)

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
@@ -317,8 +317,9 @@
         return j
 
     @rgc.no_collect
-    def freeing_block(self, start, stop):
-        from pypy.rpython.memory.gctransform import asmgcroot
+    def freeing_block(self, start, stop, asmgcroot=None):
+        if asmgcroot is None:    # always the case, except for tests
+            from pypy.rpython.memory.gctransform import asmgcroot
         # if [start:stop] is a raw block of assembler, then look up the
         # corresponding gcroot markers, and mark them as freed now in
         # self._gcmap by setting the 2nd address of every entry to NULL.
@@ -441,9 +442,25 @@
                 return WORD
             else:
                 # case of a MARKER followed by an assembler stack frame
-                self.follow_stack_frame_of_assembler(callback, gc, addr)
+                follow_stack_frame_of_assembler(callback, gc, addr)
                 return 2 * WORD
         #
+        def follow_stack_frame_of_assembler(callback, gc, addr):
+            frame_addr = addr.signed[1]
+            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]
+            n = 0
+            while True:
+                offset = rffi.cast(lltype.Signed, callshape[n])
+                if offset == 0:
+                    break
+                addr = llmemory.cast_int_to_adr(frame_addr + offset)
+                callback(gc, addr)
+                n += 1
+        #
         jit2gc.update({
             'rootstackhook': collect_jit_stack_root,
             })
@@ -451,22 +468,6 @@
     def initialize(self):
         pass
 
-    def follow_stack_frame_of_assembler(self, callback, gc, addr):
-        frame_addr = addr.signed[1]
-        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]
-        n = 0
-        while True:
-            offset = rffi.cast(lltype.Signed, callshape[n])
-            if offset == 0:
-                break
-            addr = llmemory.cast_int_to_adr(frame_addr + offset)
-            callback(gc, addr)
-            n += 1
-
     def get_basic_shape(self, is_64_bit=False):
         return []
 

diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -738,8 +738,12 @@
 
     def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None):
         save_all_regs = guard_not_forced_op is not None
+        self.xrm.before_call(force_store, save_all_regs=save_all_regs)
+        if not save_all_regs:
+            gcrootmap = gc_ll_descr = self.assembler.cpu.gc_ll_descr.gcrootmap
+            if gcrootmap and gcrootmap.is_shadow_stack:
+                save_all_regs = 2
         self.rm.before_call(force_store, save_all_regs=save_all_regs)
-        self.xrm.before_call(force_store, save_all_regs=save_all_regs)
         if op.result is not None:
             if op.result.type == FLOAT:
                 resloc = self.xrm.after_call(op.result)


More information about the Pypy-commit mailing list