[Python-checkins] bpo-40521: Convert deque freelist from global vars to instance vars (GH-25906)

rhettinger webhook-mailer at python.org
Tue May 4 20:08:39 EDT 2021


https://github.com/python/cpython/commit/6fdc4d37f3fdbc1bd51f841be6e5e4708a3b8798
commit: 6fdc4d37f3fdbc1bd51f841be6e5e4708a3b8798
branch: main
author: Raymond Hettinger <rhettinger at users.noreply.github.com>
committer: rhettinger <rhettinger at users.noreply.github.com>
date: 2021-05-04T17:08:31-07:00
summary:

bpo-40521: Convert deque freelist from global vars to instance vars (GH-25906)

files:
M Lib/test/test_deque.py
M Modules/_collectionsmodule.c

diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py
index 93cc6ca4f44ec..f1a79373decda 100644
--- a/Lib/test/test_deque.py
+++ b/Lib/test/test_deque.py
@@ -740,8 +740,9 @@ class C(object):
 
     @support.cpython_only
     def test_sizeof(self):
+        MAXFREEBLOCKS = 16
         BLOCKLEN = 64
-        basesize = support.calcvobjsize('2P4nP')
+        basesize = support.calcvobjsize('2P5n%dPP' % MAXFREEBLOCKS)
         blocksize = struct.calcsize('P%dPP' % BLOCKLEN)
         self.assertEqual(object.__sizeof__(deque()), basesize)
         check = self.check_sizeof
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index 9c8701af904ab..79c6b5752afa2 100644
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -30,6 +30,7 @@ static PyTypeObject tuplegetter_type;
 
 #define BLOCKLEN 64
 #define CENTER ((BLOCKLEN - 1) / 2)
+#define MAXFREEBLOCKS 16
 
 /* Data for deque objects is stored in a doubly-linked list of fixed
  * length blocks.  This assures that appends or pops never move any
@@ -92,6 +93,8 @@ typedef struct {
     Py_ssize_t rightindex;      /* 0 <= rightindex < BLOCKLEN */
     size_t state;               /* incremented whenever the indices move */
     Py_ssize_t maxlen;          /* maxlen is -1 for unbounded deques */
+    Py_ssize_t numfreeblocks;
+    block *freeblocks[MAXFREEBLOCKS];
     PyObject *weakreflist;
 } dequeobject;
 
@@ -123,16 +126,12 @@ static PyTypeObject deque_type;
    added at about the same rate as old blocks are being freed.
  */
 
