[pypy-svn] r79789 - in pypy/trunk/pypy/module/cpyext: . include test

arigo at codespeak.net arigo at codespeak.net
Fri Dec 3 18:50:47 CET 2010


Author: arigo
Date: Fri Dec  3 18:50:42 2010
New Revision: 79789

Modified:
   pypy/trunk/pypy/module/cpyext/api.py
   pypy/trunk/pypy/module/cpyext/include/tupleobject.h
   pypy/trunk/pypy/module/cpyext/slotdefs.py
   pypy/trunk/pypy/module/cpyext/test/test_cpyext.py
   pypy/trunk/pypy/module/cpyext/test/test_tupleobject.py
   pypy/trunk/pypy/module/cpyext/tupleobject.py
Log:
Partially revert r79688.  More precisely, revert the changes to cpyext that
were done in the rlist-jit branch.  After much searching it seems to be the
cause of the random crashes we systematically get nowadays trying to run
"pypy translate.py".  Without it, it seems to work fine again.


Modified: pypy/trunk/pypy/module/cpyext/api.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/api.py	(original)
+++ pypy/trunk/pypy/module/cpyext/api.py	Fri Dec  3 18:50:42 2010
@@ -369,7 +369,7 @@
         }.items():
         GLOBALS['Py%s_Type#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
 
-    for cpyname in 'Method List Int Long Dict Class'.split():
+    for cpyname in 'Method List Int Long Dict Tuple Class'.split():
         FORWARD_DECLS.append('typedef struct { PyObject_HEAD } '
                              'Py%sObject' % (cpyname, ))
 build_exported_objects()

Modified: pypy/trunk/pypy/module/cpyext/include/tupleobject.h
==============================================================================
--- pypy/trunk/pypy/module/cpyext/include/tupleobject.h	(original)
+++ pypy/trunk/pypy/module/cpyext/include/tupleobject.h	Fri Dec  3 18:50:42 2010
@@ -10,19 +10,9 @@
 /* defined in varargswrapper.c */
 PyObject * PyTuple_Pack(Py_ssize_t, ...);
 
-typedef struct {
-    PyObject_HEAD
-    PyObject **items;
-    Py_ssize_t size;
-} PyTupleObject;
+#define PyTuple_SET_ITEM PyTuple_SetItem
+#define PyTuple_GET_ITEM PyTuple_GetItem
 
-#define PyTuple_GET_ITEM        PyTuple_GetItem
-
-/* Macro, trading safety for speed */
-#define PyTuple_GET_SIZE(op)    (((PyTupleObject *)(op))->size)
-
-/* Macro, *only* to be used to fill in brand new tuples */
-#define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->items[i] = v)
 
 #ifdef __cplusplus
 }

Modified: pypy/trunk/pypy/module/cpyext/slotdefs.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/slotdefs.py	(original)
+++ pypy/trunk/pypy/module/cpyext/slotdefs.py	Fri Dec  3 18:50:42 2010
@@ -28,14 +28,14 @@
 
 def check_num_args(space, ob, n):
     from pypy.module.cpyext.tupleobject import PyTuple_CheckExact, \
-            _PyTuple_Size_Fast
+            PyTuple_GET_SIZE
     if not PyTuple_CheckExact(space, ob):
         raise OperationError(space.w_SystemError,
             space.wrap("PyArg_UnpackTuple() argument list is not a tuple"))
-    if n == _PyTuple_Size_Fast(space, ob):
+    if n == PyTuple_GET_SIZE(space, ob):
         return
     raise operationerrfmt(space.w_TypeError,
-        "expected %d arguments, got %d", n, _PyTuple_Size_Fast(space, ob))
+        "expected %d arguments, got %d", n, PyTuple_GET_SIZE(space, ob))
 
 def wrap_init(space, w_self, w_args, func, w_kwargs):
     func_init = rffi.cast(initproc, func)

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	Fri Dec  3 18:50:42 2010
@@ -545,17 +545,16 @@
             PyObject *true = Py_True;
             PyObject *tup = NULL;
             int refcnt = true->ob_refcnt;
-            int refcnt_middle, refcnt_after;
+            int refcnt_after;
 
             tup = PyTuple_New(1);
             Py_INCREF(true);
             if (PyTuple_SetItem(tup, 0, true) < 0)
                 return NULL;
