[pypy-svn] r20971 - in pypy/dist/pypy/translator/c: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Fri Dec 9 20:27:44 CET 2005


Author: cfbolz
Date: Fri Dec  9 20:27:43 2005
New Revision: 20971

Modified:
   pypy/dist/pypy/translator/c/gc.py
   pypy/dist/pypy/translator/c/test/test_backendoptimized.py
Log:
(johahn, cfbolz)
support __del__ in genc if using refcounting.


Modified: pypy/dist/pypy/translator/c/gc.py
==============================================================================
--- pypy/dist/pypy/translator/c/gc.py	(original)
+++ pypy/dist/pypy/translator/c/gc.py	Fri Dec  9 20:27:43 2005
@@ -84,6 +84,7 @@
 class RefcountingInfo:
     deallocator = None
     static_deallocator = None
+    destructor = None
 
 class RefcountingGcPolicy(BasicGcPolicy):
 
@@ -184,6 +185,10 @@
                 gcinfo.rtti_query_funcptr = db.get(fnptr)
                 T = typeOf(fnptr).TO.ARGS[0]
                 gcinfo.rtti_query_funcptr_argtype = db.gettype(T)
+                if hasattr(rtti._obj, 'destructor_funcptr'):
+                    destrptr = rtti._obj.destructor_funcptr
+                    gcinfo.destructor = db.get(destrptr)
+                    T = typeOf(destrptr).TO.ARGS[0]
             else:
                 # is a deallocator really needed, or would it be empty?
                 if list(self.deallocator_lines(structdefnode, '')):
@@ -198,14 +203,32 @@
     def struct_implementationcode(self, structdefnode):
         if structdefnode.gcinfo:
             gcinfo = structdefnode.gcinfo
-            if gcinfo.static_deallocator:
+            has_dynamic_deallocator = gcinfo.deallocator and gcinfo.deallocator != gcinfo.static_deallocator
+            if gcinfo.static_deallocator and not has_dynamic_deallocator:
                 yield 'void %s(struct %s *p) {' % (gcinfo.static_deallocator,
                                                structdefnode.name)
+                # insert decrefs to objects we have a reference to
                 for line in self.deallocator_lines(structdefnode, '(*p)'):
                     yield '\t' + line
                 yield '\tOP_FREE(p);'
                 yield '}'
-            if gcinfo.deallocator and gcinfo.deallocator != gcinfo.static_deallocator:
+            elif has_dynamic_deallocator:
+                # write static deallocator
+                yield 'void %s(struct %s *p) {' % (gcinfo.static_deallocator,
+                                               structdefnode.name)
+                # insert call to __del__ if necessary
+                if gcinfo.destructor:
+                    yield "\t%s((%s) p);" % (gcinfo.destructor,
+                                             cdecl(gcinfo.destructor_argtype, ''))
+                # insert decrefs to objects we have a reference to
+                yield '\tif (!--p->%s) {' % (structdefnode.gcheader,)
+                for line in self.deallocator_lines(structdefnode, '(*p)'):
+                    yield '\t\t' + line
+                yield '\t\tOP_FREE(p);'
+                yield '\t}'
+                yield '}'
+
+                # write dynamic deallocator
                 yield 'void %s(struct %s *p) {' % (gcinfo.deallocator, structdefnode.name)
                 yield '\tvoid (*staticdealloc) (void *);'
                 # the refcount should be 0; temporarily bump it to 1
@@ -214,8 +237,7 @@
                 yield '\tstaticdealloc = %s((%s) p);' % (
                     gcinfo.rtti_query_funcptr,
                     cdecl(gcinfo.rtti_query_funcptr_argtype, ''))
-                yield '\tif (!--p->%s)' % (structdefnode.gcheader,)
-                yield '\t\tstaticdealloc(p);'
+                yield '\tstaticdealloc(p);'
                 yield '}'
 
 

Modified: pypy/dist/pypy/translator/c/test/test_backendoptimized.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_backendoptimized.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_backendoptimized.py	Fri Dec  9 20:27:43 2005
@@ -7,6 +7,7 @@
 
     def process(self, t):
         _TestTypedTestCase.process(self, t)
+        self.t = t
         backend_optimizations(t)
 
     def test_remove_same_as(self):
@@ -18,3 +19,60 @@
         fn = self.getcompiled(f)
         assert f(True) == 123
         assert f(False) == 456
+
+    def test__del__(self):
+        import os
+        class B(object):
+            pass
+        b = B()
+        b.nextid = 0
+        b.num_deleted = 0
+        class A(object):
+            def __init__(self):
+                self.id = b.nextid
+                b.nextid += 1
+
+            def __del__(self):
+                b.num_deleted += 1
+
+        def f(x=int):
+            a = A()
+            for i in range(x):
+                a = A()
+            return b.num_deleted
+
+        fn = self.getcompiled(f)
+        res = f(5)
+        assert res == 5
+        res = fn(5)
+        # translated function looses its last reference earlier
+        assert res == 6
+    
+    def test_del_inheritance(self):
+        class State:
+            pass
+        s = State()
+        s.a_dels = 0
+        s.b_dels = 0
+        class A(object):
+            def __del__(self):
+                s.a_dels += 1
+        class B(A):
+            def __del__(self):
+                s.b_dels += 1
+        class C(A):
+            pass
+        def f():
+            A()
+            B()
+            C()
+            A()
+            B()
+            C()
+            return s.a_dels * 10 + s.b_dels
+        res = f()
+        assert res == 42
+        fn = self.getcompiled(f)
+        res = fn()
+        assert res == 42
+        



More information about the Pypy-commit mailing list