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

afa at codespeak.net afa at codespeak.net
Thu Mar 25 18:40:18 CET 2010


Author: afa
Date: Thu Mar 25 18:40:16 2010
New Revision: 72837

Added:
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_api.py   (contents, props changed)
Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py
   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/conftest.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_floatobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_object.py   (contents, props changed)
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_stringobject.py   (contents, props changed)
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_tupleobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Improve reference counting, especially when type(x) == x (which happens for x=type)


Modified: pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/__init__.py	Thu Mar 25 18:40:16 2010
@@ -38,3 +38,5 @@
 import pypy.module.cpyext.stringobject
 import pypy.module.cpyext.tupleobject
 import pypy.module.cpyext.dictobject
+# now that all rffi_platform.Struct types are registered, configure them
+api.configure_types()

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 18:40:16 2010
@@ -66,8 +66,8 @@
 # Functions may raise exceptions.  In context (3), the exception flows normally
 # through the calling function.  In context (1) and (2), the exception is
 # caught; if it is an OperationError, it is stored in the thread state; other
-# exceptions generate a OperationError(w_SystemError).  In every case the
-# funtion returns the error value specifed in the API.
+# exceptions generate a OperationError(w_SystemError); and the funtion returns
+# the error value specifed in the API.
 #
 
 class ApiFunction:
@@ -189,7 +189,7 @@
     (("buffer", rffi.CCHARP), ("size", Py_ssize_t))
 cpython_struct("PyStringObject", PyStringObjectFields, PyStringObjectStruct)
 
-def configure():
+def configure_types():
     for name, TYPE in rffi_platform.configure(CConfig).iteritems():
         if name in TYPES:
             TYPES[name].become(TYPE)
@@ -215,6 +215,7 @@
     return lltype.Struct(hints["c_name"], hints=hints, *new_fields)
 
 def make_ref(space, w_obj, borrowed=False, steal=False):
+    from pypy.module.cpyext.macros import Py_INCREF, Py_DECREF, DEBUG_REFCOUNT
     if w_obj is None:
         return lltype.nullptr(PyObject.TO)
     assert isinstance(w_obj, W_Root)
@@ -226,36 +227,44 @@
         w_type = space.type(w_obj)
         if space.is_w(w_type, space.w_type):
             py_obj = allocate_type_obj(space, w_obj)
+            py_obj.c_obj_refcnt = 1
             if space.is_w(w_type, w_obj):
                 pto = py_obj
+                Py_INCREF(space, pto)
             else:
                 pto = make_ref(space, w_type)
         elif isinstance(w_obj, W_PyCObject):
             w_type = space.type(w_obj)
             assert isinstance(w_type, W_PyCTypeObject)
             pto = w_type.pto
+            # Don't increase refcount for non-heaptypes
+            # Py_INCREF(space, pto)
             basicsize = pto._obj.c_tp_basicsize
             T = get_padded_type(PyObject.TO, basicsize)
             py_obj = lltype.malloc(T, None, flavor="raw")
+            py_obj.c_obj_refcnt = 1
         elif isinstance(w_obj, W_StringObject):
             py_obj = lltype.malloc(PyStringObject.TO, None, flavor='raw')
             py_obj.c_size = len(space.str_w(w_obj))
             py_obj.c_buffer = lltype.nullptr(rffi.CCHARP.TO)
             pto = make_ref(space, space.w_str)
             py_obj = rffi.cast(PyObject, py_obj)
+            py_obj.c_obj_refcnt = 1
         else:
             py_obj = lltype.malloc(PyObject.TO, None, flavor="raw")
+            py_obj.c_obj_refcnt = 1
             pto = make_ref(space, space.type(w_obj))
         py_obj.c_obj_type = rffi.cast(PyObject, pto)
-        py_obj.c_obj_refcnt = 1
         ctypes_obj = ll2ctypes.lltype2ctypes(py_obj)
         ptr = ctypes.cast(ctypes_obj, ctypes.c_void_p).value
         py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes_obj)
         py_obj = rffi.cast(PyObject, py_obj)
+        if DEBUG_REFCOUNT:
+            print "MAKREF", py_obj, w_obj
         state.py_objects_w2r[w_obj] = py_obj
         state.py_objects_r2w[ptr] = w_obj
     elif not steal:
-        py_obj.c_obj_refcnt += 1
+        Py_INCREF(space, py_obj)
     # XXX borrowed references?
     return py_obj
 
