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

cfbolz at codespeak.net cfbolz at codespeak.net
Mon Feb 6 17:25:48 CET 2006


Author: cfbolz
Date: Mon Feb  6 17:25:46 2006
New Revision: 23075

Modified:
   pypy/dist/pypy/rpython/memory/gctransform.py
   pypy/dist/pypy/rpython/memory/test/test_gctransform.py
Log:
 * fix incref to not crash on NULL pointers
 * move the write barriers to the RefcountingGCTransformer, they are not needed
   for the general case
 * same for the static_deallocator
 * write a function that generates the graph for decrefs: so far only for
   arrays


Modified: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform.py	Mon Feb  6 17:25:46 2006
@@ -2,7 +2,9 @@
 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, \
      c_last_exception, FunctionGraph, Block, Link, checkgraph
 from pypy.translator.unsimplify import insert_empty_block
-from pypy.rpython import rmodel
+from pypy.translator.translator import graphof
+from pypy.annotation import model as annmodel
+from pypy.rpython import rmodel, objectmodel
 from pypy.rpython.memory import gc
 import sets
 
@@ -44,7 +46,7 @@
         return True
     
 
-class GCTransformer:
+class GCTransformer(object):
     def __init__(self, translator):
         self.translator = translator
         self.seen_graphs = {}
@@ -140,30 +142,6 @@
         else:
             return [op]
 
-    def replace_setfield(self, op):
-        if not var_needsgc(op.args[2]):
-            return [op]
-        oldval = Variable()
-        oldval.concretetype = op.args[2].concretetype
-        getoldvalop = SpaceOperation("getfield", [op.args[0], op.args[1]], oldval)
-        result = [getoldvalop]
-        result.extend(self.pop_alive(oldval))
-        result.extend(self.push_alive(op.args[2]))
-        result.append(op)
-        return result
-
-    def replace_setarrayitem(self, op):
-        if not var_needsgc(op.args[2]):
-            return [op]
-        oldval = Variable()
-        oldval.concretetype = op.args[2].concretetype
-        getoldvalop = SpaceOperation("getarrayitem",
-                                     [op.args[0], op.args[1]], oldval)
-        result = [getoldvalop]
-        result.extend(self.pop_alive(oldval))
-        result.extend(self.push_alive(op.args[2]))
-        result.append(op)
-        return result
 
     def push_alive(self, var):
         if var_ispyobj(var):
@@ -205,6 +183,59 @@
 
     # ----------------------------------------------------------------
 
+
+class RefcountingGCTransformer(GCTransformer):
+
+    gc_header_offset = gc.GCHeaderOffset(lltype.Struct("header", ("refcount", lltype.Signed)))
+
+    def __init__(self, translator):
+        super(RefcountingGCTransformer, self).__init__(translator)
+        # create incref graph
+        def incref(adr):
+            if adr:
+                gcheader = adr - RefcountingGCTransformer.gc_header_offset
+                gcheader.signed[0] = gcheader.signed[0] + 1
+        self.increfgraph = self.translator.rtyper.annotate_helper(
+            incref, [annmodel.SomeAddress()])
+        self.translator.rtyper.specialize_more_blocks()
+        self.increfptr = const_funcptr_fromgraph(self.increfgraph)
+        self.seen_graphs[self.increfgraph] = True
+        # cache graphs:
+        self.decref_graphs = {}
+        self.static_deallocator_graphs = {}
+
+    def push_alive_nopyobj(self, var):
+        adr1 = varoftype(llmemory.Address)
+        result = [SpaceOperation("cast_ptr_to_adr", [var], adr1)]
+        result.append(SpaceOperation("direct_call", [self.increfptr, adr1],
+                                     varoftype(lltype.Void)))
+        return result
+
+    def replace_setfield(self, op):
+        if not var_needsgc(op.args[2]):
+            return [op]
+        oldval = Variable()
+        oldval.concretetype = op.args[2].concretetype
+        getoldvalop = SpaceOperation("getfield", [op.args[0], op.args[1]], oldval)
+        result = [getoldvalop]
+        result.extend(self.pop_alive(oldval))
+        result.extend(self.push_alive(op.args[2]))
+        result.append(op)
+        return result
+
+    def replace_setarrayitem(self, op):
+        if not var_needsgc(op.args[2]):
+            return [op]
+        oldval = Variable()
+        oldval.concretetype = op.args[2].concretetype
+        getoldvalop = SpaceOperation("getarrayitem",
+                                     [op.args[0], op.args[1]], oldval)
+        result = [getoldvalop]
+        result.extend(self.pop_alive(oldval))
+        result.extend(self.push_alive(op.args[2]))
+        result.append(op)
+        return result
+
     def _static_deallocator_body_for_type(self, v, TYPE, depth=1):
         if isinstance(TYPE, lltype.Array):
             
@@ -229,6 +260,8 @@
             yield '    '*depth + 'pop_alive(%s)'%v
 
     def static_deallocation_graph_for_type(self, TYPE):
+        if TYPE in self.static_deallocator_graphs:
+            return self.static_deallocator_graphs[TYPE]
         def compute_pop_alive_ll_ops(hop):
             hop.llops.extend(self.pop_alive(hop.args_v[1]))
             return hop.inputconst(hop.r_result.lowleveltype, hop.s_result.const)
@@ -276,35 +309,49 @@
         for block in g.iterblocks():
             opcount += len(block.operations)
         if opcount == 0:
+            self.static_deallocator_graphs[TYPE] = None
             return None
         else:
+            self.static_deallocator_graphs[TYPE] = g
             return g
+            
 
-class RefcountingGCTransformer(GCTransformer):
-
-    gc_header_offset = gc.GCHeaderOffset(lltype.Struct("header", ("refcount", lltype.Signed)))
-    
-    def push_alive_nopyobj(self, var):
-        adr1 = varoftype(llmemory.Address)
-        result = [SpaceOperation("cast_ptr_to_adr", [var], adr1)]
-        adr2 = varoftype(llmemory.Address)
-        offset = rmodel.inputconst(lltype.Signed, self.gc_header_offset)
-        result.append(SpaceOperation("adr_sub", [adr1, offset], adr2))
-        zero = rmodel.inputconst(lltype.Signed, 0)
-        intconst = rmodel.inputconst(lltype.Void, int)
-        refcount = varoftype(lltype.Signed)
-        result.append(SpaceOperation("raw_load", [adr2, intconst, zero], refcount))
-        newrefcount = varoftype(lltype.Signed)
-        result.append(SpaceOperation("int_add",
-                                     [refcount, rmodel.inputconst(lltype.Signed, 1)],
-                                     newrefcount))
-        result.append(SpaceOperation("raw_store",
-                                     [adr2, intconst, zero, newrefcount],
-                                     varoftype(lltype.Void)))
-        return result
-
+    def decref_graph_for_type(self, TYPE):
+        if TYPE in self.decref_graphs:
+            return self.decref_graphs[TYPE]
+        if isinstance(TYPE, lltype.GcArray):
+            graph = self.static_deallocation_graph_for_type(TYPE)
+            def compute_destructor_ll_ops(hop):
+                assert hop.args_v[1].concretetype.TO == TYPE
+                return hop.genop("direct_call",
+                                 [const_funcptr_fromgraph(graph), hop.args_v[1]],
+                                 resulttype=lltype.Void)
+            def destructor(var):
+                pass
+            destructor.compute_ll_ops = compute_destructor_ll_ops
+            destructor.llresult = lltype.Void
+            def decref(array):
+                arrayadr = objectmodel.cast_ptr_to_adr(array)
+                gcheader = arrayadr - RefcountingGCTransformer.gc_header_offset
+                refcount = gcheader.signed[0] - 1
+                gcheader.signed[0] = refcount
+                if refcount == 0:
+                    destructor(array)
+            g = self.translator.rtyper.annotate_helper(decref, [lltype.Ptr(TYPE)])
+            self.translator.rtyper.specialize_more_blocks()
+            # the produced deallocator graph does not need to be transformed
+            self.seen_graphs[g] = True
+            self.decref_graphs[TYPE] = g
+            return g
 
 def varoftype(concretetype):
     var = Variable()
     var.concretetype = concretetype
     return var
+
+def const_funcptr_fromgraph(graph):
+    FUNC = lltype.FuncType([v.concretetype for v in graph.startblock.inputargs],
+                           graph.returnblock.inputargs[0].concretetype)
+    return rmodel.inputconst(lltype.Ptr(FUNC),
+                             lltype.functionptr(FUNC, graph.name, graph=graph))
+

Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_gctransform.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py	Mon Feb  6 17:25:46 2006
@@ -260,7 +260,8 @@
         c.x = 1
         return c.x
     t = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False)
-
+    ops = getops(graphof(t, f))
+    assert len(ops['direct_call']) == 2
 
   
 # ______________________________________________________________________
@@ -278,7 +279,7 @@
         t.s = s1
         t.s = s2
         return t
-    t = rtype_and_transform(f, [], gctransform.GCTransformer)
+    t = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False)
     graph = graphof(t, f)
     ops = getops(graph)
     assert len(ops['getfield']) == 2
@@ -295,7 +296,7 @@
         a = lltype.malloc(A, 1)
         a[0] = s1
         a[0] = s2
-    t = rtype_and_transform(f, [], gctransform.GCTransformer)
+    t = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False)
     graph = graphof(t, f)
     ops = getops(graph)
     assert len(ops['getarrayitem']) == 2
@@ -306,14 +307,14 @@
 # ----------------------------------------------------------------------
 # test deallocators
 
-def make_deallocator(TYPE):
+def make_deallocator(TYPE, attr="static_deallocation_graph_for_type"):
     def f():
         pass
     t = TranslationContext()
     t.buildannotator().build_types(f, [])
     t.buildrtyper().specialize(t)
-    transformer = gctransform.GCTransformer(t)
-    graph = transformer.static_deallocation_graph_for_type(TYPE)
+    transformer = gctransform.RefcountingGCTransformer(t)
+    graph = getattr(transformer, attr)(TYPE)
     if conftest.option.view:
         t.view()
     return graph
@@ -356,6 +357,12 @@
     assert len(ops['getarraysubstruct']) == 1
     assert len(ops['gc_free']) == 1
 
+def test_decref_array():
+    TPtr = lltype.Ptr(lltype.GcStruct("T", ('a', lltype.Signed)))
+    GcA = lltype.GcArray(('x', TPtr), ('y', TPtr))
+    dgraph = make_deallocator(GcA, attr="decref_graph_for_type")
+    ops = getops(dgraph)
+
 def test_deallocator_with_destructor():
     S = lltype.GcStruct("S", ('x', lltype.Signed))
     def f(s):



More information about the Pypy-commit mailing list