Author: Matti Picus <[email protected]>
Branch:
Changeset: r94262:be473ba66a18
Date: 2018-04-08 00:42 +0300
http://bitbucket.org/pypy/pypy/changeset/be473ba66a18/
Log: merge cpyext-subclass-setattr which fixes cpyext pyobjects "losing"
a w_obj
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
@@ -640,7 +640,7 @@
'Py_DivisionWarningFlag', 'Py_DontWriteBytecodeFlag',
'Py_NoUserSiteDirectory',
'_Py_QnewFlag', 'Py_Py3kWarningFlag', 'Py_HashRandomizationFlag',
'_Py_PackageContext',
'_PyTraceMalloc_Track', '_PyTraceMalloc_Untrack', 'PyMem_Malloc',
- 'Py_IncRef', 'Py_DecRef', 'PyObject_Free', 'PyObject_GC_Del',
'PyType_GenericAlloc',
+ 'PyObject_Free', 'PyObject_GC_Del', 'PyType_GenericAlloc',
'_PyObject_New', '_PyObject_NewVar',
'_PyObject_GC_New', '_PyObject_GC_NewVar',
'PyObject_Init', 'PyObject_InitVar', 'PyInt_FromLong',
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
@@ -60,10 +60,10 @@
def _cpyext_attach_pyobj(self, space, py_obj):
self._cpy_ref = py_obj
- rawrefcount.create_link_pyobj(self, py_obj)
+ rawrefcount.create_link_pypy(self, py_obj)
cls._cpyext_attach_pyobj = _cpyext_attach_pyobj
-add_direct_pyobj_storage(W_BaseCPyObject)
+add_direct_pyobj_storage(W_BaseCPyObject)
add_direct_pyobj_storage(W_TypeObject)
add_direct_pyobj_storage(W_NoneObject)
add_direct_pyobj_storage(W_BoolObject)
@@ -414,3 +414,14 @@
@cpython_api([rffi.VOIDP], lltype.Signed, error=CANNOT_FAIL)
def _Py_HashPointer(space, ptr):
return rffi.cast(lltype.Signed, ptr)
+
+@cpython_api([PyObject], lltype.Void)
+def Py_IncRef(space, obj):
+ # used only ifdef PYPY_DEBUG_REFCOUNT
+ if obj:
+ incref(space, obj)
+
+@cpython_api([PyObject], lltype.Void)
+def Py_DecRef(space, obj):
+ # used only ifdef PYPY_DEBUG_REFCOUNT
+ decref(space, obj)
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
@@ -5,18 +5,6 @@
extern void _PyPy_Free(void *ptr);
extern void *_PyPy_Malloc(Py_ssize_t size);
-void
-Py_IncRef(PyObject *o)
-{
- Py_XINCREF(o);
-}
-
-void
-Py_DecRef(PyObject *o)
-{
- Py_XDECREF(o);
-}
-
/*
* The actual value of this variable will be the address of
* pyobject.w_marker_deallocating, and will be set by
diff --git a/pypy/module/cpyext/test/array.c b/pypy/module/cpyext/test/array.c
--- a/pypy/module/cpyext/test/array.c
+++ b/pypy/module/cpyext/test/array.c
@@ -2492,6 +2492,87 @@
return PyLong_FromLong(obj1->ob_type->tp_dealloc ==
obj2->ob_type->tp_dealloc);
}
+static PyObject *
+subclass_with_attribute(PyObject *self, PyObject* args) {
+ /* what happens when we use tp_alloc to create the subclass, then
+ * assign to the w_obj via python, then get the GC to collect?
+ * The w_obj should not be collected!!
+ */
+ PyObject * obj, *sub, *attrib, *funcname, *attribname, *collect, *res,
*tup;
+ PyTypeObject * subtype;
+ int i;
+ if (!PyArg_ParseTuple(args, "OOOO", &obj, &funcname, &attribname,
&collect)) {
+ return NULL;
+ }
+ if (!PyType_Check(obj)) {
+ PyErr_SetString(PyExc_TypeError,
+ "expected type object");
+ return NULL;
+ }
+ subtype = (PyTypeObject*)obj;
+ sub = subtype->tp_alloc(subtype, 0);
+ if (!sub) {
+ return NULL;
+ }
+ attrib = PyObject_GetAttr(sub, funcname);
+ if (!attrib || (attrib == Py_None) ) {
+ PyErr_SetString(PyExc_ValueError,
+ "could not find function to call");
+ Py_XDECREF(attrib);
+ Py_DECREF(sub);
+ return NULL;
+ }
+ tup = PyTuple_New(0);
+ /*
+ #ifdef PYPY_VERSION
+ printf("calling addattrib pypylink %lu \n", sub->ob_pypy_link);
+ #endif
+ */
+ res = PyObject_Call(attrib, tup, NULL);
+ /*
+ #ifdef PYPY_VERSION
+ printf("after addattrib pypylink %lu \n", sub->ob_pypy_link);
+ #endif
+ */
+ Py_DECREF(attrib);
+ if (res == NULL) {
+ Py_DECREF(tup);
+ Py_DECREF(sub);
+ return NULL;
+ }
+ Py_DECREF(res);
+ for(i=0; i<10; i++) {
+ /*
+ #ifdef PYPY_VERSION
+ printf("starting loop iteration %d refcnt %lu pypylink %lu \n", i,
+ sub->ob_refcnt, sub->ob_pypy_link);
+ #else
+ printf("starting loop iteration %d refcnt %lu\n", i,
sub->ob_refcnt);
+ #endif
+ */
+ attrib = PyObject_GetAttr(sub, attribname);
+ if (!attrib || (attrib == Py_None)) {
+ PyErr_SetString(PyExc_ValueError,
+ "could not find attrib on object");
+ Py_XDECREF(attrib);
+ Py_DECREF(tup);
+ Py_DECREF(sub);
+ return NULL;
+ }
+ Py_XDECREF(attrib);
+ res = PyObject_Call(collect, tup, NULL);
+ if (res == NULL) {
+ Py_DECREF(tup);
+ Py_DECREF(sub);
+ return NULL;
+ }
+ Py_DECREF(res);
+ }
+ Py_DECREF(tup);
+ Py_DECREF(sub);
+ Py_RETURN_NONE;
+}
+
/*********************** Install Module **************************/
static PyMethodDef a_methods[] = {
@@ -2502,6 +2583,7 @@
{"create_and_release_buffer", (PyCFunction)create_and_release_buffer,
METH_O, NULL},
{"same_dealloc", (PyCFunction)same_dealloc, METH_VARARGS, NULL},
{"getitem", (PyCFunction)getitem, METH_VARARGS, NULL},
+ {"subclass_with_attribute", (PyCFunction)subclass_with_attribute,
METH_VARARGS, NULL},
{NULL, NULL, 0, NULL} /* Sentinel */
};
diff --git a/pypy/module/cpyext/test/test_arraymodule.py
b/pypy/module/cpyext/test/test_arraymodule.py
--- a/pypy/module/cpyext/test/test_arraymodule.py
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -186,3 +186,15 @@
# array_subscr does)
raises(IndexError, module.getitem, a, -5)
+ def test_subclass_with_attribute(self):
+ module = self.import_module(name='array')
+ class Sub(module.array):
+ def addattrib(self):
+ print('called addattrib')
+ self.attrib = True
+ import gc
+ module.subclass_with_attribute(Sub, "addattrib", "attrib", gc.collect)
+ if self.runappdirect:
+ assert Sub.__module__ == 'pypy.module.cpyext.test.test_arraymodule'
+ assert str(Sub) == "<class
'pypy.module.cpyext.test.test_arraymodule.Sub'>"
+
diff --git a/pypy/module/cpyext/test/test_typeobject.py
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -5,7 +5,7 @@
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.api import generic_cpy_call
from pypy.module.cpyext.pyobject import make_ref, from_ref, decref, as_pyobj
-from pypy.module.cpyext.typeobject import PyTypeObjectPtr
+from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject
class AppTestTypeObject(AppTestCpythonExtensionBase):
@@ -412,33 +412,42 @@
def test_type_dict(self):
foo = self.import_module("foo")
module = self.import_extension('test', [
- ("hack_tp_dict", "METH_O",
+ ("hack_tp_dict", "METH_VARARGS",
'''
- PyTypeObject *type = args->ob_type;
+ PyTypeObject *type, *obj;
PyObject *a1 = PyLong_FromLong(1);
PyObject *a2 = PyLong_FromLong(2);
PyObject *value;
+ PyObject * key;
+ if (!PyArg_ParseTuple(args, "OO", &obj, &key))
+ return NULL;
+ type = obj->ob_type;
- if (PyDict_SetItemString(type->tp_dict, "a",
+ if (PyDict_SetItem(type->tp_dict, key,
a1) < 0)
return NULL;
Py_DECREF(a1);
PyType_Modified(type);
- value = PyObject_GetAttrString((PyObject *)type, "a");
+ value = PyObject_GetAttr((PyObject *)type, key);
Py_DECREF(value);
- if (PyDict_SetItemString(type->tp_dict, "a",
+ if (PyDict_SetItem(type->tp_dict, key,
a2) < 0)
return NULL;
Py_DECREF(a2);
PyType_Modified(type);
- value = PyObject_GetAttrString((PyObject *)type, "a");
+ value = PyObject_GetAttr((PyObject *)type, key);
return value;
'''
)
])
obj = foo.new()
- assert module.hack_tp_dict(obj) == 2
+ assert module.hack_tp_dict(obj, "a") == 2
+ class Sub(foo.fooType):
+ pass
+ obj = Sub()
+ assert module.hack_tp_dict(obj, "b") == 2
+
def test_tp_descr_get(self):
module = self.import_extension('foo', [
@@ -560,6 +569,23 @@
assert w_obj is None
assert api.PyErr_Occurred() is None
+ def test_subclass_not_PyCTypeObject(self, space, api):
+ pyobj = make_ref(space, api.PyLong_Type)
+ py_type = rffi.cast(PyTypeObjectPtr, pyobj)
+ w_pyclass = W_PyCTypeObject(space, py_type)
+ w_class = space.appexec([w_pyclass], """(base):
+ class Sub(base):
+ def addattrib(self, value):
+ self.attrib = value
+ return Sub
+ """)
+ assert w_pyclass in w_class.mro_w
+ assert isinstance(w_pyclass, W_PyCTypeObject)
+ assert not isinstance(w_class, W_PyCTypeObject)
+ assert w_pyclass.is_cpytype()
+ # XXX document the current status, not clear if this is desirable
+ assert w_class.is_cpytype()
+
class AppTestSlots(AppTestCpythonExtensionBase):
def setup_class(cls):
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
@@ -1,6 +1,6 @@
import os
-from rpython.rlib import jit
+from rpython.rlib import jit, rawrefcount
from rpython.rlib.objectmodel import specialize, we_are_translated
from rpython.rtyper.lltypesystem import rffi, lltype
@@ -517,6 +517,10 @@
self.w_doc = space.newtext(
rffi.charp2str(cts.cast('char*', pto.c_tp_doc)))
+ def _cpyext_attach_pyobj(self, space, py_obj):
+ self._cpy_ref = py_obj
+ rawrefcount.create_link_pyobj(self, py_obj)
+
@bootstrap_function
def init_typeobject(space):
make_typedescr(space.w_type.layout.typedef,
@@ -777,7 +781,6 @@
try:
w_obj = _type_realize(space, py_obj)
finally:
- name = rffi.charp2str(cts.cast('char*', pto.c_tp_name))
pto.c_tp_flags &= ~Py_TPFLAGS_READYING
pto.c_tp_flags |= Py_TPFLAGS_READY
return w_obj
@@ -884,7 +887,6 @@
base = pto.c_tp_base
base_pyo = rffi.cast(PyObject, pto.c_tp_base)
if base and not base.c_tp_flags & Py_TPFLAGS_READY:
- name = rffi.charp2str(cts.cast('char*', base.c_tp_name))
type_realize(space, base_pyo)
if base and not pto.c_ob_type: # will be filled later
pto.c_ob_type = base.c_ob_type
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit