Author: Antonio Cuni <[email protected]>
Branch: cpyext-avoid-roundtrip
Changeset: r92757:7860795a7204
Date: 2017-10-14 00:06 +0200
http://bitbucket.org/pypy/pypy/changeset/7860795a7204/

Log:    we cannot cache the empty tuple as CPython does, else we end up
        having the same py_obj for different w_objs

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
@@ -1,5 +1,13 @@
 
-/* Tuple object implementation, stolen&adapted from CPython */
+/* Tuple object implementation, stolen&adapted from CPython.  
+
+   One important difference is that CPython caches the empty tuple separately
+   and always return the very same object, while we always return a fresh one.
+   The reasons is that space.newtuple([]) always return different objects, and
+   we want to ensure that the following is always true:
+
+       w_a != w_b ==> as_pyobj(w_b) != as_pyobj(w_b)
+ */
 
 #include "Python.h"
 
@@ -12,9 +20,6 @@
 #endif
 
 #if PyTuple_MAXSAVESIZE > 0
-/* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, entry 0 is the empty
-   tuple () of which at most one instance will be allocated.
-*/
 static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
 static int numfree[PyTuple_MAXSAVESIZE];
 #endif
@@ -29,11 +34,6 @@
         return NULL;
     }
 #if PyTuple_MAXSAVESIZE > 0
-    if (size == 0 && free_list[0]) {
-        op = free_list[0];
-        Py_INCREF(op);
-        return (PyObject *) op;
-    }
     if (size < PyTuple_MAXSAVESIZE && (op = free_list[size]) != NULL) {
         free_list[size] = (PyTupleObject *) op->ob_item[0];
         numfree[size]--;
@@ -56,13 +56,6 @@
     }
     for (i=0; i < size; i++)
         op->ob_item[i] = NULL;
-#if PyTuple_MAXSAVESIZE > 0
-    if (size == 0) {
-        free_list[0] = op;
-        ++numfree[0];
-        Py_INCREF(op);          /* extra INCREF so that this is never freed */
-    }
-#endif
     _PyObject_GC_TRACK(op);
     return (PyObject *) op;
 }
@@ -76,7 +69,7 @@
     register Py_ssize_t len =  Py_SIZE(op);
     PyObject_GC_UnTrack(op);
     Py_TRASHCAN_SAFE_BEGIN(op)
-    if (len > 0) {
+    if (len >= 0) {
         i = len;
         while (--i >= 0)
             Py_XDECREF(op->ob_item[i]);
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
@@ -1,6 +1,6 @@
 import py
 
-from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, 
from_ref, decref
+from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, 
from_ref, decref, as_pyobj
 from pypy.module.cpyext.test.test_api import BaseApiTest, raises_w
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 from rpython.rtyper.lltypesystem import rffi, lltype
@@ -27,6 +27,31 @@
         py.test.raises(FatalError, from_ref, space, py_tuple)
         decref(space, py_tuple)
 
+    def test_freelist(self, space, api):
+        state = space.fromcache(State)
+        # check that we don't cache the empty tuple
+        py_a = state.C.PyTuple_New(0)
+        py_b = state.C.PyTuple_New(0)
+        assert py_a != py_b
+        assert py_a.c_ob_refcnt == 1
+        assert py_b.c_ob_refcnt == 1
+        decref(space, py_a)
+        decref(space, py_b)
+        #
+        # check that the freelist is working
+        py_c = state.C.PyTuple_New(0)
+        assert py_c == py_b
+        decref(space, py_c)
+
+    def test_empty_tuple_as_pyobj(self, space, api):
+        state = space.fromcache(State)
+        w_a = space.newtuple([])
+        w_b = space.newtuple([])
+        assert w_a is not w_b
+        py_a = as_pyobj(space, w_a)
+        py_b = as_pyobj(space, w_b)
+        assert py_a != py_b
+
     def test_tuple_resize(self, space, api):
         state = space.fromcache(State)
         w_42 = space.wrap(42)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to