bpo-31954: Reuse oldkeys if oldkeys->dk_size == newsize. by serhiy-storchaka · Pull Request #4292 · python/cpython

Expand Up @@ -417,11 +417,12 @@ dk_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) * (which cannot fail and thus can do no allocation). */ static PyDictKeysObject empty_keys_struct = { 1, /* dk_refcnt */ 1, /* dk_size */ lookdict_split, /* dk_lookup */ 0, /* dk_usable (immutable) */ 0, /* dk_nentries */ .dk_refcnt = 1, .dk_size = 1, .dk_lookup = lookdict_split, .dk_usable = 0, .dk_nentries = 0, .dk_clean = 0, .dk_indices = { .as_1 = {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}}, }; Expand Down Expand Up @@ -544,6 +545,7 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size) dk->dk_usable = usable; dk->dk_lookup = lookdict_unicode_nodummy; dk->dk_nentries = 0; dk->dk_clean = 0; memset(&dk->dk_indices.as_1[0], 0xff, es * size); memset(DK_ENTRIES(dk), 0, sizeof(PyDictKeyEntry) * usable); return dk; Expand Down Expand Up @@ -1078,27 +1080,24 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) }
oldkeys = mp->ma_keys;
/* NOTE: Current odict checks mp->ma_keys to detect resize happen. * So we can't reuse oldkeys even if oldkeys->dk_size == newsize. * TODO: Try reusing oldkeys when reimplement odict. */
/* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { mp->ma_keys = oldkeys; return -1; oldvalues = mp->ma_values; if (newsize != oldkeys->dk_size || oldvalues != NULL) { /* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { mp->ma_keys = oldkeys; return -1; } // New table must be large enough. assert(mp->ma_keys->dk_usable >= mp->ma_used); if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; } // New table must be large enough. assert(mp->ma_keys->dk_usable >= mp->ma_used); if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; mp->ma_keys->dk_clean = 0;
numentries = mp->ma_used; oldentries = DK_ENTRIES(oldkeys); newentries = DK_ENTRIES(mp->ma_keys); oldvalues = mp->ma_values; if (oldvalues != NULL) { /* Convert split table into new combined table. * We must incref keys; we can transfer values. Expand All @@ -1122,7 +1121,8 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) } else { // combined table. if (oldkeys->dk_nentries == numentries) { memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); /* Source and destination can overlap if reuse an old table. */ memmove(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); } else { PyDictKeyEntry *ep = oldentries; Expand All @@ -1133,14 +1133,24 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) } }
assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); if (oldkeys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) { DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; if (oldkeys != mp->ma_keys) { assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); if (oldkeys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) { DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; } else { DK_DEBUG_DECREF PyObject_FREE(oldkeys); } } else { DK_DEBUG_DECREF PyObject_FREE(oldkeys); oldkeys->dk_usable = USABLE_FRACTION(newsize); memset(&oldkeys->dk_indices.as_1[0], 0xff, DK_IXSIZE(oldkeys) * newsize); memset(newentries + numentries, 0, sizeof(PyDictKeyEntry) * (oldkeys->dk_usable - numentries)); } }
Expand Down