Author: Armin Rigo <[email protected]>
Branch:
Changeset: r78310:f24607693daa
Date: 2015-06-25 11:11 +0200
http://bitbucket.org/pypy/pypy/changeset/f24607693daa/
Log: Plug the logic from find_initializing_stores() to also detect and
remove duplicate write barrier calls done without any malloc()
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
@@ -52,21 +52,19 @@
return (op.opname in LL_OPERATIONS and
LL_OPERATIONS[op.opname].canmallocgc)
-def find_initializing_stores(collect_analyzer, graph):
- from rpython.flowspace.model import mkentrymap
- entrymap = mkentrymap(graph)
- # a bit of a hackish analysis: if a block contains a malloc and check that
- # the result is not zero, then the block following the True link will
- # usually initialize the newly allocated object
- result = set()
- def find_in_block(block, mallocvars):
+def propagate_no_write_barrier_needed(result, block, mallocvars,
+ collect_analyzer, entrymap):
+ # We definitely know that no write barrier is needed in the 'block'
+ # for any of the variables in 'mallocvars'. Propagate this information
+ # forward. Note that "definitely know" implies that we just did either
+ # a fixed-size malloc (variable-size might require card marking), or
+ # that we just did a full write barrier (not just for card marking).
+ if 1: # keep indentation
for i, op in enumerate(block.operations):
if op.opname in ("cast_pointer", "same_as"):
if op.args[0] in mallocvars:
mallocvars[op.result] = True
elif op.opname in ("setfield", "setarrayitem", "setinteriorfield"):
- # note that 'mallocvars' only tracks fixed-size mallocs,
- # so no risk that they use card marking
TYPE = op.args[-1].concretetype
if (op.args[0] in mallocvars and
isinstance(TYPE, lltype.Ptr) and
@@ -83,7 +81,15 @@
if var in mallocvars:
newmallocvars[exit.target.inputargs[i]] = True
if newmallocvars:
- find_in_block(exit.target, newmallocvars)
+ propagate_no_write_barrier_needed(result, exit.target,
+ newmallocvars,
+ collect_analyzer, entrymap)
+
+def find_initializing_stores(collect_analyzer, graph, entrymap):
+ # a bit of a hackish analysis: if a block contains a malloc and check that
+ # the result is not zero, then the block following the True link will
+ # usually initialize the newly allocated object
+ result = set()
mallocnum = 0
blockset = set(graph.iterblocks())
while blockset:
@@ -113,7 +119,8 @@
target = exit.target
mallocvars = {target.inputargs[index]: True}
mallocnum += 1
- find_in_block(target, mallocvars)
+ propagate_no_write_barrier_needed(result, target, mallocvars,
+ collect_analyzer, entrymap)
#if result:
# print "found %s initializing stores in %s" % (len(result), graph.name)
return result
@@ -698,8 +705,11 @@
" %s" % func)
if self.write_barrier_ptr:
+ from rpython.flowspace.model import mkentrymap
+ self._entrymap = mkentrymap(graph)
self.clean_sets = (
- find_initializing_stores(self.collect_analyzer, graph))
+ find_initializing_stores(self.collect_analyzer, graph,
+ self._entrymap))
if self.gcdata.gc.can_optimize_clean_setarrayitems():
self.clean_sets = self.clean_sets.union(
find_clean_setarrayitems(self.collect_analyzer, graph))
@@ -1269,6 +1279,15 @@
hop.genop("direct_call", [self.write_barrier_ptr,
self.c_const_gc,
v_structaddr])
+ # we just did a full write barrier here, so we can use
+ # this helper to propagate this knowledge forward and
+ # avoid to repeat the write barrier.
+ if self.curr_block is not None: # for tests
+ propagate_no_write_barrier_needed(self.clean_sets,
+ self.curr_block,
+ {v_struct: True},
+ self.collect_analyzer,
+ self._entrymap)
hop.rename('bare_' + opname)
def transform_getfield_typeptr(self, hop):
diff --git a/rpython/memory/gctransform/test/test_framework.py
b/rpython/memory/gctransform/test/test_framework.py
--- a/rpython/memory/gctransform/test/test_framework.py
+++ b/rpython/memory/gctransform/test/test_framework.py
@@ -1,6 +1,6 @@
from rpython.annotator.listdef import s_list_of_strings
from rpython.annotator.model import SomeInteger
-from rpython.flowspace.model import Constant, SpaceOperation
+from rpython.flowspace.model import Constant, SpaceOperation, mkentrymap
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.memory.gc.semispace import SemiSpaceGC
@@ -231,6 +231,33 @@
Constant('b', lltype.Void), varoftype(PTR_TYPE2)],
varoftype(lltype.Void)))
+def test_remove_duplicate_write_barrier():
+ from rpython.translator.c.genc import CStandaloneBuilder
+ from rpython.flowspace.model import summary
+
+ class A(object):
+ pass
+ glob_a_1 = A()
+ glob_a_2 = A()
+
+ def f(a, cond):
+ a.x = a
+ a.z = a
+ if cond:
+ a.y = a
+ def g():
+ f(glob_a_1, 5)
+ f(glob_a_2, 0)
+ t = rtype(g, [])
+ t.config.translation.gc = "minimark"
+ cbuild = CStandaloneBuilder(t, g, t.config,
+ gcpolicy=FrameworkGcPolicy2)
+ db = cbuild.generate_graphs_for_llinterp()
+
+ ff = graphof(t, f)
+ #ff.show()
+ assert summary(ff)['direct_call'] == 1 # only one remember_young_pointer
+
def test_find_initializing_stores():
class A(object):
@@ -246,7 +273,8 @@
etrafo = ExceptionTransformer(t)
graphs = etrafo.transform_completely()
collect_analyzer = CollectAnalyzer(t)
- init_stores = find_initializing_stores(collect_analyzer, t.graphs[0])
+ init_stores = find_initializing_stores(collect_analyzer, t.graphs[0],
+ mkentrymap(t.graphs[0]))
assert len(init_stores) == 1
def test_find_initializing_stores_across_blocks():
@@ -271,7 +299,8 @@
etrafo = ExceptionTransformer(t)
graphs = etrafo.transform_completely()
collect_analyzer = CollectAnalyzer(t)
- init_stores = find_initializing_stores(collect_analyzer, t.graphs[0])
+ init_stores = find_initializing_stores(collect_analyzer, t.graphs[0],
+ mkentrymap(t.graphs[0]))
assert len(init_stores) == 5
def test_find_clean_setarrayitems():
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
@@ -83,6 +83,7 @@
class BaseGCTransformer(object):
finished_helpers = False
+ curr_block = None
def __init__(self, translator, inline=False):
self.translator = translator
@@ -159,7 +160,7 @@
def transform_block(self, block, is_borrowed):
llops = LowLevelOpList()
- #self.curr_block = block
+ self.curr_block = block
self.livevars = [var for var in block.inputargs
if var_needsgc(var) and not is_borrowed(var)]
allvars = [var for var in block.getvariables() if var_needsgc(var)]
@@ -205,6 +206,7 @@
block.operations[:] = llops
self.livevars = None
self.var_last_needed_in = None
+ self.curr_block = None
def transform_graph(self, graph):
if graph in self.minimal_transform:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit