[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