Author: Matti Picus <matti.pi...@gmail.com>
Branch: PyTuple_Type-subclass
Changeset: r85339:1f707f869b48
Date: 2016-06-22 22:43 +0300
http://bitbucket.org/pypy/pypy/changeset/1f707f869b48/

Log:    change PyTupleObject.ob_item from PyObject** to PyObject*[], implies
        tp_itemsize != 0

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
@@ -8,9 +8,12 @@
 #endif
 
 typedef struct {
-    PyObject_HEAD
-    Py_ssize_t ob_size;
-    PyObject **ob_item;    /* XXX optimize to ob_item[] */
+    PyObject_VAR_HEAD
+    PyObject *ob_item[1];
+    /* ob_item contains space for 'ob_size' elements.
+     * Items must normally not be NULL, except during construction when
+     * the tuple is not yet visible outside the function that builds it.
+     */
 } PyTupleObject;
 
 /* defined in varargswrapper.c */
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
@@ -51,7 +51,7 @@
         api._PyTuple_Resize(ar, 10)
         assert api.PyTuple_Size(ar[0]) == 10
         for i in range(3, 10):
-            rffi.cast(PyTupleObject, py_tuple).c_ob_item[i] = make_ref(
+            rffi.cast(PyTupleObject, ar[0]).c_ob_item[i] = make_ref(
                 space, space.wrap(42 + i))
         w_tuple = from_ref(space, ar[0])
         assert space.int_w(space.len(w_tuple)) == 10
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
@@ -2,10 +2,10 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.debug import fatalerror_notb
 from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL,
-                                    build_type_checkers, PyObjectFields,
+                                    build_type_checkers, PyVarObjectFields,
                                     cpython_struct, bootstrap_function)
 from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef,
-    make_ref, from_ref, decref,
+    make_ref, from_ref, decref, pyobj_has_w_obj,
     track_reference, make_typedescr, get_typedescr)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.objspace.std.tupleobject import W_TupleObject
@@ -29,8 +29,8 @@
 PyTupleObjectStruct = lltype.ForwardReference()
 PyTupleObject = lltype.Ptr(PyTupleObjectStruct)
 ObjectItems = rffi.CArray(PyObject)
-PyTupleObjectFields = PyObjectFields + \
-    (("ob_size", Py_ssize_t), ("ob_item", lltype.Ptr(ObjectItems)))
+PyTupleObjectFields = PyVarObjectFields + \
+    (("ob_item", ObjectItems),)
 cpython_struct("PyTupleObject", PyTupleObjectFields, PyTupleObjectStruct)
 
 @bootstrap_function
@@ -56,14 +56,12 @@
     tuple_realize() is called.  Refcount of the result is 1.
     """
     typedescr = get_typedescr(space.w_tuple.layout.typedef)
-    py_obj = typedescr.allocate(space, space.w_tuple)
+    py_obj = typedescr.allocate(space, space.w_tuple, length)
     py_tup = rffi.cast(PyTupleObject, py_obj)
-
-    py_tup.c_ob_item = lltype.malloc(ObjectItems, length,
-                                     flavor='raw', zero=True,
-                                     add_memory_pressure=True)
-    py_tup.c_ob_size = length
-    return py_tup
+    p = py_tup.c_ob_item
+    for i in range(py_tup.c_ob_size):
+        p[i] = lltype.nullptr(PyObject.TO)
+    return py_obj
 
 def tuple_attach(space, py_obj, w_obj):
     """
