[pypy-commit] pypy stmgc-c8: Plug the logic from find_initializing_stores() to also detect and remove
arigo
noreply at buildbot.pypy.org
Thu Jun 25 22:47:32 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c8
Changeset: r78311:8043ab320b22
Date: 2015-06-25 11:11 +0200
http://bitbucket.org/pypy/pypy/changeset/8043ab320b22/
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,23 +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
if op.args[0] in mallocvars:
# Collect all assignments, even if they are not storing
# a pointer. This is needed for stmframework and doesn't
@@ -85,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:
@@ -115,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
@@ -713,8 +718,11 @@
" %s\n%s" % (func, err.getvalue()))
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))
@@ -1328,6 +1336,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
@@ -244,6 +244,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):
@@ -259,7 +286,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():
@@ -284,7 +312,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:
More information about the pypy-commit
mailing list