-#define MAXFREEBLOCKS 16
-static Py_ssize_t numfreeblocks = 0;
-static block *freeblocks[MAXFREEBLOCKS];
-
-static block *
-newblock(void) {
+static inline block *
+newblock(dequeobject *deque) {
     block *b;
-    if (numfreeblocks) {
-        numfreeblocks--;
-        return freeblocks[numfreeblocks];
+    if (deque->numfreeblocks) {
+        deque->numfreeblocks--;
+        return deque->freeblocks[deque->numfreeblocks];
     }
     b = PyMem_Malloc(sizeof(block));
     if (b != NULL) {
@@ -142,12 +141,12 @@ newblock(void) {
     return NULL;
 }
 
-static void
-freeblock(block *b)
+static inline void
+freeblock(dequeobject *deque, block *b)
 {
-    if (numfreeblocks < MAXFREEBLOCKS) {
-        freeblocks[numfreeblocks] = b;
-        numfreeblocks++;
+    if (deque->numfreeblocks < MAXFREEBLOCKS) {
+        deque->freeblocks[deque->numfreeblocks] = b;
+        deque->numfreeblocks++;
     } else {
         PyMem_Free(b);
     }
@@ -164,7 +163,7 @@ deque_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     if (deque == NULL)
         return NULL;
 
-    b = newblock();
+    b = newblock(deque);
     if (b == NULL) {
         Py_DECREF(deque);
         return NULL;
@@ -180,6 +179,7 @@ deque_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     deque->rightindex = CENTER;
     deque->state = 0;
     deque->maxlen = -1;
+    deque->numfreeblocks = 0;
     deque->weakreflist = NULL;
 
     return (PyObject *)deque;
@@ -204,7 +204,7 @@ deque_pop(dequeobject *deque, PyObject *unused)
         if (Py_SIZE(deque)) {
             prevblock = deque->rightblock->leftlink;
             assert(deque->leftblock != deque->rightblock);
-            freeblock(deque->rightblock);
+            freeblock(deque, deque->rightblock);
             CHECK_NOT_END(prevblock);
             MARK_END(prevblock->rightlink);
             deque->rightblock = prevblock;
@@ -242,7 +242,7 @@ deque_popleft(dequeobject *deque, PyObject *unused)
         if (Py_SIZE(deque)) {
             assert(deque->leftblock != deque->rightblock);
             prevblock = deque->leftblock->rightlink;
-            freeblock(deque->leftblock);
+            freeblock(deque, deque->leftblock);
             CHECK_NOT_END(prevblock);
             MARK_END(prevblock->leftlink);
             deque->leftblock = prevblock;
@@ -278,7 +278,7 @@ static inline int
 deque_append_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen)
 {
     if (deque->rightindex == BLOCKLEN - 1) {
-        block *b = newblock();
+        block *b = newblock(deque);
         if (b == NULL)
             return -1;
         b->leftlink = deque->rightblock;
@@ -315,7 +315,7 @@ static inline int
 deque_appendleft_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen)
 {
     if (deque->leftindex == 0) {
-        block *b = newblock();
+        block *b = newblock(deque);
         if (b == NULL)
             return -1;
         b->rightlink = deque->leftblock;
@@ -584,7 +584,7 @@ deque_clear(dequeobject *deque)
        adversary could cause it to never terminate).
     */
 
-    b = newblock();
+    b = newblock(deque);
     if (b == NULL) {
         PyErr_Clear();
         goto alternate_method;
@@ -623,13 +623,13 @@ deque_clear(dequeobject *deque)
             itemptr = leftblock->data;
             limit = itemptr + m;
             n -= m;
-            freeblock(prevblock);
+            freeblock(deque, prevblock);
         }
         item = *(itemptr++);
         Py_DECREF(item);
     }
     CHECK_END(leftblock->rightlink);
-    freeblock(leftblock);
+    freeblock(deque, leftblock);
     return 0;
 
   alternate_method:
@@ -679,7 +679,7 @@ deque_inplace_repeat(dequeobject *deque, Py_ssize_t n)
         deque->state++;
         for (i = 0 ; i < n-1 ; ) {
             if (deque->rightindex == BLOCKLEN - 1) {
-                block *b = newblock();
+                block *b = newblock(deque);
                 if (b == NULL) {
                     Py_SET_SIZE(deque, Py_SIZE(deque) + i);
                     return NULL;
@@ -797,7 +797,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
     while (n > 0) {
         if (leftindex == 0) {
             if (b == NULL) {
-                b = newblock();
+                b = newblock(deque);
                 if (b == NULL)
                     goto done;
             }
@@ -841,7 +841,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
     while (n < 0) {
         if (rightindex == BLOCKLEN - 1) {
             if (b == NULL) {
-                b = newblock();
+                b = newblock(deque);
                 if (b == NULL)
                     goto done;
             }
@@ -885,7 +885,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
     rv = 0;
 done:
     if (b != NULL)
-        freeblock(b);
+        freeblock(deque, b);
     deque->leftblock = leftblock;
     deque->rightblock = rightblock;
     deque->leftindex = leftindex;
@@ -1306,16 +1306,21 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v)
 static void
 deque_dealloc(dequeobject *deque)
 {
+    Py_ssize_t i;
+
     PyObject_GC_UnTrack(deque);
     if (deque->weakreflist != NULL)
         PyObject_ClearWeakRefs((PyObject *) deque);
     if (deque->leftblock != NULL) {
         deque_clear(deque);
         assert(deque->leftblock != NULL);
-        freeblock(deque->leftblock);
+        freeblock(deque, deque->leftblock);
     }
     deque->leftblock = NULL;
     deque->rightblock = NULL;
+    for (i=0 ; i < deque->numfreeblocks ; i++) {
+        PyMem_Free(deque->freeblocks[i]);
+    }
     Py_TYPE(deque)->tp_free(deque);
 }
 



More information about the Python-checkins mailing list