[pypy-commit] pypy cpyext-gc-support: Deallocators
arigo
noreply at buildbot.pypy.org
Wed Oct 21 04:50:55 EDT 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cpyext-gc-support
Changeset: r80371:59c2d992bc0e
Date: 2015-10-21 10:48 +0200
http://bitbucket.org/pypy/pypy/changeset/59c2d992bc0e/
Log: Deallocators
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -262,6 +262,7 @@
rffi.cast(restype, 0) == 0)
def decorate(func):
+ func._always_inline_ = 'try'
func_name = func.func_name
if external:
c_name = None
@@ -355,7 +356,6 @@
return res
unwrapper.func = func
unwrapper.api_func = api_function
- unwrapper._always_inline_ = 'try'
return unwrapper
unwrapper_catch = make_unwrapper(True)
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -38,7 +38,7 @@
fill_pyobj: called to fill the PyObject after attaching is done
alloc_pypy: function called to create a PyPy object from a PyObject
fill_pypy: called to fill the PyPy object after attaching is done
- dealloc : a cpython_api(external=False), similar to PyObject_dealloc
+ dealloc: function called with the pyobj when the refcount drops to zero
"""
tp_basestruct = kw.pop('basestruct', PyObject.TO)
@@ -46,11 +46,11 @@
tp_fill_pyobj = kw.pop('fill_pyobj', None)
tp_alloc_pypy = kw.pop('alloc_pypy', None)
tp_fill_pypy = kw.pop('fill_pypy', None)
+ tp_dealloc = kw.pop('dealloc', None)
force_create_pyobj = kw.pop('force_create_pyobj', False)
realize_subclass_of = kw.pop('realize_subclass_of', None)
alloc_pypy_light_if = kw.pop('alloc_pypy_light_if', None)
- #tp_dealloc = kw.pop('dealloc', None)
- assert not kw, "Extra arguments to make_typedescr: %s" % kw.keys()
+ assert not kw, "Extra arguments to setup_class_for_cpyext: %s" % kw.keys()
assert 'cpyext_basestruct' not in W_Class.__dict__ # double set
@@ -86,7 +86,7 @@
keepalive_until_here(self)
W_Class.cpyext_fill_prebuilt_pyobj = cpyext_fill_prebuilt_pyobj
- if tp_alloc_pyobj or tp_fill_pyobj or realize_subclass_of:
+ if tp_alloc_pyobj or tp_fill_pyobj or realize_subclass_of or tp_dealloc:
if realize_subclass_of is None:
realize_subclass_of = W_Class
#
@@ -116,6 +116,19 @@
assert 'cpyext_create_pypy' not in typedef.__dict__
typedef.cpyext_create_pypy = cpyext_create_pypy
+ if tp_dealloc:
+ @cpython_api([PyObject], lltype.Void,
+ external=False, error=CANNOT_FAIL)
+ def dealloc(space, py_obj):
+ tp_dealloc(space, rffi.cast(lltype.Ptr(tp_basestruct), py_obj))
+ #
+ def cpyext_get_dealloc(space):
+ return llhelper(dealloc.api_func.functype,
+ dealloc.api_func.get_wrapper(space))
+ #
+ assert 'cpyext_get_dealloc' not in typedef.__dict__
+ typedef.cpyext_get_dealloc = cpyext_get_dealloc
+
W_Class.cpyext_basestruct = tp_basestruct
@@ -157,10 +170,17 @@
@bootstrap_function
def init_pyobject(space):
setup_class_for_cpyext(W_Root, force_create_pyobj=True,
- realize_subclass_of=W_ObjectObject)
+ realize_subclass_of=W_ObjectObject,
+ dealloc=_default_dealloc)
# use this cpyext_create_pypy as the default for all other TypeDefs
from pypy.interpreter.typedef import TypeDef
- TypeDef.cpyext_create_pypy = W_ObjectObject.typedef.cpyext_create_pypy
+ TypeDef.cpyext_create_pypy = staticmethod(
+ W_ObjectObject.typedef.cpyext_create_pypy)
+ TypeDef.cpyext_get_dealloc = staticmethod(
+ W_ObjectObject.typedef.cpyext_get_dealloc)
+
+def _default_dealloc(space, py_obj):
+ lltype.free(py_obj, flavor='raw', track_allocation=False)
#________________________________________________________
@@ -479,24 +499,6 @@
# "'s type which is", rffi.charp2str(pto.c_tp_name)
generic_cpy_call(space, pto.c_tp_dealloc, obj)
-#___________________________________________________________
-# Support for "lifelines"
-#
-# Object structure must stay alive even when not referenced
-# by any C code.
-
-class PyOLifeline(object):
- def __init__(self, space, pyo):
- ZZZ
- self.pyo = pyo
- self.space = space
-
- def __del__(self):
- if self.pyo:
- assert self.pyo.c_ob_refcnt == 0
- _Py_Dealloc(self.space, self.pyo)
- self.pyo = lltype.nullptr(PyObject.TO)
- # XXX handle borrowed objects here
#___________________________________________________________
# Support for borrowed references
diff --git a/pypy/module/cpyext/test/test_tupleobject.py b/pypy/module/cpyext/test/test_tupleobject.py
--- a/pypy/module/cpyext/test/test_tupleobject.py
+++ b/pypy/module/cpyext/test/test_tupleobject.py
@@ -1,7 +1,7 @@
import py
from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
-from pypy.module.cpyext.pyobject import PyObject, PyObjectP
+from pypy.module.cpyext.pyobject import PyObject, PyObjectP, debug_collect
from pypy.module.cpyext.test.test_api import BaseApiTest
from rpython.rtyper.lltypesystem import rffi, lltype
@@ -26,6 +26,14 @@
w_obj2 = api.from_pyobj(api.PyTuple_GetItem(atuple, 1))
assert space.eq_w(w_obj1, space.wrap(10))
assert space.eq_w(w_obj2, space.wrap(11))
+ #
+ # one reference from the PyTupleObject
+ assert api.as_pyobj(w_obj1).c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT + 1
+ assert api.as_pyobj(w_obj2).c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT + 1
+ del atuple
+ debug_collect()
+ assert api.as_pyobj(w_obj1).c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT
+ assert api.as_pyobj(w_obj2).c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT
def test_tupleobject_spec_oo(self, space, api):
w_obj1 = space.newlist([])
@@ -34,6 +42,14 @@
assert api.PyTuple_Size(atuple) == 2
assert api.from_pyobj(api.PyTuple_GetItem(atuple, 0)) is w_obj1
assert api.from_pyobj(api.PyTuple_GetItem(atuple, 1)) is w_obj2
+ #
+ # no reference from the PyTupleObject: it is borrowed
+ assert api.as_pyobj(w_obj1).c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT
+ assert api.as_pyobj(w_obj2).c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT
+ del atuple
+ debug_collect()
+ assert api.as_pyobj(w_obj1).c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT
+ assert api.as_pyobj(w_obj2).c_ob_refcnt == REFCNT_FROM_PYPY_LIGHT
def test_new_setitem(self, space, api):
w_obj1 = space.newlist([])
diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -4,7 +4,7 @@
cpython_struct, PyVarObjectFields, build_type_checkers3, bootstrap_function)
from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef,
setup_class_for_cpyext, as_pyobj, get_pyobj_and_incref, from_pyobj,
- pyobj_has_w_obj, RRC_PERMANENT, RRC_PERMANENT_LIGHT, new_pyobj)
+ pyobj_has_w_obj, RRC_PERMANENT, RRC_PERMANENT_LIGHT, new_pyobj, xdecref)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.objspace.std.tupleobject import W_TupleObject, W_AbstractTupleObject
@@ -34,6 +34,10 @@
# --and then we call this function to initialize the W_TupleObject--
fill_pypy=tuple_fill_pypy,
+
+ # --deallocator, *not* called if tuple_alloc_pyobj() made a
+ # PyTupleObject of borrowed items--
+ dealloc=tuple_dealloc,
)
def tuple_alloc_pyobj(space, w_obj):
@@ -63,6 +67,11 @@
for i in range(py_tuple.c_ob_size)]
W_TupleObject.__init__(w_obj, objects_w)
+def tuple_dealloc(space, py_tup):
+ for i in range(py_tup.c_ob_size):
+ xdecref(space, py_tup.c_ob_item[i])
+ lltype.free(py_tup, flavor='raw', track_allocation=False)
+
@cpython_api([Py_ssize_t], PyObject)
def PyTuple_New(space, size):
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -428,7 +428,8 @@
w_type.cpyext_c_type_object = pto
# dealloc
- #pto.c_tp_dealloc = typedescr.get_dealloc(space) ZZZ
+ pto.c_tp_dealloc = w_type.instancetypedef.cpyext_get_dealloc(space)
+
# buffer protocol
if space.is_w(w_type, space.w_str):
setup_string_buffer_procs(space, pto)
More information about the pypy-commit
mailing list