-            refcnt_middle = true->ob_refcnt;
-            Py_DECREF(tup);
             refcnt_after = true->ob_refcnt;
-            fprintf(stderr, "REFCNT2 %i %i %i\\n", refcnt, refcnt_middle, refcnt_after);
-            return PyBool_FromLong(refcnt_after == refcnt && refcnt_middle == refcnt+1);
+            Py_DECREF(tup);
+            fprintf(stderr, "REFCNT2 %i %i\\n", refcnt, refcnt_after);
+            return PyBool_FromLong(refcnt_after == refcnt);
         }
 
         static PyMethodDef methods[] = {

Modified: pypy/trunk/pypy/module/cpyext/test/test_tupleobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/test/test_tupleobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/test/test_tupleobject.py	Fri Dec  3 18:50:42 2010
@@ -7,34 +7,24 @@
 class TestTupleObject(BaseApiTest):
     def test_tupleobject(self, space, api):
         assert not api.PyTuple_Check(space.w_None)
-        #assert api.PyTuple_SetItem(space.w_None, 0, space.w_None) == -1     XXX
+        assert api.PyTuple_SetItem(space.w_None, 0, space.w_None) == -1
         atuple = space.newtuple([0, 1, 'yay'])
         assert api.PyTuple_Size(atuple) == 3
-        #raises(TypeError, api.PyTuple_Size(space.newlist([])))     XXX
+        assert api.PyTuple_GET_SIZE(atuple) == 3
+        raises(TypeError, api.PyTuple_Size(space.newlist([])))
         api.PyErr_Clear()
     
     def test_tuple_resize(self, space, api):
-        ref_tup = api.PyTuple_New(3)
+        py_tuple = api.PyTuple_New(3)
         ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw')
-        ar[0] = rffi.cast(PyObject, ref_tup)
+        ar[0] = rffi.cast(PyObject, make_ref(space, py_tuple))
         api._PyTuple_Resize(ar, 2)
-        assert ar[0] == rffi.cast(PyObject, ref_tup)
-        # ^^^ our _PyTuple_Resize does not actually need to change the ptr so far
-        assert api.PyTuple_Size(ar[0]) == 2
+        py_tuple = from_ref(space, ar[0])
+        assert len(py_tuple.wrappeditems) == 2
         
         api._PyTuple_Resize(ar, 10)
-        assert api.PyTuple_Size(ar[0]) == 10
+        py_tuple = from_ref(space, ar[0])
+        assert len(py_tuple.wrappeditems) == 10
         
         api.Py_DecRef(ar[0])
         lltype.free(ar, flavor='raw')
-
-    def test_tuple_setup(self, space, api):
-        ref_tup = api.PyTuple_New(2)
-        ref0 = make_ref(space, space.wrap(123))
-        api.PyTuple_SetItem(ref_tup, 0, ref0)
-        ref1 = make_ref(space, space.wrap(456))
-        api.PyTuple_SetItem(ref_tup, 1, ref1)
-
-        w_tup = from_ref(space, ref_tup)
-        assert space.is_true(space.eq(w_tup, space.wrap((123, 456))))
-        api.Py_DecRef(ref_tup)

Modified: pypy/trunk/pypy/module/cpyext/tupleobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/tupleobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/tupleobject.py	Fri Dec  3 18:50:42 2010
@@ -1,144 +1,55 @@
 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL,
-                                    build_type_checkers, PyObjectFields,
-                                    cpython_struct, bootstrap_function)
+                                    build_type_checkers)
 from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef,
-    borrow_from, make_ref, from_ref, make_typedescr, get_typedescr, Reference,
-    track_reference)
+    borrow_from, make_ref, from_ref)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
+from pypy.objspace.std.tupleobject import W_TupleObject
 
-##
-## Implementation of PyTupleObject
-## ===============================
-##
-## We have the same problem as PyStringObject: a PyTupleObject can be
-## initially used in a read-write way with PyTuple_New(), PyTuple_SetItem()
-## and _PyTuple_Resize().
-##
-## The 'size' and 'items' fields of a PyTupleObject are always valid.
-## Apart from that detail, see the big comment in stringobject.py for
-## more information.
-##
-
-ARRAY_OF_PYOBJ = rffi.CArrayPtr(PyObject)
-PyTupleObjectStruct = lltype.ForwardReference()
-PyTupleObject = lltype.Ptr(PyTupleObjectStruct)
-PyTupleObjectFields = PyObjectFields + \
-    (("items", ARRAY_OF_PYOBJ), ("size", Py_ssize_t))
-cpython_struct("PyTupleObject", PyTupleObjectFields, PyTupleObjectStruct)
-
- at bootstrap_function
-def init_tupleobject(space):
-    "Type description of PyTupleObject"
-    make_typedescr(space.w_tuple.instancetypedef,
-                   basestruct=PyTupleObject.TO,
-                   attach=tuple_attach,
-                   dealloc=tuple_dealloc,
-                   realize=tuple_realize)
 
 PyTuple_Check, PyTuple_CheckExact = build_type_checkers("Tuple")
 
