[pypy-commit] pypy shadowstack-perf-2: in-progress: starting with tests

arigo pypy.commits at gmail.com
Wed May 11 10:15:39 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: shadowstack-perf-2
Changeset: r84375:76c1df47dbe3
Date: 2016-05-11 16:15 +0200
http://bitbucket.org/pypy/pypy/changeset/76c1df47dbe3/

Log:	in-progress: starting with tests

diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -609,6 +609,9 @@
                     "the custom trace hook %r for %r can cause "
                     "the GC to be called!" % (func, TP))
 
+    def postprocess_graph(self, graph):
+        self.root_walker.postprocess_graph(self, graph)
+
     def consider_constant(self, TYPE, value):
         self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc)
 
diff --git a/rpython/memory/gctransform/shadowcolor.py b/rpython/memory/gctransform/shadowcolor.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gctransform/shadowcolor.py
@@ -0,0 +1,35 @@
+
+
+def find_interesting_variables(graph):
+    # Decide which variables are "interesting" or not.  Interesting
+    # variables contain at least the ones that appear in gc_push_roots
+    # and gc_pop_roots.
+    pending = []
+    interesting_vars = set()
+    for block in graph.iterblocks():
+        for op in block.operations:
+            if op.opname == 'gc_push_roots':
+                for v in op.args:
+                    interesting_vars.add(v)
+                    pending.append((block, v))
+            elif op.opname == 'gc_pop_roots':
+                for v in op.args:
+                    assert v in interesting_vars   # must be pushed just above
+    if not interesting_vars:
+        return
+
+    # If there is a path from a gc_pop_roots(v) to a subsequent
+    # gc_push_roots(w) where w contains the same value as v along that
+    # path, then we consider all intermediate blocks along that path
+    # which contain a copy of the same value, and add these variables
+    # as "interesting", too.
+
+    #....
+    return interesting_vars
+
+
+def postprocess_graph(gct, graph):
+    """Collect information about the gc_push_roots and gc_pop_roots
+    added in this complete graph, and replace them with real operations.
+    """
+    xxxx
diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py
--- a/rpython/memory/gctransform/shadowstack.py
+++ b/rpython/memory/gctransform/shadowstack.py
@@ -31,28 +31,13 @@
         self.num_pushs += len(livevars)
         if not livevars:
             return []
-        c_len = rmodel.inputconst(lltype.Signed, len(livevars) )
-        base_addr = hop.genop("direct_call", [self.incr_stack_ptr, c_len ],
-                              resulttype=llmemory.Address)
-        for k,var in enumerate(livevars):
-            c_k = rmodel.inputconst(lltype.Signed, k * sizeofaddr)
-            v_adr = gen_cast(hop.llops, llmemory.Address, var)
-            hop.genop("raw_store", [base_addr, c_k, v_adr])
+        hop.genop("gc_push_roots", livevars)
         return livevars
 
     def pop_roots(self, hop, livevars):
         if not livevars:
             return
-        c_len = rmodel.inputconst(lltype.Signed, len(livevars) )
-        base_addr = hop.genop("direct_call", [self.decr_stack_ptr, c_len ],
-                              resulttype=llmemory.Address)
-        if self.gcdata.gc.moving_gc:
-            # for moving collectors, reload the roots into the local variables
-            for k,var in enumerate(livevars):
-                c_k = rmodel.inputconst(lltype.Signed, k * sizeofaddr)
-                v_newaddr = hop.genop("raw_load", [base_addr, c_k],
-                                      resulttype=llmemory.Address)
-                hop.genop("gc_reload_possibly_moved", [v_newaddr, var])
+        hop.genop("gc_pop_roots", livevars)
 
 
 class ShadowStackRootWalker(BaseRootWalker):
@@ -222,6 +207,10 @@
         from rpython.rlib import _stacklet_shadowstack
         _stacklet_shadowstack.complete_destrptr(gctransformer)
 
+    def postprocess_graph(self, gct, graph):
+        from rpython.memory.gctransform import shadowcolor
+        shadowcolor.postprocess_graph(gct, graph)
+
 # ____________________________________________________________
 
 class ShadowStackPool(object):
