[pypy-svn] r74554 - in pypy/trunk/pypy/module/cpyext: . test
afa at codespeak.net
afa at codespeak.net
Wed May 19 01:55:14 CEST 2010
Author: afa
Date: Wed May 19 01:55:11 2010
New Revision: 74554
Modified:
pypy/trunk/pypy/module/cpyext/api.py
pypy/trunk/pypy/module/cpyext/modsupport.py
pypy/trunk/pypy/module/cpyext/pyobject.py
pypy/trunk/pypy/module/cpyext/state.py
pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
Log:
Add a new way to borrow objects:
borrow_from(None, w_obj) will keep the object alive until the end of the C function call
(managed by generic_cpy_call()).
>From what I understand, this is very similar to JNI "Local References".
Use this whenever there is no container managed by user code:
PyErr_Occurred(), PySys_GetObject()
Modified: pypy/trunk/pypy/module/cpyext/api.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/api.py (original)
+++ pypy/trunk/pypy/module/cpyext/api.py Wed May 19 01:55:11 2010
@@ -811,6 +811,7 @@
@specialize.memo()
def make_generic_cpy_call(FT, decref_args, expect_null):
from pypy.module.cpyext.pyobject import make_ref, from_ref, Py_DecRef
+ from pypy.module.cpyext.pyobject import RefcountState
from pypy.module.cpyext.pyerrors import PyErr_Occurred
unrolling_arg_types = unrolling_iterable(enumerate(FT.ARGS))
RESULT_TYPE = FT.RESULT
@@ -856,8 +857,17 @@
boxed_args += (arg,)
else:
boxed_args += (arg,)
- result = call_external_function(func, *boxed_args)
+
try:
+ # create a new container for borrowed references
+ state = space.fromcache(RefcountState)
+ old_container = state.swap_borrow_container(None)
+ try:
+ # Call the function
+ result = call_external_function(func, *boxed_args)
+ finally:
+ state.swap_borrow_container(old_container)
+
if RESULT_TYPE is PyObject:
if result is None:
ret = result
Modified: pypy/trunk/pypy/module/cpyext/modsupport.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/modsupport.py (original)
+++ pypy/trunk/pypy/module/cpyext/modsupport.py Wed May 19 01:55:11 2010
@@ -58,8 +58,7 @@
if doc:
space.setattr(w_mod, space.wrap("__doc__"),
space.wrap(rffi.charp2str(doc)))
- # we cannot borrow here
- return w_mod
+ return borrow_from(None, w_mod)
def convert_method_defs(space, dict_w, methods, w_type, w_self=None):
Modified: pypy/trunk/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/pyobject.py (original)
+++ pypy/trunk/pypy/module/cpyext/pyobject.py Wed May 19 01:55:11 2010
@@ -151,8 +151,14 @@
self.space = space
self.py_objects_w2r = {} # { w_obj -> raw PyObject }
self.py_objects_r2w = {} # { addr of raw PyObject -> w_obj }
- self.borrow_mapping = {} # { w_container -> { w_containee -> None } }
- self.borrowed_objects = {} # { addr of containee -> None }
+
+ self.borrow_mapping = {None: {}}
+ # { w_container -> { w_containee -> None } }
+ # the None entry manages references borrowed during a call to
+ # generic_cpy_call()
+ self.borrowed_objects = {}
+ # { addr of containee -> None }
+
# For tests
self.non_heaptypes_w = []
@@ -173,12 +179,69 @@
for w_obj, obj in self.py_objects_w2r.items():
print "%r: %i" % (w_obj, obj.c_ob_refcnt)
+ def make_borrowed(self, w_container, w_borrowed):
+ """
+ Create a borrowed reference, which will live as long as the container
+ has a living reference (as a PyObject!)
+ """
+ ref = make_ref(self.space, w_borrowed)
+ obj_ptr = rffi.cast(ADDR, ref)
+ if obj_ptr not in self.borrowed_objects:
+ # borrowed_objects owns the reference
+ self.borrowed_objects[obj_ptr] = None
+ else:
+ Py_DecRef(self.space, ref) # already in borrowed list
+
+ borrowees = self.borrow_mapping.setdefault(w_container, {})
+ borrowees[w_borrowed] = None
+ return ref
+
def reset_borrowed_references(self):
+ "Used in tests"
while self.borrowed_objects:
addr, _ = self.borrowed_objects.popitem()
w_obj = self.py_objects_r2w[addr]
Py_DecRef(self.space, w_obj)
- self.borrow_mapping = {}
+ self.borrow_mapping = {None: {}}
+
+ def delete_borrower(self, w_obj):
+ """
+ Called when a potential container for borrowed references has lost its
+ last reference. Removes the borrowed references it contains.
+ """
+ if w_obj in self.borrow_mapping: # move to lifeline __del__
+ for w_containee in self.borrow_mapping[w_obj]:
+ self.forget_borrowee(w_containee)
+ del self.borrow_mapping[w_obj]
+
+ def swap_borrow_container(self, container):
+ """switch the current default contained with the given one."""
+ if container is None:
+ old_container = self.borrow_mapping[None]
+ self.borrow_mapping[None] = {}
+ return old_container
+ else:
+ old_container = self.borrow_mapping[None]
+ self.borrow_mapping[None] = container
+ for w_containee in old_container:
+ self.forget_borrowee(w_containee)
+
+ def forget_borrowee(self, w_obj):
+ "De-register an object from the list of borrowed references"
+ ref = self.py_objects_w2r.get(w_obj, lltype.nullptr(PyObject.TO))
+ if not ref:
+ if DEBUG_REFCOUNT:
+ print >>sys.stderr, "Borrowed object is already gone:", \
+ hex(containee)
+ return
+
+ containee_ptr = rffi.cast(ADDR, ref)
+ try:
+ del self.borrowed_objects[containee_ptr]
+ except KeyError:
+ pass
+ else:
+ Py_DecRef(self.space, ref)
class InvalidPointerException(Exception):
pass
@@ -293,7 +356,7 @@
_Py_Dealloc(space, obj)
del state.py_objects_w2r[w_obj]
# if the object was a container for borrowed references
- delete_borrower(space, w_obj)
+ state.delete_borrower(w_obj)
else:
if not we_are_translated() and obj.c_ob_refcnt < 0:
message = "Negative refcount for obj %s with type %s" % (
@@ -329,23 +392,11 @@
Create a borrowed reference, which will live as long as the container
has a living reference (as a PyObject!)
"""
- ref = make_ref(space, w_borrowed)
- if not ref:
- return ref
+ if w_borrowed is None:
+ return lltype.nullptr(PyObject.TO)
- # state.borrowed_objects owns the reference
state = space.fromcache(RefcountState)
- obj_ptr = rffi.cast(ADDR, ref)
- if obj_ptr not in state.borrowed_objects:
- state.borrowed_objects[obj_ptr] = None
- else:
- Py_DecRef(space, ref) # already in borrowed list
-
- if w_container is None: # self-managed
- return ref
- borrowees = state.borrow_mapping.setdefault(w_container, {})
- borrowees[w_borrowed] = None
- return ref
+ return state.make_borrowed(w_container, w_borrowed)
class BorrowPair:
"""
@@ -361,36 +412,6 @@
def borrow_from(container, borrowed):
return BorrowPair(container, borrowed)
-def forget_borrowee(space, w_obj):
- "De-register an object from the list of borrowed references"
- state = space.fromcache(RefcountState)
- ref = state.py_objects_w2r.get(w_obj, lltype.nullptr(PyObject.TO))
- if not ref:
- if DEBUG_REFCOUNT:
- print >>sys.stderr, "Borrowed object is already gone:", \
- hex(containee)
- return
-
- containee_ptr = rffi.cast(ADDR, ref)
- try:
- del state.borrowed_objects[containee_ptr]
- except KeyError:
- pass
- else:
- Py_DecRef(space, ref)
-
-def delete_borrower(space, w_obj):
- """
- Called when a potential container for borrowed references has lost its
- last reference. Removes the borrowed references it contains.
- """
- state = space.fromcache(RefcountState)
- if w_obj in state.borrow_mapping: # move to lifeline __del__
- for w_containee in state.borrow_mapping[w_obj]:
- forget_borrowee(space, w_containee)
- del state.borrow_mapping[w_obj]
-
-
#___________________________________________________________
@cpython_api([rffi.VOIDP_real], lltype.Signed, error=CANNOT_FAIL)
Modified: pypy/trunk/pypy/module/cpyext/state.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/state.py (original)
+++ pypy/trunk/pypy/module/cpyext/state.py Wed May 19 01:55:11 2010
@@ -29,17 +29,9 @@
self.operror = operror
def clear_exception(self):
- """Clear the current exception state, and return the operror.
- Also frees the borrowed reference returned by PyErr_Occurred()
- """
+ """Clear the current exception state, and return the operror."""
from pypy.module.cpyext.api import ADDR
- # handling of borrowed objects, remove when we have
- # a weakkeydict
operror = self.operror
- if operror is not None:
- # we have no explicit container
- from pypy.module.cpyext.pyobject import forget_borrowee
- forget_borrowee(self.space, operror.w_type)
self.operror = None
return operror
Modified: pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/test_cpyext.py (original)
+++ pypy/trunk/pypy/module/cpyext/test/test_cpyext.py Wed May 19 01:55:11 2010
@@ -249,14 +249,11 @@
def unimport_module(self, name):
"""
- Remove the named module from the space's sys.modules and discard the
- reference (owned by "the test") to it.
+ Remove the named module from the space's sys.modules.
"""
w_modules = self.space.sys.get('modules')
w_name = self.space.wrap(name)
- w_mod = self.space.getitem(w_modules, w_name)
self.space.delitem(w_modules, w_name)
- Py_DecRef(self.space, w_mod)
def teardown_method(self, func):
for name in self.imported_module_names:
More information about the Pypy-commit
mailing list