[pypy-svn] r47815 - in pypy/dist/pypy/rpython/memory/gctransform: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Wed Oct 24 13:15:38 CEST 2007


Author: cfbolz
Date: Wed Oct 24 13:15:37 2007
New Revision: 47815

Modified:
   pypy/dist/pypy/rpython/memory/gctransform/framework.py
   pypy/dist/pypy/rpython/memory/gctransform/test/test_framework.py
   pypy/dist/pypy/rpython/memory/gctransform/test/test_transform.py
Log:
a small heuristic to find initializing stores (basically stores that happen
directly after mallocs without any operation in between that can cause a
malloc). Those stores don't need a write barrier for the generational GC.


Modified: pypy/dist/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/framework.py	Wed Oct 24 13:15:37 2007
@@ -28,6 +28,64 @@
             flags = op.args[1].value
             return flags['flavor'] == 'gc' and not flags.get('nocollect', False)
 
+def find_initializing_stores(collect_analyzer, graph):
+    from pypy.objspace.flow.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 = {}
+    def find_in_block(block, mallocvars):
+        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"):
+                if (op.args[0] in mallocvars and
+                    op.args[-1].concretetype.TO._gckind == "gc"):
+                    result[op] = True
+            else:
+                if collect_analyzer.analyze(op):
+                    return
+        for exit in block.exits:
+            if len(entrymap[exit.target]) != 1:
+                continue
+            newmallocvars = {}
+            for i, var in enumerate(exit.args):
+                if var in mallocvars:
+                    newmallocvars[exit.target.inputargs[i]] = True
+            if newmallocvars:
+                find_in_block(exit.target, newmallocvars)
+    mallocnum = 0
+    blockset = set(graph.iterblocks())
+    while blockset:
+        block = blockset.pop()
+        if len(block.operations) < 2:
+            continue
+        mallocop = block.operations[-2]
+        checkop = block.operations[-1]
+        if not (mallocop.opname == "malloc" and
+                checkop.opname == "ptr_nonzero" and
+                mallocop.result is checkop.args[0] and
+                block.exitswitch is checkop.result):
+            continue
+        exits = [exit for exit in block.exits if exit.llexitcase]
+        if len(exits) != 1:
+            continue
+        exit = exits[0]
+        if len(entrymap[exit.target]) != 1:
+            continue
+        try:
+            index = exit.args.index(mallocop.result)
+        except ValueError:
+            continue
+        target = exit.target
+        mallocvars = {target.inputargs[index]: True}
+        mallocnum += 1
+        find_in_block(target, mallocvars)
+    print graph.name, mallocnum, len(result)
+    return result
+
 ADDRESS_VOID_FUNC = lltype.FuncType([llmemory.Address], lltype.Void)
 
 class FrameworkGCTransformer(GCTransformer):
@@ -439,6 +497,14 @@
         for typeid, TYPE in all:
             f.write("%s %s\n" % (typeid, TYPE))
 
+    def transform_graph(self, graph):
+        if self.write_barrier_ptr:
+            self.initializing_stores = find_initializing_stores(
+                self.collect_analyzer, graph)
+        super(FrameworkGCTransformer, self).transform_graph(graph)
+        if self.write_barrier_ptr:
+            self.initializing_stores = None
+
     def gct_direct_call(self, hop):
         if self.collect_analyzer.analyze(hop.spaceop):
             livevars = self.push_roots(hop)
@@ -603,7 +669,8 @@
         # ok
         if (self.write_barrier_ptr is not None
             and not isinstance(v_newvalue, Constant)
-            and v_struct.concretetype.TO._gckind == "gc"):
+            and v_struct.concretetype.TO._gckind == "gc"
+            and hop.spaceop not in self.initializing_stores):
             self.write_barrier_calls += 1
             v_oldvalue = hop.genop('g' + opname[1:],
                                    hop.inputargs()[:-1],

Modified: pypy/dist/pypy/rpython/memory/gctransform/test/test_framework.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/test/test_framework.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/test/test_framework.py	Wed Oct 24 13:15:37 2007
@@ -1,14 +1,17 @@
 from pypy.objspace.flow.model import Constant, SpaceOperation
 from pypy.annotation.model import SomeInteger
 from pypy.rpython.memory.gc.marksweep import MarkSweepGC
-from pypy.rpython.memory.gctransform.test.test_transform import rtype
+from pypy.rpython.memory.gctransform.test.test_transform import rtype, \
+    rtype_and_transform
 from pypy.rpython.memory.gctransform.transform import GcHighLevelOp
-from pypy.rpython.memory.gctransform.framework import FrameworkGCTransformer, CollectAnalyzer
+from pypy.rpython.memory.gctransform.framework import FrameworkGCTransformer, \
+    CollectAnalyzer, find_initializing_stores
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.rtyper import LowLevelOpList
 from pypy.translator.c.gc import FrameworkGcPolicy
 from pypy.translator.translator import TranslationContext, graphof
 from pypy.translator.unsimplify import varoftype
+from pypy.translator.exceptiontransform import ExceptionTransformer
 from pypy import conftest
 
 import py
@@ -119,3 +122,45 @@
         [varoftype(ARRAYPTR2), varoftype(lltype.Signed),
          Constant('b', lltype.Void), varoftype(PTR_TYPE2)],
         varoftype(lltype.Void)))
+
+def test_find_initializing_stores():
+
+    class A(object):
+        pass
+    class B(object):
+        pass
+    def f():
+        a = A()
+        b = B()
+        b.a = a
+    t = rtype(f, [])
+    etrafo = ExceptionTransformer(t)
+    graphs = etrafo.transform_completely()
+    collect_analyzer = CollectAnalyzer(t)
+    init_stores = find_initializing_stores(collect_analyzer, t.graphs[0])
+    assert len(init_stores) == 1
+
+def test_find_initializing_stores_across_blocks():
+
+    class A(object):
+        pass
+    class B(object):
+        pass
+    def f(x):
+        a1 = A()
+        a2 = A()
+        a = A()
+        b = B()
+        b.a = a
+        if x:
+            b.b = a1
+            b.c = a2
+        else:
+            b.c = a1
+            b.b = a2
+    t = rtype(f, [int])
+    etrafo = ExceptionTransformer(t)
+    graphs = etrafo.transform_completely()
+    collect_analyzer = CollectAnalyzer(t)
+    init_stores = find_initializing_stores(collect_analyzer, t.graphs[0])
+    assert len(init_stores) == 5

Modified: pypy/dist/pypy/rpython/memory/gctransform/test/test_transform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/test/test_transform.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/test/test_transform.py	Wed Oct 24 13:15:37 2007
@@ -149,6 +149,8 @@
     t.buildannotator().build_types(func, inputtypes)
     if specialize:
         t.buildrtyper().specialize()
+    if conftest.option.view:
+        t.view()
     return t    
 
 def rtype_and_transform(func, inputtypes, transformcls, specialize=True, check=True):



More information about the Pypy-commit mailing list