[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