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

mwh at codespeak.net mwh at codespeak.net
Wed Jan 25 18:25:53 CET 2006


Author: mwh
Date: Wed Jan 25 18:25:51 2006
New Revision: 22661

Added:
   pypy/dist/pypy/rpython/memory/gctransform.py   (contents, props changed)
   pypy/dist/pypy/rpython/memory/test/test_gctransform.py   (contents, props changed)
Log:
(cfbolz, mwh)
A start at a gctransformer that transforms l2 graphs, inserting
(at least potentially) the operations needed by the GC.  Some
over complicated tests.


Added: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/memory/gctransform.py	Wed Jan 25 18:25:51 2006
@@ -0,0 +1,91 @@
+from pypy.rpython.lltypesystem import lltype
+from pypy.objspace.flow.model import SpaceOperation, Variable
+from pypy.translator.unsimplify import insert_empty_block
+import sets
+
+"""
+thought experiments
+
+'setfield' obj field value ->
+  a1 <- 'cast_ptr_to_adr' obj
+  a2 <- 'cast_ptr_to_adr' value
+  'direct_call' write_barrier a1, offset(TYPE(obj), field), a2
+
+operations that need hooks:
+
+setfield, setarrayitem, direct_call, indirect_call, malloc, getfield,
+getarrayitem, getsubstruct?
+
+push_alive, pop_alive,
+
+"""
+
+def var_needsgc(var):
+    vartype = var.concretetype
+    return isinstance(vartype, lltype.Ptr) and vartype._needsgc()
+
+class GCTransformer:
+    def __init__(self, graphs):
+        self.graphs = graphs
+
+    def transform(self):
+        for graph in self.graphs:
+            self.transform_graph(graph)
+
+    def transform_graph(self, graph):
+        self.links_to_split = {} # link -> vars to pop_alive across the link
+        for block in graph.iterblocks():
+            self.transform_block(block)
+        for link, vars in self.links_to_split.iteritems():
+            newops = []
+            for var in vars:
+                newops.extend(self.pop_alive(var))
+            insert_empty_block(None, link, newops)
+
+    def transform_block(self, block):
+        newops = []
+        livevars = [var for var in block.inputargs if var_needsgc(var)]
+        for op in block.operations:
+            newops.extend(self.replacement_operations(op))
+            if var_needsgc(op.result):
+                if op.opname not in ('direct_call', 'indirect_call'):
+                    newops.extend(self.push_alive(op.result))
+                livevars.append(op.result)
+        if len(block.exits) == 0:
+            # everything is fine already for returnblocks and exceptblocks
+            pass
+        elif len(block.exits) == 1:
+            for var in livevars:
+                if var not in block.exits[0].args:
+                    newops.extend(self.pop_alive(var))
+        else:
+            deadinallexits = sets.Set(livevars)
+            for link in block.exits:
+                deadinallexits.difference_update(sets.Set(link.args))
+            for var in deadinallexits:
+                newops.extend(self.pop_alive(var))
+            for link in block.exits:
+                deadvarsforlink = sets.Set(livevars) - deadinallexits - sets.Set(link.args)
+                if deadvarsforlink:
+                    self.links_to_split[link] = deadvarsforlink
+        if newops:
+            block.operations = newops
+
+    def replacement_operations(self, op):
+        m = getattr(self, 'replace_' + op.opname, None)
+        if m:
+            return m(op)
+        else:
+            return [op]
+
+    def push_alive(self, var):
+        result = Variable()
+        result.concretetype = lltype.Void
+        return [SpaceOperation("push_alive", [var], result)]
+
+    def pop_alive(self, var):
+        result = Variable()
+        result.concretetype = lltype.Void
+        return [SpaceOperation("pop_alive", [var], result)]
+
+    

Added: pypy/dist/pypy/rpython/memory/test/test_gctransform.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py	Wed Jan 25 18:25:51 2006
@@ -0,0 +1,91 @@
+from pypy.rpython.memory import gctransform
+from pypy.translator.translator import TranslationContext, graphof
+from pypy.rpython.lltypesystem import lltype
+
+def rtype_and_transform(func, inputtypes, transformcls):
+    t = TranslationContext()
+    t.buildannotator().build_types(func, inputtypes)
+    t.buildrtyper().specialize(t)
+    transformer = transformcls(t.graphs)
+    transformer.transform()
+    t.checkgraphs()
+    return t
+
+def test_simple():
+    def f():
+        return 1
+    rtype_and_transform(f, [], gctransform.GCTransformer)
+
+def test_fairly_simple():
+    class C:
+        pass
+    def f():
+        c = C()
+        c.x = 1
+        return c.x
+    t = rtype_and_transform(f, [], gctransform.GCTransformer)
+
+def test_return_gcpointer():
+    class C:
+        pass
+    def f():
+        c = C()
+        c.x = 1
+        return c
+    t = rtype_and_transform(f, [], gctransform.GCTransformer)
+    
+def test_call_function():
+    class C:
+        pass
+    def f():
+        c = C()
+        c.x = 1
+        return c
+    def g():
+        return f().x
+    t = rtype_and_transform(g, [], gctransform.GCTransformer)
+    ggraph = graphof(t, g)
+    for i, op in enumerate(ggraph.startblock.operations):
+        if op.opname == "direct_call":
+            break
+    else:
+        assert False, "direct_call not found!"
+    assert ggraph.startblock.operations[i + 1].opname != 'push_alive'
+
+def test_multiple_exits():
+    S = lltype.GcStruct("S", ('x', lltype.Signed))
+    T = lltype.GcStruct("T", ('y', lltype.Signed))
+    def f(n):
+        c = lltype.malloc(S)
+        d = lltype.malloc(T)
+        e = lltype.malloc(T)
+        if n:
+            x = d
+        else:
+            x = e
+        return x
+    t = rtype_and_transform(f, [int], gctransform.GCTransformer)
+    fgraph = graphof(t, f)
+    from pypy.translator.backendopt.ssa import SSI_to_SSA
+    SSI_to_SSA(fgraph) # *cough*
+    #t.view()
+    pop_alive_count = 0
+    for i, op in enumerate(fgraph.startblock.operations):
+        if op.opname == "pop_alive":
+            var, = op.args
+            assert var.concretetype == lltype.Ptr(S)
+            pop_alive_count += 1
+    
+    assert pop_alive_count == 1, "pop_alive not found!"
+    for link in fgraph.startblock.exits:
+        assert len(link.args) == 2
+        ops = link.target.operations
+        assert len(ops) == 1
+        assert ops[0].opname == 'pop_alive'
+        assert len(ops[0].args) == len(link.target.exits) == \
+               len(link.target.exits[0].args) == 1
+        dyingname = ops[0].args[0].name
+        passedname = link.target.exits[0].args[0].name
+        assert dyingname != passedname
+    
+        



More information about the Pypy-commit mailing list