[pypy-svn] r47026 - in pypy/dist/pypy: rpython rpython/lltypesystem/test rpython/memory/gctransform translator/c translator/c/src

arigo at codespeak.net arigo at codespeak.net
Sat Sep 29 19:31:18 CEST 2007


Author: arigo
Date: Sat Sep 29 19:31:17 2007
New Revision: 47026

Modified:
   pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py
   pypy/dist/pypy/rpython/memory/gctransform/refcounting.py
   pypy/dist/pypy/rpython/rcpy.py
   pypy/dist/pypy/translator/c/funcgen.py
   pypy/dist/pypy/translator/c/src/mem.h
Log:
Support Python subclasses of types created by the extension compiler.

Don't think I'm actively developping the extension compiler - I was
fixing the failures in test_rcpyclass and I was forced to do the
right thing :-)


Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py	Sat Sep 29 19:31:17 2007
@@ -14,7 +14,7 @@
         return self.x * 2
 
 
-mytest = CPyTypeInterface('mytest', {})
+mytest = CPyTypeInterface('mytest', {}, subclassable=True)
 
 def test_cpy_export():
     def f():
@@ -22,7 +22,8 @@
         return cpy_export(mytest, w)
 
     fn = compile(f, [])
-    res = fn(expected_extra_mallocs=1)
+    res = fn()            # the W_MyTest is allocated with the CPython logic,
+                          # so it doesn't count in expected_extra_mallocs
     assert type(res).__name__ == 'mytest'
 
 
@@ -76,17 +77,17 @@
         return cpy_export(mytest, w), total
 
     fn = compile(f, [object])
-    obj, total = fn(None, expected_extra_mallocs=2) # 1 W_MyTest (with 1 tuple)
+    obj, total = fn(None, expected_extra_mallocs=1) # 1 tuple in w.stuff
     assert total == 1
-    obj, total = fn(obj, expected_extra_mallocs=4)  # 2 W_MyTests alive
-    assert total == 3
-    obj, total = fn(obj, expected_extra_mallocs=4)  # 2 W_MyTests alive
+    obj, total = fn(obj, expected_extra_mallocs=2)  # 2 tuples: old obj.stuff
+    assert total == 3                               #         + new obj.stuff
+    obj, total = fn(obj, expected_extra_mallocs=2)
     assert total == 6
-    obj, total = fn(obj, expected_extra_mallocs=4)  # etc
+    obj, total = fn(obj, expected_extra_mallocs=2)  # idem
     assert total == 10
-    obj, total = fn(obj, expected_extra_mallocs=4)
+    obj, total = fn(obj, expected_extra_mallocs=2)
     assert total == 15
-    obj, total = fn(obj, expected_extra_mallocs=4)
+    obj, total = fn(obj, expected_extra_mallocs=2)
     assert total == 21
 
 
@@ -100,32 +101,32 @@
         return cpy_export(mytest, w), w.x
 
     fn = compile(f, [object])
-    obj, x = fn(None, expected_extra_mallocs=1) # 1 W_MyTest
+    obj, x = fn(None)
     assert x == 22
 
     obj2 = type(obj)()
     del obj
-    obj, x = fn(obj2, expected_extra_mallocs=1) # 1 W_MyTest (obj2)
+    obj, x = fn(obj2)
     assert obj is obj2
     assert x == 601     # 600 is the class default of W_MyTest.x
 
 
 def test_subclass_from_cpython():
-    import py; py.test.skip("not implemented (see comments in rcpy.py)")
-
     def f(input):
         current = total = 10
         if input:
             w = cpy_import(W_MyTest, input)
-            current, total = w.stuff
+            current = w.current    # or 0 if left uninitialized, as by U()
+            total = w.total        # or 0 if left uninitialized, as by U()
         w = W_MyTest(21)
         current += 1
         total += current
-        w.stuff = current, total
+        w.current = current
+        w.total = total
         return cpy_export(mytest, w), total
 
     fn = compile(f, [object])
-    obj, total = fn(None, expected_extra_mallocs=2) # 1 W_MyTest (with 1 tuple)
+    obj, total = fn(None)
     assert total == 21
     T = type(obj)
     class U(T):
@@ -136,11 +137,11 @@
     del obj
 
     objlist = [U() for i in range(100)]
-    obj, total = fn(obj2, expected_extra_mallocs=204) # 102 W_MyTests alive
+    obj, total = fn(obj2)
     assert total == 1
 
     del objlist
-    obj, total = fn(obj, expected_extra_mallocs=6) # 3 W_MyTests alive
+    obj, total = fn(obj)
     assert total == 3
 
 
@@ -151,7 +152,7 @@
         return cpy_export(mytest2, w)
 
     fn = compile(f, [])
-    obj = fn(expected_extra_mallocs=1)
+    obj = fn()
     assert obj.hi == 123
     assert type(obj).hi == 123
 
@@ -164,7 +165,7 @@
         return cpy_export(mytest2, w)
 
     fn = compile(f, [])
-    obj = fn(expected_extra_mallocs=1)
+    obj = fn()
     assert obj.hi == 123
     assert type(obj).hi == 123
     assert obj.there == "foo"

Modified: pypy/dist/pypy/rpython/memory/gctransform/refcounting.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/refcounting.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/refcounting.py	Sat Sep 29 19:31:17 2007
@@ -69,6 +69,8 @@
                     gcheader.refcount = refcount
         def ll_no_pointer_dealloc(adr):
             llop.gc_free(lltype.Void, adr)
