[pypy-commit] pypy cpyext-gc-cycle: Fixed some (de)allocation bugs in existing and derived gc cpyext-classes
stevie_92
pypy.commits at gmail.com
Fri May 10 02:13:31 EDT 2019
Author: Stefan Beyer <home at sbeyer.at>
Branch: cpyext-gc-cycle
Changeset: r96591:0dff3316692e
Date: 2019-05-09 23:32 +0200
http://bitbucket.org/pypy/pypy/changeset/0dff3316692e/
Log: Fixed some (de)allocation bugs in existing and derived gc cpyext-
classes
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
@@ -129,7 +129,7 @@
Py_TPFLAGS_READY Py_TPFLAGS_READYING
METH_COEXIST METH_STATIC METH_CLASS Py_TPFLAGS_BASETYPE Py_MAX_FMT
METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O
-Py_TPFLAGS_HEAPTYPE
+Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_GC
Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_MAX_NDIMS
Py_CLEANUP_SUPPORTED
PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES PyBUF_WRITABLE PyBUF_SIMPLE PyBUF_WRITE
@@ -1182,6 +1182,9 @@
[Py_ssize_t], PyObject,
compilation_info=eci,
_nowrapper=True)
+ state.C._PyPy_tuple_free = rffi.llexternal(
+ '_PyPy_tuple_free', [rffi.VOIDP], lltype.Void,
+ compilation_info=eci, _nowrapper=True)
state.C._PyPy_tuple_dealloc = rffi.llexternal(
'_PyPy_tuple_dealloc', [PyObject], lltype.Void,
compilation_info=eci, _nowrapper=True)
diff --git a/pypy/module/cpyext/include/tupleobject.h b/pypy/module/cpyext/include/tupleobject.h
--- a/pypy/module/cpyext/include/tupleobject.h
+++ b/pypy/module/cpyext/include/tupleobject.h
@@ -18,6 +18,7 @@
PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size);
PyAPI_FUNC(void) _PyPy_tuple_dealloc(PyObject *);
+PyAPI_FUNC(void) _PyPy_tuple_free(void *);
/* defined in varargswrapper.c */
PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...);
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
@@ -7,7 +7,7 @@
from pypy.module.cpyext.api import (
cpython_api, bootstrap_function, PyObject, PyObjectP, ADDR,
CANNOT_FAIL, Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr, is_PyObject,
- PyVarObject, Py_ssize_t, init_function, cts)
+ PyVarObject, Py_ssize_t, init_function, cts, Py_TPFLAGS_HAVE_GC)
from pypy.module.cpyext.state import State
from pypy.objspace.std.typeobject import W_TypeObject
from pypy.objspace.std.noneobject import W_NoneObject
@@ -77,37 +77,17 @@
state = space.fromcache(State)
return state.C._PyPy_subtype_dealloc
- # CCC port to C
+ def get_free(self, space):
+ state = space.fromcache(State)
+ return state.C.PyObject_Free
+
def allocate(self, space, w_type, itemcount=0, immortal=False):
- # typically called from PyType_GenericAlloc via typedescr.allocate
- # this returns a PyObject with ob_refcnt == 1.
-
- pytype = as_pyobj(space, w_type)
- pytype = rffi.cast(PyTypeObjectPtr, pytype)
- assert pytype
- # Don't increase refcount for non-heaptypes
- flags = rffi.cast(lltype.Signed, pytype.c_tp_flags)
- if flags & Py_TPFLAGS_HEAPTYPE:
- incref(space, pytype)
-
- if pytype:
- size = pytype.c_tp_basicsize
- else:
- size = rffi.sizeof(self.basestruct)
- if pytype.c_tp_itemsize:
- size += itemcount * pytype.c_tp_itemsize
- assert size >= rffi.sizeof(PyObject.TO)
- buf = lltype.malloc(rffi.VOIDP.TO, size,
- flavor='raw', zero=True,
- add_memory_pressure=True, immortal=immortal)
- pyobj = rffi.cast(PyObject, buf)
- if pytype.c_tp_itemsize:
- pyvarobj = rffi.cast(PyVarObject, pyobj)
- pyvarobj.c_ob_size = itemcount
- pyobj.c_ob_refcnt = 1
- #pyobj.c_ob_pypy_link should get assigned very quickly
- pyobj.c_ob_type = pytype
- return pyobj
+ state = space.fromcache(State)
+ ob_type = rffi.cast(PyTypeObjectPtr, as_pyobj(space, w_type))
+ ptup = state.ccall("PyType_GenericAlloc", ob_type, itemcount)
+ if not ptup:
+ state.check_and_raise_exception(always=True)
+ return ptup
def attach(self, space, pyobj, w_obj, w_userdata=None):
pass
@@ -140,6 +120,7 @@
attach : Function called to tie a raw structure to a pypy object
realize : Function called to create a pypy object from a raw struct
dealloc : a @slot_function(), similar to PyObject_dealloc
+ free : a @slot_function(), similar to PyObject_free
"""
tp_basestruct = kw.pop('basestruct', PyObject.TO)
@@ -147,6 +128,7 @@
tp_attach = kw.pop('attach', None)
tp_realize = kw.pop('realize', None)
tp_dealloc = kw.pop('dealloc', None)
+ tp_free = kw.pop('free', None)
assert not kw, "Extra arguments to make_typedescr"
null_dealloc = lltype.nullptr(lltype.FuncType([PyObject], lltype.Void))
@@ -166,6 +148,10 @@
def get_dealloc(self, space):
return tp_dealloc
+ if tp_free:
+ def get_free(self, space):
+ return tp_free
+
if tp_attach:
def attach(self, space, pyobj, w_obj, w_userdata=None):
tp_attach(space, pyobj, w_obj, w_userdata)
diff --git a/pypy/module/cpyext/src/object.c b/pypy/module/cpyext/src/object.c
--- a/pypy/module/cpyext/src/object.c
+++ b/pypy/module/cpyext/src/object.c
@@ -132,7 +132,10 @@
PyObject *
PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
{
- return (PyObject*)_PyObject_NewVar(type, nitems);
+ if (PyType_IS_GC(type))
+ return (PyObject*)_PyObject_GC_NewVar(type, nitems);
+ else
+ return (PyObject*)_PyObject_NewVar(type, nitems);
}
PyObject *
diff --git a/pypy/module/cpyext/src/tupleobject.c b/pypy/module/cpyext/src/tupleobject.c
--- a/pypy/module/cpyext/src/tupleobject.c
+++ b/pypy/module/cpyext/src/tupleobject.c
@@ -89,3 +89,9 @@
done:
Py_TRASHCAN_SAFE_END(op)
}
+
+void
+_PyPy_tuple_free(void *obj)
+{
+ PyObject_GC_Del(obj);
+}
\ No newline at end of file
diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -822,7 +822,7 @@
if (PyType_Ready(&UnicodeSubtype3) < 0)
INITERROR;
- TupleLike.tp_flags = Py_TPFLAGS_DEFAULT;
+ TupleLike.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC;
TupleLike.tp_base = &PyTuple_Type;
if (PyType_Ready(&TupleLike) < 0)
INITERROR;
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,10 +4,11 @@
from rpython.rlib.debug import fatalerror_notb
from pypy.module.cpyext.api import (
cpython_api, Py_ssize_t, build_type_checkers_flags,
- PyVarObjectFields, cpython_struct, bootstrap_function, slot_function)
+ PyVarObjectFields, cpython_struct, bootstrap_function, slot_function,
+ PyTypeObjectPtr)
from pypy.module.cpyext.pyobject import (
PyObject, PyObjectP, make_ref, from_ref, decref, incref, BaseCpyTypedescr,
- track_reference, make_typedescr, get_typedescr, pyobj_has_w_obj)
+ track_reference, make_typedescr, get_typedescr, pyobj_has_w_obj, as_pyobj)
from pypy.module.cpyext.state import State
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.objspace.std.tupleobject import W_TupleObject
@@ -44,7 +45,8 @@
attach=tuple_attach,
alloc=tuple_alloc,
dealloc=state.C._PyPy_tuple_dealloc,
- realize=tuple_realize)
+ realize=tuple_realize,
+ free=state.C._PyPy_tuple_free)
PyTuple_Check, PyTuple_CheckExact = build_type_checkers_flags("Tuple")
@@ -65,7 +67,13 @@
state.check_and_raise_exception(always=True)
return ptup
else:
- return BaseCpyTypedescr.allocate(typedescr, space, w_type, itemcount)
+ if not we_are_translated() and itemcount == _BAD_ITEMCOUNT:
+ itemcount = -42
+ ob_type = rffi.cast(PyTypeObjectPtr, as_pyobj(space, w_type))
+ ptup = state.ccall("PyType_GenericAlloc", ob_type, itemcount)
+ if not ptup:
+ state.check_and_raise_exception(always=True)
+ return ptup
def tuple_attach(space, py_obj, w_obj, w_userdata=None):
"""
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
@@ -20,7 +20,7 @@
Py_TPFLAGS_DICT_SUBCLASS, Py_TPFLAGS_BASE_EXC_SUBCLASS,
Py_TPFLAGS_TYPE_SUBCLASS,
Py_TPFLAGS_BYTES_SUBCLASS,
- Py_TPPYPYFLAGS_FLOAT_SUBCLASS,
+ Py_TPPYPYFLAGS_FLOAT_SUBCLASS, Py_TPFLAGS_HAVE_GC
)
from pypy.module.cpyext.cparser import CTypeSpace
@@ -419,6 +419,8 @@
if pto.c_tp_itemsize < base_pto.c_tp_itemsize:
pto.c_tp_itemsize = base_pto.c_tp_itemsize
+ pto.c_tp_flags |= (base_pto.c_tp_flags & Py_TPFLAGS_HAVE_GC)
+
#/* Setup fast subclass flags */
if space.issubtype_w(w_obj, space.w_BaseException):
pto.c_tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS
@@ -432,6 +434,7 @@
pto.c_tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS
elif space.issubtype_w(w_obj, space.w_tuple):
pto.c_tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS
+ pto.c_tp_flags |= Py_TPFLAGS_HAVE_GC
elif space.issubtype_w(w_obj, space.w_list):
pto.c_tp_flags |= Py_TPFLAGS_LIST_SUBCLASS
elif space.issubtype_w(w_obj, space.w_dict):
@@ -606,9 +609,9 @@
pto.c_tp_itemsize = 1
elif space.is_w(w_type, space.w_tuple):
pto.c_tp_itemsize = rffi.sizeof(PyObject)
+ pto.c_tp_flags |= Py_TPFLAGS_HAVE_GC
state = space.fromcache(State)
- pto.c_tp_free = state.C.PyObject_Free
pto.c_tp_alloc = state.C.PyType_GenericAlloc
builder = state.builder
if ((pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE) != 0
@@ -643,6 +646,15 @@
# strange, but happens (ABCMeta)
pto.c_tp_dealloc = state.C._PyPy_subtype_dealloc
+ # free
+ if space.gettypeobject(w_type.layout.typedef) is w_type:
+ # only for the exact type, like 'space.w_tuple' or 'space.w_list'
+ pto.c_tp_free = typedescr.get_free(space)
+ else:
+ pto.c_tp_free = pto.c_tp_base.c_tp_free
+
+ # TODO: traverse (for tuple)
+
if builder.cpyext_type_init is not None:
builder.cpyext_type_init.append((pto, w_type))
else:
More information about the pypy-commit
mailing list