[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