[pypy-svn] r72798 - in pypy/branch/cpython-extension/pypy/module/cpyext: . test

xoraxax at codespeak.net xoraxax at codespeak.net
Thu Mar 25 14:02:06 CET 2010


Author: xoraxax
Date: Thu Mar 25 14:02:04 2010
New Revision: 72798

Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/api.py
   pypy/branch/cpython-extension/pypy/module/cpyext/macros.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_boolobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Implement refcount checking for our tests. Only one test is failing, amaury may fix it :-) Refcounts are now checked against the baseline after every test is run.

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py	Thu Mar 25 14:02:04 2010
@@ -208,7 +208,7 @@
     hints["padding"] = hints["padding"] + tuple(pad_fields)
     return lltype.Struct(hints["c_name"], hints=hints, *new_fields)
 
-def make_ref(space, w_obj, borrowed=False):
+def make_ref(space, w_obj, borrowed=False, steal=False):
     if w_obj is None:
         return lltype.nullptr(PyObject.TO)
     assert isinstance(w_obj, W_Root)
@@ -242,7 +242,7 @@
         py_obj = rffi.cast(PyObject, py_obj)
         state.py_objects_w2r[w_obj] = py_obj
         state.py_objects_r2w[ptr] = w_obj
-    else:
+    elif not steal:
         py_obj.c_obj_refcnt += 1
     # XXX borrowed references?
     return py_obj

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/macros.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/macros.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/macros.py	Thu Mar 25 14:02:04 2010
@@ -21,6 +21,10 @@
 def Py_INCREF(space, obj):
     obj.c_obj_refcnt += 1
 
+ at cpython_api([PyObject], lltype.Void)
+def Py_XDECREF(space, obj):
+    if obj:
+        Py_DECREF(space, obj)
 
 def _Py_Dealloc(space, obj):
     from pypy.module.cpyext.typeobject import PyTypeObjectPtr

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_boolobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_boolobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_boolobject.py	Thu Mar 25 14:02:04 2010
@@ -44,4 +44,3 @@
         assert module.get_false() == False
         assert module.test_FromLong() == True
         assert module.test_Check() == True
-        self.check_refcnts("FOOOOOO %r")

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py	Thu Mar 25 14:02:04 2010
@@ -69,6 +69,7 @@
 class AppTestCpythonExtensionBase:
     def setup_class(cls):
         cls.space = gettestobjspace(usemodules=['cpyext'])
+        cls.freeze_refcnts()
 
     def import_module(self, name, init=None, body=''):
         if init is not None:
@@ -129,9 +130,7 @@
     def setup_method(self, func):
         self.w_import_module = self.space.wrap(self.import_module)
         self.w_import_extension = self.space.wrap(self.import_extension)
-        self.w_check_refcnts = self.space.wrap(self.check_refcnts)
-        self.check_refcnts("Object has refcnt != 1: %r -- Not executing test!")
-        #self.space.fromcache(State).print_refcounts()
+        #self.check_and_print_leaks("Object %r leaked some time ago (refcount %i) -- Not executing test!")
 
     def teardown_method(self, func):
         try:
@@ -142,16 +141,31 @@
             Py_DECREF(self.space, w_mod)
         except OperationError:
             pass
-        self.space.fromcache(State).print_refcounts()
-        self.check_refcnts("Test leaks object: %r")
+        if self.check_and_print_leaks():
+            assert False, "Test leaks object(s)."
 
-    def check_refcnts(self, message):
+    @classmethod
+    def freeze_refcnts(cls):
+        state = cls.space.fromcache(State)
+        cls.frozen_refcounts = {}
+        for w_obj, obj in state.py_objects_w2r.iteritems():
+            cls.frozen_refcounts[w_obj] = obj.c_obj_refcnt
+
+    def check_and_print_leaks(self):
         # check for sane refcnts