-def new_empty_tuple(space, length):
-    """
-    Allocate a PyTupleObject and its array, but without a corresponding
-    interpreter object.  The array items may be mutated, until
-    tuple_realize() is called.
-    """
-    typedescr = get_typedescr(space.w_tuple.instancetypedef)
-    py_obj = typedescr.allocate(space, space.w_tuple)
-    py_tup = rffi.cast(PyTupleObject, py_obj)
-
-    py_tup.c_items = lltype.malloc(ARRAY_OF_PYOBJ.TO, length,
-                                   flavor='raw', zero=True)
-    py_tup.c_size = length
-    return py_tup
-
-def tuple_attach(space, py_obj, w_obj):
-    """
-    Fills a newly allocated PyTupleObject with the given tuple object.
-    """
-    items_w = space.fixedview(w_obj)
-    py_tup = rffi.cast(PyTupleObject, py_obj)
-    py_tup.c_items = lltype.nullptr(ARRAY_OF_PYOBJ.TO)
-    py_tup.c_size = len(items_w)
-
-def tuple_realize(space, py_obj):
-    """
-    Creates the tuple in the interpreter. The PyTupleObject items array
-    must not be modified after this call.
-    """
-    py_tup = rffi.cast(PyTupleObject, py_obj)
-    # If your CPython extension creates a self-referential tuple
-    # with PyTuple_SetItem(), you loose.
-    c_items = py_tup.c_items
-    items_w = [from_ref(space, c_items[i]) for i in range(py_tup.c_size)]
-    w_obj = space.newtuple(items_w)
-    track_reference(space, py_obj, w_obj)
-    return w_obj
-
- at cpython_api([PyObject], lltype.Void, external=False)
-def tuple_dealloc(space, py_obj):
-    """Frees allocated PyTupleObject resources.
-    """
-    py_tup = rffi.cast(PyTupleObject, py_obj)
-    if py_tup.c_items:
-        for i in range(py_tup.c_size):
-            Py_DecRef(space, py_tup.c_items[i])
-        lltype.free(py_tup.c_items, flavor="raw")
-    from pypy.module.cpyext.object import PyObject_dealloc
-    PyObject_dealloc(space, py_obj)
-
-#_______________________________________________________________________
-
 @cpython_api([Py_ssize_t], PyObject)
 def PyTuple_New(space, size):
-    return rffi.cast(PyObject, new_empty_tuple(space, size))
+    return space.newtuple([space.w_None] * size)
 
 @cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real, error=-1)
-def PyTuple_SetItem(space, ref, pos, ref_item):
-    # XXX steals a reference at the level of PyObjects.  Don't try to
-    # XXX call this function with an interpreter object as ref_item!
-
-    # XXX do PyTuple_Check, without forcing ref as an interpreter object
-    # XXX -- then if it fails it should also steal a reference, test it!!!
-    ref_tup = rffi.cast(PyTupleObject, ref)
-    if not ref_tup.c_items:
-        msg = "PyTuple_SetItem() called on an already-escaped tuple object"
-        raise OperationError(space.w_SystemError, space.wrap(msg))
-    ref_old = ref_tup.c_items[pos]
-    ref_tup.c_items[pos] = ref_item      # SetItem steals a reference!
-    Py_DecRef(space, ref_old)
+def PyTuple_SetItem(space, w_t, pos, w_obj):
+    if not PyTuple_Check(space, w_t):
+        # XXX this should also steal a reference, test it!!!
+        PyErr_BadInternalCall(space)
+    assert isinstance(w_t, W_TupleObject)
+    w_t.wrappeditems[pos] = w_obj
+    Py_DecRef(space, w_obj) # SetItem steals a reference!
     return 0
 
 @cpython_api([PyObject, Py_ssize_t], PyObject)