@@ -299,6 +308,7 @@
     w_obj_type = space.type(w_obj)
     return int(space.is_w(w_obj_type, w_type) or space.is_true(space.issubtype(w_obj_type, w_type)))
 
+# Make the wrapper for the cases (1) and (2)
 def make_wrapper(space, callable):
     def wrapper(*args):
         boxed_args = []
@@ -381,8 +391,6 @@
     pypy_rename_h.write('\n'.join(pypy_rename))
 
 
-    configure() # needs pypy_rename.h
-
     # Structure declaration code
     members = []
     for name, func in FUNCTIONS.iteritems():
@@ -508,6 +516,8 @@
         FT = lltype.typeOf(func).TO
         if FT.RESULT is PyObject:
             ret = from_ref(space, result)
+            if result:
+                Py_DECREF(space, result)
 
             # Check for exception consistency
             has_error = PyErr_Occurred(space) is not None
@@ -523,11 +533,10 @@
                 state = space.fromcache(State)
                 state.check_and_raise_exception()
 
-            Py_DECREF(space, ret) # XXX WHY??
             return ret
     finally:
         if decref_args:
-            for arg in args: # XXX ur needed
-                if arg is not None and isinstance(arg, W_Root):
-                    Py_DECREF(space, arg)
+            for arg, ref in zip(args, boxed_args):
+                if isinstance(arg, W_Root) and ref:
+                    Py_DECREF(space, ref)
 

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 18:40:16 2010
@@ -4,11 +4,15 @@
 from pypy.module.cpyext.api import cpython_api, PyObject, make_ref, from_ref
 from pypy.module.cpyext.state import State
 
+DEBUG_REFCOUNT = False
+
 # XXX Optimize these functions and put them into macro definitions
 @cpython_api([PyObject], lltype.Void)
 def Py_DECREF(space, obj):
     from pypy.module.cpyext.typeobject import string_dealloc
     obj.c_obj_refcnt -= 1
+    if DEBUG_REFCOUNT:
+        print "DECREF", obj, obj.c_obj_refcnt
     if obj.c_obj_refcnt == 0:
         state = space.fromcache(State)
         ptr = ctypes.addressof(obj._obj._storage)
@@ -25,6 +29,8 @@
 @cpython_api([PyObject], lltype.Void)
 def Py_INCREF(space, obj):
     obj.c_obj_refcnt += 1
+    if DEBUG_REFCOUNT:
+        print "INCREF", obj, obj.c_obj_refcnt
 
 @cpython_api([PyObject], lltype.Void)
 def Py_XDECREF(space, obj):

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/conftest.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/conftest.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/conftest.py	Thu Mar 25 18:40:16 2010
@@ -1,12 +1,19 @@
 import py
-from pypy.conftest import option
+from pypy.conftest import option, gettestobjspace
 
 class Directory(py.test.collect.Directory):
     def collect(self):
         if option.runappdirect:
             py.test.skip("cannot be run by py.test -A")
+
+        # ensure additional functions are registered
+        import pypy.module.cpyext.test.test_cpyext
+
         return super(Directory, self).collect()
 
+def pytest_funcarg__space(request):
+    return gettestobjspace(usemodules=['cpyext'])
+
 def pytest_funcarg__api(request):
     return request.cls.api
 

Added: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_api.py
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_api.py	Thu Mar 25 18:40:16 2010
@@ -0,0 +1,32 @@
+from pypy.conftest import gettestobjspace
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.interpreter.baseobjspace import W_Root
+from pypy.module.cpyext.state import State
+from pypy.module.cpyext import api
+PyObject = api.PyObject
+
+ at api.cpython_api([PyObject], lltype.Void)
+def PyPy_GetWrapped(space, w_arg):
+    assert isinstance(w_arg, W_Root)
+ at api.cpython_api([PyObject], lltype.Void)
+def PyPy_GetReference(space, arg):
+    assert lltype.typeOf(arg) is  PyObject
+
+class BaseApiTest:
+    def setup_class(cls):
+        cls.space = gettestobjspace(usemodules=['cpyext'])
+        class CAPI:
+            def __getattr__(self, name):
+                return getattr(cls.space, name)
+        cls.api = CAPI()
+        CAPI.__dict__.update(api.INTERPLEVEL_API)
+
+    def teardown_method(self, func):
+        state = self.space.fromcache(State)
+        assert state.exc_value is None
+
+class TestConversion(BaseApiTest):
+    def test_conversions(self, space, api):
+        api.PyPy_GetWrapped(space.w_None)
+        api.PyPy_GetReference(space.w_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 18:40:16 2010
@@ -12,7 +12,6 @@
 from pypy.module.cpyext.macros import Py_DECREF
 from pypy.translator.goal import autopath
 
-
 @api.cpython_api([], api.PyObject)
 def PyPy_Crash1(space):
     1/0
@@ -54,18 +53,6 @@
         standalone=False)
     return str(soname)
 
