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

xoraxax at codespeak.net xoraxax at codespeak.net
Thu Apr 1 04:23:21 CEST 2010


Author: xoraxax
Date: Thu Apr  1 04:23:19 2010
New Revision: 73238

Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/object.py
   pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Introduce dual objects to W_PyCObject. These are used only to be stored in the mapping dicts. Before this change, cpyext would always throw away the pyo, even of a C type, with all its data because the reference count did not consider that PyPy itself was also using the object. Now this is respected by the invariant that the refcount of the object is up by one if the corresponding PyCObject exists. As long as the pyo is alive (refcnt > 0), the PyCObject is automatically recreated if necessary.

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/object.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/object.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/object.py	Thu Apr  1 04:23:19 2010
@@ -3,7 +3,8 @@
 from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
 from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef
 from pypy.module.cpyext.state import State
-from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject, W_PyCObject
+from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject, W_PyCObject,\
+        W_PyCObjectDual
 from pypy.objspace.std.objectobject import W_ObjectObject
 import pypy.module.__builtin__.operation as operation
 
@@ -12,6 +13,11 @@
     if isinstance(w_type, W_PyCTypeObject):
         w_pycobj = space.allocate_instance(W_PyCObject, w_type)
         w_pycobj.__init__(space)
+        w_pycobjd = space.allocate_instance(W_PyCObjectDual, w_type)
+        w_pycobjd.__init__(space)
+        w_pycobjd.set_pycobject(w_pycobj)
+        w_pycobj.set_dual(w_pycobjd)
+        Py_IncRef(space, w_pycobj)
         return w_pycobj
     assert False, "Please add more cases in get_cls_for_type_object!"
 

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py	Thu Apr  1 04:23:19 2010
@@ -29,14 +29,16 @@
 
 
 def make_ref(space, w_obj, borrowed=False, steal=False):
+    from pypy.module.cpyext.typeobject import allocate_type_obj,\
+            W_PyCTypeObject, W_PyCObject, W_PyCObjectDual
     if w_obj is None:
         return lltype.nullptr(PyObject.TO)
     assert isinstance(w_obj, W_Root)
     state = space.fromcache(State)
+    if isinstance(w_obj, W_PyCObject):
+        w_obj = w_obj.w_dual
     py_obj = state.py_objects_w2r.get(w_obj, lltype.nullptr(PyObject.TO))
     if not py_obj:
-        from pypy.module.cpyext.typeobject import allocate_type_obj,\
-                W_PyCTypeObject, W_PyCObject
         w_type = space.type(w_obj)
         if space.is_w(w_type, space.w_type):
             pto = allocate_type_obj(space, w_obj)
@@ -97,13 +99,27 @@
 
 
 def from_ref(space, ref):
+    from pypy.module.cpyext.typeobject import W_PyCObjectDual, W_PyCObject
     assert lltype.typeOf(ref) == PyObject
     if not ref:
         return None
     state = space.fromcache(State)
     ptr = rffi.cast(ADDR, ref)
     try:
-        obj = state.py_objects_r2w[ptr]
+        w_obj = state.py_objects_r2w[ptr]
+        if isinstance(w_obj, W_PyCObjectDual):
+            w_obj_wr = w_obj.w_pycobject
+            w_obj_or_None = w_obj_wr()
+            if w_obj_or_None is None:
+                # resurrect new PyCObject
+                Py_IncRef(space, ref)
+                w_obj_new = space.allocate_instance(W_PyCObject, space.type(w_obj))
+                w_obj_new.__init__(space)
+                w_obj_new.set_dual(w_obj)
+                w_obj.set_pycobject(w_obj_new)
+                w_obj = w_obj_new
+            else:
+                w_obj = w_obj_or_None
     except KeyError:
         ref_type = ref.c_ob_type
         if ref != ref_type and space.is_w(from_ref(space, ref_type), space.w_str):
@@ -113,7 +129,7 @@
             if not we_are_translated():
                 msg = "Got invalid reference to a PyObject: %r" % (ref, )
             raise InvalidPointerException(msg)
-    return obj
+    return w_obj
 
 
 # XXX Optimize these functions and put them into macro definitions

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c	Thu Apr  1 04:23:19 2010
@@ -57,11 +57,21 @@
     return PyString_FromStringAndSize("Foo Example", 11);
 }
 
+static PyObject *
+foo_get_foo(PyObject *self, void *closure)
+{
+  return PyInt_FromLong(((fooobject*)self)->foo);
+}
+
 static PyGetSetDef foo_getseters[] = {
     {"name",
      (getter)foo_get_name, NULL,
      NULL,
      NULL},
+     {"foo",
+     (getter)foo_get_foo, NULL,
+     NULL,
+     NULL},
     {NULL}  /* Sentinel */
 };
 

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py	Thu Apr  1 04:23:19 2010
@@ -10,6 +10,8 @@
         assert 'foo' in sys.modules
         assert "copy" in dir(module.fooType)
         obj = module.new()
+        print obj.foo
+        assert obj.foo == 42
         print "Obj has type", type(obj)
         assert type(obj) is module.fooType
         print "type of obj has type", type(type(obj))
@@ -23,3 +25,6 @@
         assert repr(obj2) == "<Foo>"
         assert repr(module.fooType.__call__) == "<slot wrapper '__call__' of 'foo' objects>"
         assert obj2(foo=1, bar=2) == dict(foo=1, bar=2)
+
+        print obj.foo
+        assert obj.foo == 42

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 Apr  1 04:23:19 2010
@@ -1,5 +1,6 @@
 import os
 import sys
+from weakref import ref
 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.annlowlevel import llhelper
@@ -103,6 +104,12 @@
     def __init__(self, space):
         self.space = space
 
+    def set_dual(self, w_obj):
+        self.w_dual = w_obj
+
+    def __del__(self):
+        Py_DecRef(self.space, self)
+
     def getter(self, space, w_self):
         return generic_cpy_call(
             space, self.getset.c_get, w_self,
@@ -113,6 +120,17 @@
             space, self.getset.c_set, w_self, w_value,
             self.getset.c_closure)
 
+
+class W_PyCObjectDual(W_PyCObject):
+    def __init__(self, space):
+        self.space = space
+
+    def set_pycobject(self, w_pycobject):
+        self.w_pycobject = ref(w_pycobject)
+
+    def __del__(self): # ok, subclassing isnt so sensible here
+        pass
+
 @cpython_api([PyObject], lltype.Void, external=False)
 def subtype_dealloc(space, obj):
     pto = rffi.cast(PyTypeObjectPtr, obj.c_ob_type)



More information about the Pypy-commit mailing list