Author: Matti Picus <matti.pi...@gmail.com>
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
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to