+        def ll_no_pointer_cpydealloc(adr):
+            llop.cpy_free(lltype.Void, adr)
 
         mh = mallocHelpers()
         mh.allocate = lladdress.raw_malloc
@@ -102,6 +104,8 @@
                 ll_decref_simple, [llmemory.Address], lltype.Void)
             self.no_pointer_dealloc_ptr = self.inittime_helper(
                 ll_no_pointer_dealloc, [llmemory.Address], lltype.Void)
+            self.no_pointer_cpydealloc_ptr = self.inittime_helper(
+                ll_no_pointer_cpydealloc, [llmemory.Address], lltype.Void)
             self.malloc_fixedsize_ptr = self.inittime_helper(
                 ll_malloc_fixedsize, [lltype.Signed], llmemory.Address)
             self.malloc_varsize_no_length_ptr = self.inittime_helper(
@@ -195,7 +199,10 @@
 
         if destrptr is None and not find_gc_ptrs_in_type(TYPE):
             #print repr(TYPE)[:80], 'is dealloc easy'
-            p = self.no_pointer_dealloc_ptr.value
+            if TYPE._gckind == 'cpy':
+                p = self.no_pointer_cpydealloc_ptr.value
+            else:
+                p = self.no_pointer_dealloc_ptr.value
             self.static_deallocator_funcptrs[TYPE] = p
             return p
 
@@ -215,19 +222,19 @@
         gcheader.refcount = refcount
         if refcount == 0:
 %s
-            llop.gc_free(lltype.Void, addr)
+            llop.%s_free(lltype.Void, addr)
     except:
         pass
     llop.gc_restore_exception(lltype.Void, exc_instance)
     pop_alive(exc_instance)
     # XXX layering of exceptiontransform versus gcpolicy
 
-""" % (body, )
+""" % (body, TYPE._gckind)
         else:
             call_del = None
             body = '\n'.join(_static_deallocator_body_for_type('v', TYPE))
             src = ('def ll_deallocator(addr):\n    v = cast_adr_to_ptr(addr, PTR_TYPE)\n' +
-                   body + '\n    llop.gc_free(lltype.Void, addr)\n')
+                   body + '\n    llop.%s_free(lltype.Void, addr)\n' % (TYPE._gckind,))
         d = {'pop_alive': LLTransformerOp(self.pop_alive),
              'llop': llop,
              'lltype': lltype,

Modified: pypy/dist/pypy/rpython/rcpy.py
==============================================================================
--- pypy/dist/pypy/rpython/rcpy.py	(original)
+++ pypy/dist/pypy/rpython/rcpy.py	Sat Sep 29 19:31:17 2007
@@ -264,7 +264,7 @@
         p[len(name)] = '\x00'
         pytypeobj.c_tp_name = lltype.direct_arrayitems(p)
         pytypeobj.c_tp_basicsize = llmemory.sizeof(r_inst.lowleveltype.TO)
-        if cpytype.subclassable and False: # XXX deallocation of subclass object segfaults!
+        if cpytype.subclassable:
             pytypeobj.c_tp_flags = CDefinedIntSymbolic('''(Py_TPFLAGS_DEFAULT |
                 Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_BASETYPE)''')
         else:
@@ -302,13 +302,6 @@
         cache[r_inst.classdef] = result
         return result
 
-# To make this a Py_TPFLAGS_BASETYPE, we need to have a tp_new that does
-# something different for subclasses: it needs to allocate a bit more
-# for CPython's GC (see PyObject_GC_Malloc); it needs to Py_INCREF the
-# type if it's a heap type; and it needs to PyObject_GC_Track() the object.
-# Also, tp_dealloc needs to untrack the object.
-
-
 # ____________________________________________________________
 # Emulation support, to have user-defined classes and instances
 # work nicely on top of CPython running the CPyObjSpace

Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py	(original)
+++ pypy/dist/pypy/translator/c/funcgen.py	Sat Sep 29 19:31:17 2007
@@ -538,7 +538,7 @@
         return "OP_CPY_MALLOC(%s, %s, %s);" % (cpytype, eresult, erestype)
 
     def OP_CPY_FREE(self, op):
-        return "OP_CPY_FREE(%s)" % (self.expr(op.args[1]),)
+        return "OP_CPY_FREE(%s);" % (self.expr(op.args[0]),)
 
     def OP_DIRECT_FIELDPTR(self, op):
         return self.OP_GETFIELD(op, ampersand='&')

Modified: pypy/dist/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/mem.h	(original)
+++ pypy/dist/pypy/translator/c/src/mem.h	Sat Sep 29 19:31:17 2007
@@ -115,10 +115,11 @@
 
 #define OP_CPY_MALLOC(cpytype, r, restype)  {				\
 	/* XXX add tp_itemsize later */					\
-	r = ((PyTypeObject *)cpytype)->tp_alloc((PyTypeObject *)cpytype, 0); \
+	r = (restype)((PyTypeObject *)cpytype)->tp_alloc(		\
+		(PyTypeObject *)cpytype, 0);				\
 	if (!r) RPyConvertExceptionFromCPython();			\
     }
-#define OP_CPY_FREE(x)   XXX "this shouldn't be used any more"
+#define OP_CPY_FREE(x)   ((PyObject *)x)->ob_type->tp_free((PyObject *)x)
 
 /************************************************************/
 /* weakref support */



More information about the Pypy-commit mailing list