diff --git a/rpython/memory/gctransform/test/test_shadowcolor.py b/rpython/memory/gctransform/test/test_shadowcolor.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gctransform/test/test_shadowcolor.py
@@ -0,0 +1,55 @@
+from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.test.test_llinterp import gengraph
+from rpython.conftest import option
+from rpython.memory.gctransform.shadowcolor import find_interesting_variables
+
+
+def make_graph(f, argtypes):
+    t, rtyper, graph = gengraph(f, argtypes, viewbefore=False)
+    if getattr(option, 'view', False):
+        graph.show()
+    return graph
+
+def summary(interesting_vars):
+    result = {}
+    for v in interesting_vars:
+        name = v._name.rstrip('_')
+        result[name] = result.get(name, 0) + 1
+    return result
+
+
+def test_interesting_vars_0():
+    def f(a, b):
+        pass
+    graph = make_graph(f, [llmemory.GCREF, int])
+    assert not find_interesting_variables(graph)
+
+def test_interesting_vars_1():
+    def f(a, b):
+        llop.gc_push_roots(lltype.Void, a)
+        llop.gc_pop_roots(lltype.Void, a)
+    graph = make_graph(f, [llmemory.GCREF, int])
+    assert summary(find_interesting_variables(graph)) == {'a': 1}
+
+def test_interesting_vars_2():
+    def f(a, b, c):
+        llop.gc_push_roots(lltype.Void, a)
+        llop.gc_pop_roots(lltype.Void, a)
+        while b > 0:
+            b -= 5
+        llop.gc_push_roots(lltype.Void, c)
+        llop.gc_pop_roots(lltype.Void, c)
+    graph = make_graph(f, [llmemory.GCREF, int, llmemory.GCREF])
+    assert summary(find_interesting_variables(graph)) == {'a': 1, 'c': 1}
+
+def test_interesting_vars_3():
+    def f(a, b):
+        llop.gc_push_roots(lltype.Void, a)
+        llop.gc_pop_roots(lltype.Void, a)
+        while b > 0:   # 'a' remains interesting across the blocks of this loop
+            b -= 5
+        llop.gc_push_roots(lltype.Void, a)
+        llop.gc_pop_roots(lltype.Void, a)
+    graph = make_graph(f, [llmemory.GCREF, int])
+    assert summary(find_interesting_variables(graph)) == {'a': 4}
diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -236,6 +236,8 @@
                 else:
                     insert_empty_block(link, llops)
 
+        self.postprocess_graph(graph)
+
         # remove the empty block at the start of the graph, which should
         # still be empty (but let's check)
         if starts_with_empty_block(graph) and inserted_empty_startblock:
@@ -252,6 +254,9 @@
         graph.exc_cleanup = (v, list(llops))
         return is_borrowed    # xxx for tests only
 
+    def postprocess_graph(self, graph):
+        pass
+
     def annotate_helper(self, ll_helper, ll_args, ll_result, inline=False):
         assert not self.finished_helpers
         args_s = map(lltype_to_annotation, ll_args)
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -513,6 +513,9 @@
     'gc_rawrefcount_from_obj':          LLOp(sideeffects=False),
     'gc_rawrefcount_to_obj':            LLOp(sideeffects=False),
 
+    'gc_push_roots'       : LLOp(),
+    'gc_pop_roots'        : LLOp(),
+
     # ------- JIT & GC interaction, only for some GCs ----------
 
     'gc_adr_of_nursery_free' : LLOp(),
diff --git a/rpython/tool/algo/test/test_regalloc.py b/rpython/tool/algo/test/test_regalloc.py
--- a/rpython/tool/algo/test/test_regalloc.py
+++ b/rpython/tool/algo/test/test_regalloc.py
@@ -57,4 +57,5 @@
         return b
     t, rtyper, graph = gengraph(f, [int, int], viewbefore=False)
     regalloc = perform_register_allocation(graph, is_int)
-    check_valid(graph, regalloc, is_int)
+    num_renamings = check_valid(graph, regalloc, is_int)
+    assert num_renamings == 2


More information about the pypy-commit mailing list