[pypy-svn] pypy default: (fijal, arigo)

arigo commits-noreply at bitbucket.org
Sat Mar 12 22:36:43 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r42539:0646aa086da7
Date: 2011-03-12 15:52 -0500
http://bitbucket.org/pypy/pypy/changeset/0646aa086da7/

Log:	(fijal, arigo)

	Improve on the previous check-in to detect fresh mallocs as long as
	they are in the same graph. That's probably good enough.

diff --git a/pypy/translator/backendopt/test/test_writeanalyze.py b/pypy/translator/backendopt/test/test_writeanalyze.py
--- a/pypy/translator/backendopt/test/test_writeanalyze.py
+++ b/pypy/translator/backendopt/test/test_writeanalyze.py
@@ -63,6 +63,69 @@
         result = wa.analyze_direct_call(fgraph)
         assert not result
 
+    def test_write_to_new_struct_2(self):
+        class A(object):
+            pass
+        def f(x):
+            a = A()
+            # a few extra blocks
+            i = 10
+            while i > 0:
+                i -= 1
+            # done
+            a.baz = x   # writes to a fresh new struct are ignored
+            return a
+        t, wa = self.translate(f, [int])
+        fgraph = graphof(t, f)
+        result = wa.analyze_direct_call(fgraph)
+        assert not result
+
+    def test_write_to_new_struct_3(self):
+        class A(object):
+            pass
+        prebuilt = A()
+        def f(x):
+            if x > 5:
+                a = A()
+            else:
+                a = A()
+            a.baz = x
+            return a
+        t, wa = self.translate(f, [int])
+        fgraph = graphof(t, f)
+        result = wa.analyze_direct_call(fgraph)
+        assert not result
+
+    def test_write_to_new_struct_4(self):
+        class A(object):
+            pass
+        prebuilt = A()
+        def f(x):
+            if x > 5:
+                a = A()
+            else:
+                a = prebuilt
+            a.baz = x
+            return a
+        t, wa = self.translate(f, [int])
+        fgraph = graphof(t, f)
+        result = wa.analyze_direct_call(fgraph)
+        assert len(result) == 1 and 'baz' in list(result)[0][-1]
+
+    def test_write_to_new_struct_5(self):
+        class A(object):
+            baz = 123
+        def f(x):
+            if x:
+                a = A()
+            else:
+                a = A()
+            a.baz += 1
+        t, wa = self.translate(f, [int])
+        fgraph = graphof(t, f)
+        result = wa.analyze_direct_call(fgraph)
+        assert not result
+
     def test_method(self):
         class A(object):
             def f(self):

diff --git a/pypy/translator/backendopt/writeanalyze.py b/pypy/translator/backendopt/writeanalyze.py
--- a/pypy/translator/backendopt/writeanalyze.py
+++ b/pypy/translator/backendopt/writeanalyze.py
@@ -1,3 +1,4 @@
+from pypy.objspace.flow.model import Variable
 from pypy.translator.backendopt import graphanalyze
 from pypy.rpython.ootypesystem import ootype
 
@@ -27,13 +28,13 @@
         return result is top_set
 
     def analyze_simple_operation(self, op, graphinfo):
-        if graphinfo and op.args[0] in graphinfo:
-            return empty_set
         if op.opname in ("setfield", "oosetfield"):
-            return frozenset([
-                ("struct", op.args[0].concretetype, op.args[1].value)])
+            if graphinfo is None or not graphinfo.is_fresh_malloc(op.args[0]):
+                return frozenset([
+                    ("struct", op.args[0].concretetype, op.args[1].value)])
         elif op.opname == "setarrayitem":
-            return self._array_result(op.args[0].concretetype)
+            if graphinfo is None or not graphinfo.is_fresh_malloc(op.args[0]):
+                return self._array_result(op.args[0].concretetype)
         return empty_set
 
     def _array_result(self, TYPE):
@@ -49,16 +50,43 @@
         return graphanalyze.GraphAnalyzer.analyze_external_method(self, op, TYPE, meth)
 
     def compute_graph_info(self, graph):
-        newstructs = set()
-        for block in graph.iterblocks():
+        return FreshMallocs(graph)
+
+
+class FreshMallocs(object):
+    def __init__(self, graph):
+        self.nonfresh = set(graph.getargs())
+        pendingblocks = list(graph.iterblocks())
+        self.allvariables = set()
+        for block in pendingblocks:
+            self.allvariables.update(block.inputargs)
+        pendingblocks.reverse()
+        while pendingblocks:
+            block = pendingblocks.pop()
             for op in block.operations:
+                self.allvariables.add(op.result)
                 if (op.opname == 'malloc' or op.opname == 'malloc_varsize'
                     or op.opname == 'new'):
-                    newstructs.add(op.result)
+                    continue
                 elif op.opname in ('cast_pointer', 'same_as'):
-                    if op.args[0] in newstructs:
-                        newstructs.add(op.result)
-        return newstructs
+                    if self.is_fresh_malloc(op.args[0]):
+                        continue
+                self.nonfresh.add(op.result)
+            for link in block.exits:
+                self.nonfresh.update(link.getextravars())
+                self.allvariables.update(link.getextravars())
+                prevlen = len(self.nonfresh)
+                for v1, v2 in zip(link.args, link.target.inputargs):
+                    if not self.is_fresh_malloc(v1):
+                        self.nonfresh.add(v2)
+                if len(self.nonfresh) > prevlen:
+                    pendingblocks.append(link.target)
+
+    def is_fresh_malloc(self, v):
+        if not isinstance(v, Variable):
+            return False
+        assert v in self.allvariables
+        return v not in self.nonfresh
 
 
 class ReadWriteAnalyzer(WriteAnalyzer):


More information about the Pypy-commit mailing list