[pypy-commit] pypy shadowstack-perf: Tentative: remove the clears at the start of every function.

arigo noreply at buildbot.pypy.org
Wed Jul 6 20:28:34 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: shadowstack-perf
Changeset: r45374:31d4b032dd61
Date: 2011-07-04 11:15 +0200
http://bitbucket.org/pypy/pypy/changeset/31d4b032dd61/

Log:	Tentative: remove the clears at the start of every function. Needs
	careful tweaks to ensure that old, invalid pointers are not left
	behind after a collection.

diff --git a/pypy/rpython/lltypesystem/llmemory.py b/pypy/rpython/lltypesystem/llmemory.py
--- a/pypy/rpython/lltypesystem/llmemory.py
+++ b/pypy/rpython/lltypesystem/llmemory.py
@@ -435,8 +435,17 @@
         if isinstance(other, fakeaddress):
             if self == other:
                 return 0
-            else:
-                raise TypeError("cannot subtract fakeaddresses in general")
+            # <*_subarray at n> - <*_subarray at m> == ItemOffset(n-m)
+            obj1 = self.ptr._obj
+            obj2 = other.ptr._obj
+            if (isinstance(obj1, lltype._subarray) and
+                isinstance(obj2, lltype._subarray) and
+                obj1._TYPE == obj2._TYPE and
+                obj1._parentstructure() == obj2._parentstructure()):
+                n = obj1._parent_index
+                m = obj2._parent_index
+                return ItemOffset(obj1._TYPE.OF, n - m)
+            raise TypeError("cannot subtract fakeaddresses in general")
         if other == 0:
             return self
         return NotImplemented
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
@@ -55,11 +55,25 @@
         return top.address[0]
 
     def allocate_stack(self):
-        return llmemory.raw_malloc(self.rootstacksize)
+        stackbase = llmemory.raw_malloc(self.rootstacksize)
+        if not stackbase:
+            raise MemoryError
+        self.clear_stack(stackbase, stackbase)
+        return stackbase
+
+    def clear_stack(self, stackbase, stacktop):
+        """When a function is called, the current stack top is
+        incremented by as much as needed by this function, but the old
+        content is left in the stack.  This is a speed optimization that
+        may lead to occasional leaks, because the stack may end up
+        containing dead pointers.  Another drawback is that we need to
+        clear the stack manually after every minor collection, to
+        prevent these leftover pointers from pointing to garbage."""
+        size = stackbase + self.rootstacksize - stacktop
+        llmemory.raw_memclear(stacktop, size)
 
     def setup_root_walker(self):
         stackbase = self.allocate_stack()
-        ll_assert(bool(stackbase), "could not allocate root stack")
         self.gcdata.root_stack_top  = stackbase
         self.gcdata.root_stack_base = stackbase
         BaseRootWalker.setup_root_walker(self)
@@ -67,9 +81,10 @@
     def walk_stack_roots(self, collect_stack_root):
         gcdata = self.gcdata
         gc = self.gc
-        rootstackhook = self.rootstackhook
         addr = gcdata.root_stack_base
         end = gcdata.root_stack_top
+        self.clear_stack(addr, end)
+        rootstackhook = self.rootstackhook
         while addr != end:
             addr += rootstackhook(collect_stack_root, gc, addr)
         if self.collect_stacks_from_other_threads is not None:
@@ -107,8 +122,6 @@
             """
             if not gcdata._fresh_rootstack:
                 gcdata._fresh_rootstack = self.allocate_stack()
-                if not gcdata._fresh_rootstack:
-                    raise MemoryError
 
         def thread_run():
             """Called whenever the current thread (re-)acquired the GIL.
@@ -132,6 +145,7 @@
             gcdata.thread_stacks.setitem(aid, llmemory.NULL)
             old = gcdata.root_stack_base
             if gcdata._fresh_rootstack == llmemory.NULL:
+                self.clear_stack(old, old)
                 gcdata._fresh_rootstack = old
             else:
                 llmemory.raw_free(old)
@@ -178,9 +192,10 @@
                 # collect all valid stacks from the dict (the entry
                 # corresponding to the current thread is not valid)
                 gc = self.gc
-                rootstackhook = self.rootstackhook
                 end = stacktop - sizeofaddr
                 addr = end.address[0]
+                self.clear_stack(addr, stacktop)
+                rootstackhook = self.rootstackhook
                 while addr != end:
                     addr += rootstackhook(callback, gc, addr)
 
@@ -294,13 +309,6 @@
         c_numcolors = rmodel.inputconst(lltype.Signed, numcolors)
         llops.genop("direct_call", [gct.incr_stack_ptr, c_numcolors],
                     resulttype=llmemory.Address)
-        top_addr = llops.genop("direct_call",
-                               [gct.get_stack_top_ptr],
-                               resulttype=llmemory.Address)
-        c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL)
-        for k in range(numcolors):
-            c_k = rmodel.inputconst(lltype.Signed, ~k)
-            llops.genop("raw_store", [top_addr, c_type, c_k, c_null])
         graph.startblock.operations[:0] = llops
         #
         # Put at the end of the graph: "decr_stack()"


More information about the pypy-commit mailing list