Author: Armin Rigo <ar...@tunes.org> 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit