[pypy-svn] r25931 - in pypy/dist/pypy/translator/backendopt: . test

arigo at codespeak.net arigo at codespeak.net
Tue Apr 18 10:36:39 CEST 2006


Author: arigo
Date: Tue Apr 18 10:36:37 2006
New Revision: 25931

Modified:
   pypy/dist/pypy/translator/backendopt/malloc.py
   pypy/dist/pypy/translator/backendopt/test/test_malloc.py
Log:
A test that shows a situation where malloc removal needs an
extra 'keepalive' to be valid.  Fix.


Modified: pypy/dist/pypy/translator/backendopt/malloc.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/malloc.py	(original)
+++ pypy/dist/pypy/translator/backendopt/malloc.py	Tue Apr 18 10:36:37 2006
@@ -153,11 +153,12 @@
 
     for block, vars in variables_by_block.items():
 
-        def flowin(var, newvarsmap):
+        def flowin(var, newvarsmap, insert_keepalive=False):
             # in this 'block', follow where the 'var' goes to and replace
             # it by a flattened-out family of variables.  This family is given
             # by newvarsmap, whose keys are the 'flatnames'.
             vars = {var: True}
+            last_removed_access = None
 
             def list_newvars():
                 return [newvarsmap[key] for key in flatnames]
@@ -175,11 +176,13 @@
                                                [newvarsmap[S, fldname]],
                                                op.result)
                         newops.append(newop)
+                        last_removed_access = len(newops)
                     elif op.opname == "setfield":
                         S = op.args[0].concretetype.TO
                         fldname = op.args[1].value
                         assert (S, fldname) in newvarsmap
                         newvarsmap[S, fldname] = op.args[2]
+                        last_removed_access = len(newops)
                     elif op.opname in ("same_as", "cast_pointer"):
                         assert op.result not in vars
                         vars[op.result] = True
@@ -188,7 +191,7 @@
                         # flattened list of variables for both, as a "setfield"
                         # via one pointer must be reflected in the other.
                     elif op.opname == 'keepalive':
-                        pass
+                        last_removed_access = len(newops)
                     else:
                         raise AssertionError, op.opname
                 elif op.result in vars:
@@ -198,7 +201,7 @@
                     # drop the "malloc" operation
                 else:
                     newops.append(op)
-            block.operations[:] = newops
+
             assert block.exitswitch not in vars
 
             for link in block.exits:
@@ -206,10 +209,24 @@
                 for arg in link.args:
                     if arg in vars:
                         newargs += list_newvars()
+                        insert_keepalive = False   # kept alive by the link
                     else:
                         newargs.append(arg)
                 link.args[:] = newargs
 
+            if insert_keepalive and last_removed_access is not None:
+                keepalives = []
+                for v in list_newvars():
+                    T = v.concretetype
+                    if isinstance(T, lltype.Ptr) and T._needsgc():
+                        v0 = Variable()
+                        v0.concretetype = lltype.Void
+                        newop = SpaceOperation('keepalive', [v], v0)
+                        keepalives.append(newop)
+                newops[last_removed_access:last_removed_access] = keepalives
+
+            block.operations[:] = newops
+
         # look for variables arriving from outside the block
         for var in vars:
             if var in block.inputargs:
@@ -224,7 +241,7 @@
                 newinputargs += block.inputargs[i+1:]
                 block.inputargs[:] = newinputargs
                 assert var not in block.inputargs
-                flowin(var, newvarsmap)
+                flowin(var, newvarsmap, insert_keepalive=True)
 
         # look for variables created inside the block by a malloc
         vars_created_here = []

Modified: pypy/dist/pypy/translator/backendopt/test/test_malloc.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_malloc.py	(original)
+++ pypy/dist/pypy/translator/backendopt/test/test_malloc.py	Tue Apr 18 10:36:37 2006
@@ -3,6 +3,7 @@
 from pypy.translator.backendopt.inline import inline_function
 from pypy.translator.backendopt.all import backend_optimizations
 from pypy.translator.translator import TranslationContext, graphof
+from pypy.translator import simplify
 from pypy.objspace.flow.model import checkgraph, flatten, Block
 from pypy.rpython.llinterp import LLInterpreter
 from pypy.conftest import option
@@ -28,6 +29,8 @@
     if option.view:
         t.view()
     remove_simple_mallocs(graph)
+    # to detect missing keepalives:
+    simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks()))
     if option.view:
         t.view()
     if must_be_removed:
@@ -146,3 +149,33 @@
     op = graph.startblock.exits[0].target.exits[1].target.operations[0]
     assert op.opname == "malloc"
 
+def test_add_keepalives():
+    from pypy.rpython.lltypesystem import lltype
+    class A:
+        pass
+    SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
+    BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
+    def fn7(i):
+        big = lltype.malloc(BIG)
+        a = A()
+        a.big = big
+        a.small = big.s
+        while i > 0:
+            a.small.x += i
+            i -= 1
+        return a.small.x
+    check(fn7, [int], [10], 55, must_be_removed=False)
+
+def test_getsubstruct():
+    py.test.skip("in-progress")
+    from pypy.rpython.lltypesystem import lltype
+    SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
+    BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
+
+    def fn(n1, n2):
+        b = lltype.malloc(BIG)
+        b.z = n1
+        b.s.x = n2
+        return b.z - b.s.x
+
+    check(fn, [int, int], [100, 58], 42)



More information about the Pypy-commit mailing list