-class BaseApiTest:
-    def setup_class(cls):
-        class CAPI:
-            def __getattr__(self, name):
-                return getattr(cls.space, name)
-        cls.api = CAPI()
-        CAPI.__dict__.update(api.INTERPLEVEL_API)
-
-    def teardown_method(self, func):
-        state = self.space.fromcache(State)
-        assert state.exc_value is None
-
 class AppTestCpythonExtensionBase:
     def setup_class(cls):
         cls.space = gettestobjspace(usemodules=['cpyext'])

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_floatobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_floatobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_floatobject.py	Thu Mar 25 18:40:16 2010
@@ -1,4 +1,4 @@
-from pypy.module.cpyext.test.test_cpyext import BaseApiTest
+from pypy.module.cpyext.test.test_api import BaseApiTest
 
 class TestFloatObject(BaseApiTest):
     def test_floatobject(self, space, api):

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_object.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_object.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_object.py	Thu Mar 25 18:40:16 2010
@@ -1,4 +1,4 @@
-from pypy.module.cpyext.test.test_cpyext import BaseApiTest
+from pypy.module.cpyext.test.test_api import BaseApiTest
 
 class TestObject(BaseApiTest):
     def test_IsTrue(self, space, api):

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_stringobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_stringobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_stringobject.py	Thu Mar 25 18:40:16 2010
@@ -1,5 +1,5 @@
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.test.test_cpyext import BaseApiTest
+from pypy.module.cpyext.test.test_api import BaseApiTest
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 
 import py
@@ -51,15 +51,19 @@
         module = self.import_extension('foo', [
             ("getstring", "METH_NOARGS",
              """
-                 PyObject* s = PyString_FromStringAndSize(NULL, 3);
+                 PyObject *s, *t;
+                 char* c;
+                 Py_ssize_t len;
+
+                 s = PyString_FromStringAndSize(NULL, 3);
                  if (s == NULL)
                     return NULL;
-                 PyObject* t = PyString_FromStringAndSize(NULL, 3);
+                 t = PyString_FromStringAndSize(NULL, 3);
                  if (t == NULL)
                     return NULL;
                  Py_DECREF(t);
-                 char* c = PyString_AsString(s);
-                 //Py_ssize_t len = PyString_Size(s);
+                 c = PyString_AsString(s);
+                 //len = PyString_Size(s);
                  c[0] = 'a';
                  c[1] = 'b'; 
                  c[2] = 'c';//len-1] = 'c';

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_tupleobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_tupleobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_tupleobject.py	Thu Mar 25 18:40:16 2010
@@ -1,6 +1,4 @@
-import py.test
-
-from pypy.module.cpyext.test.test_cpyext import BaseApiTest
+from pypy.module.cpyext.test.test_api import BaseApiTest
 
 class TestTupleObject(BaseApiTest):
     def test_tupleobject(self, space, api):

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 18:40:16 2010
@@ -11,7 +11,7 @@
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.module.cpyext.api import cpython_api, cpython_api_c, cpython_struct, \
     PyObject, PyVarObjectFields, Py_ssize_t, Py_TPFLAGS_READYING, \
-    Py_TPFLAGS_READY, make_wrapper, Py_TPFLAGS_HEAPTYPE, make_ref, \
+    Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, make_ref, \
     PyStringObject
 from pypy.interpreter.module import Module
 from pypy.module.cpyext.modsupport import PyMethodDef, convert_method_defs
@@ -283,9 +283,8 @@
     pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
     bases_w = w_type.bases_w
     assert len(bases_w) <= 1
-    if not bases_w:
-        pto.c_tp_base = lltype.nullptr(PyTypeObject)
-    elif not space.is_w(w_type, space.w_type): # avoid endless recursion
+    pto.c_tp_base = lltype.nullptr(PyTypeObject)
+    if bases_w and not space.is_w(w_type, space.w_type): # avoid endless recursion
         ref = make_ref(space, bases_w[0])
         pto.c_tp_base = rffi.cast(PyTypeObjectPtr, ref)
     #  XXX fill slots in pto



More information about the Pypy-commit mailing list