-        for w_obj in (self.space.w_True, self.space.w_False,
-                self.space.w_None):
-            state = self.space.fromcache(State)
-            obj = state.py_objects_w2r.get(w_obj)
-            assert obj.c_obj_refcnt == 1, message % (w_obj, )
+        leaking = False
+        state = self.space.fromcache(State)
+        global_objects_w = set()
+        for w_obj, obj in state.py_objects_w2r.iteritems():
+            base_refcnt = self.frozen_refcounts.get(w_obj)
+            delta = obj.c_obj_refcnt
+            if base_refcnt is not None:
+                delta -= base_refcnt
+            if delta != 0:
+                leaking = True
+                print >>sys.stderr, "Leaking %r: %i references" % (w_obj, delta)
+        return leaking
+
 
 class AppTestCpythonExtension(AppTestCpythonExtensionBase):
     def test_createmodule(self):
@@ -324,7 +338,7 @@
             refcnt_after = Py_REFCNT(true);
             Py_DECREF(true);
             Py_DECREF(true);
-            printf("REFCNT %i %i\\n", refcnt, refcnt_after);
+            fprintf(stderr, "REFCNT %i %i\\n", refcnt, refcnt_after);
             return PyBool_FromLong(refcnt_after == refcnt+2 && refcnt < 3);
         }
         static PyObject* foo_bar(PyObject* self, PyObject *args)
@@ -339,8 +353,9 @@
             if (PyTuple_SetItem(tup, 0, true) < 0)
                 return NULL;
             refcnt_after = Py_REFCNT(true);
-            printf("REFCNT2 %i %i\\n", refcnt, refcnt_after);
-            return PyBool_FromLong(refcnt_after == refcnt && refcnt < 3);
+            Py_DECREF(tup);
+            fprintf(stderr, "REFCNT2 %i %i\\n", refcnt, refcnt_after);
+            return PyBool_FromLong(refcnt_after == refcnt);
         }
 
         static PyMethodDef methods[] = {

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py	Thu Mar 25 14:02:04 2010
@@ -16,7 +16,7 @@
 from pypy.module.cpyext.modsupport import PyMethodDef, convert_method_defs
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext.methodobject import generic_cpy_call
-from pypy.module.cpyext.macros import Py_DECREF
+from pypy.module.cpyext.macros import Py_DECREF, Py_XDECREF
 
 
 PyTypeObject = lltype.ForwardReference()
@@ -225,7 +225,8 @@
     assert pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
     base = pto
     this_func_ptr = subtype_dealloc.api_func.get_llhelper(space)
-    ref_of_object_type = rffi.cast(PyTypeObjectPtr, make_ref(space, space.w_object))
+    ref_of_object_type = rffi.cast(PyTypeObjectPtr,
+            make_ref(space, space.w_object, steal=True))
     while base.c_tp_dealloc == this_func_ptr:
         base = base.c_tp_base
         assert base
@@ -240,13 +241,16 @@
 def type_dealloc(space, obj):
     obj_pto = rffi.cast(PyTypeObjectPtr, obj)
     type_pto = rffi.cast(PyTypeObjectPtr, obj.c_obj_type)
+    Py_XDECREF(space, obj_pto.c_tp_base)
     # type_dealloc code follows:
-    # XXX XDECREF tp_base, tp_dict, tp_bases, tp_mro, tp_cache,
+    # XXX XDECREF tp_dict, tp_bases, tp_mro, tp_cache,
     #             tp_subclasses
     # free tp_doc
     lltype.free(obj_pto.c_tp_name, flavor="raw")
     obj_pto_voidp = rffi.cast(rffi.VOIDP_real, obj_pto)
     generic_cpy_call(space, type_pto.c_tp_free, obj_pto_voidp)
+    pto = rffi.cast(PyObject, type_pto)
+    Py_DECREF(space, type_pto)
 
 def allocate_type_obj(space, w_type):
     """ Allocates a pto from a w_type which must be a PyPy type. """



More information about the Pypy-commit mailing list