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

xoraxax at codespeak.net xoraxax at codespeak.net
Thu Mar 25 22:26:26 CET 2010


Author: xoraxax
Date: Thu Mar 25 22:26:24 2010
New Revision: 72855

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/state.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/cpython-extension/pypy/module/cpyext/tupleobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Implement borrowing. We need two new dicts for that.

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 22:26:24 2010
@@ -260,12 +260,19 @@
         py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes_obj)
         py_obj = rffi.cast(PyObject, py_obj)
         if DEBUG_REFCOUNT:
-            print "MAKREF", py_obj, w_obj
+            print >>sys.stderr, "MAKREF", py_obj, w_obj
         state.py_objects_w2r[w_obj] = py_obj
         state.py_objects_r2w[ptr] = w_obj
+        if borrowed and ptr not in state.borrowed_objects:
+            state.borrowed_objects[ptr] = None
     elif not steal:
-        Py_INCREF(space, py_obj)
-    # XXX borrowed references?
+        if borrowed:
+            py_obj_addr = ctypes.addressof(py_obj._obj._storage)
+            if py_obj_addr not in state.borrowed_objects:
+                Py_INCREF(space, py_obj)
+                state.borrowed_objects[py_obj_addr] = None
+        else:
+            Py_INCREF(space, py_obj)
     return py_obj
 
 def force_string(space, ref):
@@ -289,19 +296,23 @@
     try:
         obj = state.py_objects_r2w[ptr]
     except KeyError:
-        if space.is_w(from_ref(space, ref.c_obj_type), space.w_str):
+        ref_type = ref.c_obj_type
+        if ref != ref_type and space.is_w(from_ref(space, ref_type), space.w_str):
             return force_string(space, ref)
         else:
             raise InvalidPointerException("Got invalid reference to a PyObject: %r" % (ref, ))
     return obj
 
-def clear_memory(space):
-    from pypy.module.cpyext.macros import Py_DECREF
+
+ at cpython_api([PyObject, PyObject], lltype.Void, external=False)
+def add_borrowed_object(space, container, obj):
     state = space.fromcache(State)
-    while state.py_objects_r2w:
-        key = state.py_objects_r2w.keys()[0]
-        Py_DECREF(space, key)
-    state.reset()
+    container_ptr = ctypes.addressof(container._obj._storage)
+    borrowees = state.borrow_mapping.get(container_ptr)
+    if borrowees is None:
+        state.borrow_mapping[container_ptr] = borrowees = {}
+    obj_ptr = ctypes.addressof(obj._obj._storage)
+    borrowees[obj_ptr] = None
 
 
 def general_check(space, w_obj, w_type):
@@ -517,6 +528,9 @@
         if FT.RESULT is PyObject:
             ret = from_ref(space, result)
             if result:
+                # The object reference returned from a C function 
+                # that is called from Python must be an owned reference 
+                # - ownership is transferred from the function to its caller.
                 Py_DECREF(space, result)
 
             # Check for exception consistency

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 22:26:24 2010
@@ -1,4 +1,5 @@
 import ctypes
+import sys
 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import cpython_api, PyObject, make_ref, from_ref
@@ -12,19 +13,31 @@
     from pypy.module.cpyext.typeobject import string_dealloc
     obj.c_obj_refcnt -= 1
     if DEBUG_REFCOUNT:
-        print "DECREF", obj, obj.c_obj_refcnt
+        print >>sys.stderr, "DECREF", obj, obj.c_obj_refcnt
     if obj.c_obj_refcnt == 0:
         state = space.fromcache(State)
         ptr = ctypes.addressof(obj._obj._storage)
         if ptr not in state.py_objects_r2w and \
             space.is_w(from_ref(space, obj.c_obj_type), space.w_str):
             # this is a half-allocated string, lets call the deallocator
-            # directly
-            string_dealloc(space, obj)
+            # without modifying the r2w/w2r dicts
+            _Py_Dealloc(space, obj)
         else:
             w_obj = state.py_objects_r2w.pop(ptr)
             _Py_Dealloc(space, obj)
             del state.py_objects_w2r[w_obj]
+        if ptr in state.borrow_mapping:
+            for containee in state.borrow_mapping[ptr]:
+                w_containee = state.py_objects_r2w.get(containee)
+                if w_containee is not None:
+                    containee = state.py_objects_w2r[w_containee]
+                    Py_DECREF(space, w_containee)
+                    containee_ptr = ctypes.addressof(containee._obj._storage)
+                    try:
+                        del state.borrowed_objects[containee_ptr]
+                    except KeyError:
+                        pass
+            del state.borrow_mapping[ptr]
     else:
         assert obj.c_obj_refcnt > 0
 
@@ -32,7 +45,7 @@
 def Py_INCREF(space, obj):
     obj.c_obj_refcnt += 1
     if DEBUG_REFCOUNT:
-        print "INCREF", obj, obj.c_obj_refcnt
+        print >>sys.stderr, "INCREF", obj, obj.c_obj_refcnt
 
 @cpython_api([PyObject], lltype.Void)
 def Py_XDECREF(space, obj):