@@ -71,23 +69,22 @@
     buffer must not be modified.
     """
     items_w = space.fixedview(w_obj)
-    l = len(items_w)
-    p = lltype.malloc(ObjectItems, l, flavor='raw',
-                      add_memory_pressure=True)
+    py_tup = rffi.cast(PyTupleObject, py_obj)
+    length = len(items_w)
+    if py_tup.c_ob_size < length:
+        raise oefmt(space.w_ValueError,
+            "tuple_attach called on object with ob_size %d but trying to store 
%d",
+            py_tup.c_ob_size, length) 
     i = 0
     try:
-        while i < l:
-            p[i] = make_ref(space, items_w[i])
+        while i < length:
+            py_tup.c_ob_item[i] = make_ref(space, items_w[i])
             i += 1
     except:
         while i > 0:
             i -= 1
-            decref(space, p[i])
-        lltype.free(p, flavor='raw')
+            decref(space, py_tup.c_ob_item[i])
         raise
-    py_tup = rffi.cast(PyTupleObject, py_obj)
-    py_tup.c_ob_size = l
-    py_tup.c_ob_item = p
 
 def tuple_realize(space, py_obj):
     """
@@ -101,7 +98,9 @@
     p = py_tup.c_ob_item
     items_w = [None] * l
     for i in range(l):
-        w_item = from_ref(space, p[i])
+        w_item = None
+        if p[i]:
+            w_item = from_ref(space, p[i])
         if w_item is None:
             fatalerror_notb(
                 "Fatal error in cpyext, CPython compatibility layer: "
@@ -120,18 +119,17 @@
     """
     py_tup = rffi.cast(PyTupleObject, py_obj)
     p = py_tup.c_ob_item
-    if p:
-        for i in range(py_tup.c_ob_size):
+    for i in range(py_tup.c_ob_size):
+        if p[i] and p[i].c_ob_refcnt > 0:
             decref(space, p[i])
-        lltype.free(p, flavor="raw")
-    from pypy.module.cpyext.object import PyObject_dealloc
-    PyObject_dealloc(space, py_obj)
+    while py_obj.c_ob_refcnt > 0:
+        decref(space, py_obj)
 
 #_______________________________________________________________________
 
 @cpython_api([Py_ssize_t], PyObject, result_is_ll=True)
 def PyTuple_New(space, size):
-    return rffi.cast(PyObject, new_empty_tuple(space, size))
+    return new_empty_tuple(space, size)
 
 @cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real, error=-1)
 def PyTuple_SetItem(space, ref, index, py_obj):
@@ -187,25 +185,23 @@
     ref = p_ref[0]
     if not tuple_check_ref(space, ref):
         PyErr_BadInternalCall(space)
-    ref = rffi.cast(PyTupleObject, ref)
-    oldsize = ref.c_ob_size
-    oldp = ref.c_ob_item
-    newp = lltype.malloc(ObjectItems, newsize, zero=True, flavor='raw',
-                         add_memory_pressure=True)
+    oldref = rffi.cast(PyTupleObject, ref)
+    oldsize = oldref.c_ob_size
+    p_ref[0] = new_empty_tuple(space, newsize)
+    newref = rffi.cast(PyTupleObject, p_ref[0])
     try:
         if oldsize < newsize:
             to_cp = oldsize
         else:
             to_cp = newsize
         for i in range(to_cp):
-            newp[i] = oldp[i]
+            newref.c_ob_item[i] = oldref.c_ob_item[i]
     except:
-        lltype.free(newp, flavor='raw')
+        decref(space, p_ref[0])
+        p_ref[0] = lltype.nullptr(PyObject.TO)
         raise
-    ref.c_ob_item = newp
-    ref.c_ob_size = newsize
-    lltype.free(oldp, flavor='raw')
-    # in this version, p_ref[0] never needs to be updated
+    finally:
+        decref(space, ref)
     return 0
 
 @cpython_api([PyObject, Py_ssize_t, Py_ssize_t], PyObject)
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
@@ -659,6 +659,8 @@
             subtype_dealloc.api_func.get_wrapper(space))
     if space.is_w(w_type, space.w_str):
         pto.c_tp_itemsize = 1
+    elif space.is_w(w_type, space.w_tuple):
+        pto.c_tp_itemsize = rffi.sizeof(PyObject)
     # buffer protocol
     setup_buffer_procs(space, w_type, pto)
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to