-def PyTuple_GetItem(space, ref, pos):
-    # XXX do PyTuple_Check, without forcing ref as an interpreter object
-    ref_tup = rffi.cast(PyTupleObject, ref)
-    if ref_tup.c_items:
-        return Reference(ref_tup.c_items[pos])     # borrowed reference
-    else:
-        w_t = from_ref(space, ref)
-        w_obj = space.getitem(w_t, space.wrap(pos))
-        return borrow_from(w_t, w_obj)
-
- at cpython_api([PyObject], Py_ssize_t, error=-1)
-def _PyTuple_Size_Fast(space, ref):
-    # custom version: it's not a macro, so it can be called from other .py
-    # files; but it doesn't include PyTuple_Check()
-    ref_tup = rffi.cast(PyTupleObject, ref)
-    return ref_tup.c_size
+def PyTuple_GetItem(space, w_t, pos):
+    if not PyTuple_Check(space, w_t):
+        PyErr_BadInternalCall(space)
+    assert isinstance(w_t, W_TupleObject)
+    w_obj = w_t.wrappeditems[pos]
+    return borrow_from(w_t, w_obj)
+
+ at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+def PyTuple_GET_SIZE(space, w_t):
+    """Return the size of the tuple p, which must be non-NULL and point to a tuple;
+    no error checking is performed. """
+    assert isinstance(w_t, W_TupleObject)
+    return len(w_t.wrappeditems)
 
 @cpython_api([PyObject], Py_ssize_t, error=-1)
 def PyTuple_Size(space, ref):
     """Take a pointer to a tuple object, and return the size of that tuple."""
-    # XXX do PyTuple_Check, without forcing ref as an interpreter object
-    ref_tup = rffi.cast(PyTupleObject, ref)
-    return ref_tup.c_size
+    if not PyTuple_Check(space, ref):
+        raise OperationError(space.w_TypeError,
+                             space.wrap("expected tuple object"))
+    return PyTuple_GET_SIZE(space, ref)
 
 
 @cpython_api([PyObjectP, Py_ssize_t], rffi.INT_real, error=-1)
-def _PyTuple_Resize(space, refp, newsize):
+def _PyTuple_Resize(space, ref, newsize):
     """Can be used to resize a tuple.  newsize will be the new length of the tuple.
     Because tuples are supposed to be immutable, this should only be used if there
     is only one reference to the object.  Do not use this if the tuple may already
@@ -149,22 +60,18 @@
     this function. If the object referenced by *p is replaced, the original
     *p is destroyed.  On failure, returns -1 and sets *p to NULL, and
     raises MemoryError or SystemError."""
-    # XXX do PyTuple_Check, without forcing ref as an interpreter object
-    # XXX -- then if it fails it should reset refp[0] to null
-    ref_tup = rffi.cast(PyTupleObject, refp[0])
-    c_newitems = lltype.malloc(ARRAY_OF_PYOBJ.TO, newsize,
-                               flavor='raw', zero=True)
-    c_olditems = ref_tup.c_items
-    if not c_olditems:
-        msg = "_PyTuple_Resize() called on an already-escaped tuple object"
-        raise OperationError(space.w_SystemError, space.wrap(msg))
-    oldsize = ref_tup.c_size
-    for i in range(min(oldsize, newsize)):
-        c_newitems[i] = c_olditems[i]
-    # decref items deleted by shrinkage
-    for i in range(newsize, oldsize):
-        Py_DecRef(space, c_olditems[i])
-    ref_tup.c_items = c_newitems
-    ref_tup.c_size = newsize
-    lltype.free(c_olditems, flavor='raw')
+    py_tuple = from_ref(space, ref[0])
+    if not PyTuple_Check(space, py_tuple):
+        PyErr_BadInternalCall(space)
+    assert isinstance(py_tuple, W_TupleObject)
+    py_newtuple = PyTuple_New(space, newsize)
+    
+    to_cp = newsize
+    oldsize = len(py_tuple.wrappeditems)
+    if oldsize < newsize:
+        to_cp = oldsize
+    for i in range(to_cp):
+        py_newtuple.wrappeditems[i] = py_tuple.wrappeditems[i]
+    Py_DecRef(space, ref[0])
+    ref[0] = make_ref(space, py_newtuple)
     return 0



More information about the Pypy-commit mailing list