@@ -45,7 +58,7 @@
     state = space.fromcache(State)
     pto = obj.c_obj_type
     pto = rffi.cast(PyTypeObjectPtr, pto)
-    print "Calling dealloc slot of", obj, \
+    print >>sys.stderr, "Calling dealloc slot of", obj, \
           "'s type which is", rffi.charp2str(pto.c_tp_name)
     generic_cpy_call(space, pto.c_tp_dealloc, obj, decref_args=False)
 

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/state.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/state.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/state.py	Thu Mar 25 22:26:24 2010
@@ -2,13 +2,17 @@
 from pypy.lib.identity_dict import identity_dict
 from pypy.interpreter.error import OperationError
 
+
 class State:
     def __init__(self, space):
+        self.space = space
         self.reset()
 
     def reset(self):
-        self.py_objects_w2r = identity_dict() # w_obj -> raw PyObject
-        self.py_objects_r2w = {} # addr of raw PyObject -> w_obj
+        self.py_objects_w2r = identity_dict() # { w_obj -> raw PyObject }
+        self.py_objects_r2w = {} # { addr of raw PyObject -> w_obj }
+        self.borrow_mapping = {} # { addr of container -> { addr of containee -> None } }
+        self.borrowed_objects = {} # { addr of containee -> None }
         self.exc_type = None
         self.exc_value = None
 

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 22:26:24 2010
@@ -11,6 +11,7 @@
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext.macros import Py_DECREF
 from pypy.translator.goal import autopath
+from pypy.lib.identity_dict import identity_dict
 
 @api.cpython_api([], api.PyObject)
 def PyPy_Crash1(space):
@@ -56,7 +57,6 @@
 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:
@@ -117,6 +117,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.freeze_refcnts()
         #self.check_and_print_leaks("Object %r leaked some time ago (refcount %i) -- Not executing test!")
 
     def teardown_method(self, func):
@@ -128,29 +129,35 @@
             Py_DECREF(self.space, w_mod)
         except OperationError:
             pass
+        state = self.space.fromcache(State)
         if self.check_and_print_leaks():
-            assert False, "Test leaks object(s)."
+            assert False, "Test leaks or loses object(s)."
 
-    @classmethod
-    def freeze_refcnts(cls):
-        state = cls.space.fromcache(State)
-        cls.frozen_refcounts = {}
+    def freeze_refcnts(self):
+        state = self.space.fromcache(State)
+        self.frozen_refcounts = {}
         for w_obj, obj in state.py_objects_w2r.iteritems():
-            cls.frozen_refcounts[w_obj] = obj.c_obj_refcnt
+            self.frozen_refcounts[w_obj] = obj.c_obj_refcnt
+        state.print_refcounts()
 
     def check_and_print_leaks(self):
         # check for sane refcnts
         leaking = False
         state = self.space.fromcache(State)
-        global_objects_w = set()
+        lost_objects_w = identity_dict()
+        lost_objects_w.update((key, None) for key in self.frozen_refcounts.keys())
         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
+                lost_objects_w.pop(w_obj)
             if delta != 0:
                 leaking = True
                 print >>sys.stderr, "Leaking %r: %i references" % (w_obj, delta)
+        for w_obj in lost_objects_w:
+            print >>sys.stderr, "Lost object %r" % (w_obj, )
+            leaking = True
         return leaking
 
 
@@ -273,7 +280,9 @@
         body = """
         PyObject* foo_test(PyObject* self, PyObject *args)
         {
-            return PyTuple_GetItem(args, 0);
+            PyObject *t = PyTuple_GetItem(args, 0);
+            Py_INCREF(t);
+            return t;
         }
         static PyMethodDef methods[] = {
             { "test", foo_test, METH_VARARGS },

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/tupleobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/tupleobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/tupleobject.py	Thu Mar 25 22:26:24 2010
@@ -1,6 +1,6 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import cpython_api, PyObject, Py_ssize_t, \
-        general_check, CANNOT_FAIL
+        general_check, CANNOT_FAIL, add_borrowed_object
 from pypy.module.cpyext.macros import Py_DECREF
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.objspace.std.tupleobject import W_TupleObject
@@ -29,4 +29,5 @@
         PyErr_BadInternalCall(space)
     assert isinstance(w_t, W_TupleObject)
     w_obj = w_t.wrappeditems[pos]
+    add_borrowed_object(space, w_t, w_obj)
     return w_obj

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 22:26:24 2010
@@ -1,4 +1,5 @@
 import ctypes
+import sys
 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.lltypesystem.lltype import Ptr, FuncType, Void
@@ -220,7 +221,7 @@
 
 @cpython_api([PyObject], lltype.Void, external=False)
 def subtype_dealloc(space, obj):
-    print "Dealloc of", obj
+    print >>sys.stderr, "Dealloc of", obj
     pto = rffi.cast(PyTypeObjectPtr, obj.c_obj_type)
     assert pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
     base = pto



More information about the Pypy-commit mailing list