From d4f1017479175f0d4447f2458c65a5d05349adec Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 13 Nov 2018 21:04:54 +0900 Subject: [PATCH 1/3] bpo-35230: Remove _Py_REF_DEBUG_COMMA --- Include/object.h | 2 -- Objects/dictobject.c | 64 +++++++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/Include/object.h b/Include/object.h index 10ec60051e5e8e..48ce9d2b970a5d 100644 --- a/Include/object.h +++ b/Include/object.h @@ -734,7 +734,6 @@ PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); #define _Py_INC_REFTOTAL _Py_RefTotal++ #define _Py_DEC_REFTOTAL _Py_RefTotal-- -#define _Py_REF_DEBUG_COMMA , /* Py_REF_DEBUG also controls the display of refcounts and memory block * allocations at the interactive prompt and at interpreter shutdown @@ -743,7 +742,6 @@ PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void); #else #define _Py_INC_REFTOTAL #define _Py_DEC_REFTOTAL -#define _Py_REF_DEBUG_COMMA #endif /* Py_REF_DEBUG */ #ifdef COUNT_ALLOCS diff --git a/Objects/dictobject.c b/Objects/dictobject.c index ca383a193d3f57..b826fc8fb45f9f 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -302,14 +302,27 @@ PyDict_Fini(void) #define DK_ENTRIES(dk) \ ((PyDictKeyEntry*)(&((int8_t*)((dk)->dk_indices))[DK_SIZE(dk) * DK_IXSIZE(dk)])) -#define DK_DEBUG_INCREF _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA -#define DK_DEBUG_DECREF _Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA - -#define DK_INCREF(dk) (DK_DEBUG_INCREF ++(dk)->dk_refcnt) -#define DK_DECREF(dk) if (DK_DEBUG_DECREF (--(dk)->dk_refcnt) == 0) free_keys_object(dk) #define DK_MASK(dk) (((dk)->dk_size)-1) #define IS_POWER_OF_2(x) (((x) & (x-1)) == 0) +static void free_keys_object(PyDictKeysObject *keys); + +static inline void +dk_incref(PyDictKeysObject *dk) +{ + _Py_INC_REFTOTAL; + dk->dk_refcnt++; +} + +static inline void +dk_decref(PyDictKeysObject *dk) +{ + _Py_DEC_REFTOTAL; + if (--dk->dk_refcnt == 0) { + free_keys_object(dk); + } +} + /* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */ static inline Py_ssize_t dk_get_index(PyDictKeysObject *keys, Py_ssize_t i) @@ -543,7 +556,8 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size) return NULL; } } - DK_DEBUG_INCREF dk->dk_refcnt = 1; + _Py_INC_REFTOTAL; + dk->dk_refcnt = 1; dk->dk_size = size; dk->dk_usable = usable; dk->dk_lookup = lookdict_unicode_nodummy; @@ -587,7 +601,7 @@ new_dict(PyDictKeysObject *keys, PyObject **values) else { mp = PyObject_GC_New(PyDictObject, &PyDict_Type); if (mp == NULL) { - DK_DECREF(keys); + dk_decref(keys); free_values(values); return NULL; } @@ -610,7 +624,7 @@ new_dict_with_shared_keys(PyDictKeysObject *keys) size = USABLE_FRACTION(DK_SIZE(keys)); values = new_values(size); if (values == NULL) { - DK_DECREF(keys); + dk_decref(keys); return PyErr_NoMemory(); } for (i = 0; i < size; i++) { @@ -665,7 +679,7 @@ clone_combined_dict(PyDictObject *orig) /* Since we copied the keys table we now have an extra reference in the system. Manually call _Py_INC_REFTOTAL to signal that - we have it now; calling DK_INCREF would be an error as + we have it now; calling dk_incref would be an error as keys->dk_refcnt is already set to 1 (after memcpy). */ _Py_INC_REFTOTAL; @@ -1171,7 +1185,7 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) newentries[i].me_value = oldvalues[i]; } - DK_DECREF(oldkeys); + dk_decref(oldkeys); mp->ma_values = NULL; if (oldvalues != empty_values) { free_values(oldvalues); @@ -1194,10 +1208,12 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) assert(oldkeys->dk_refcnt == 1); if (oldkeys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) { - DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; + _Py_DEC_REFTOTAL; + keys_free_list[numfreekeys++] = oldkeys; } else { - DK_DEBUG_DECREF PyObject_FREE(oldkeys); + _Py_DEC_REFTOTAL; + PyObject_FREE(oldkeys); } } @@ -1247,7 +1263,7 @@ make_keys_shared(PyObject *op) mp->ma_keys->dk_lookup = lookdict_split; mp->ma_values = values; } - DK_INCREF(mp->ma_keys); + dk_incref(mp->ma_keys); return mp->ma_keys; } @@ -1630,7 +1646,7 @@ PyDict_Clear(PyObject *op) if (oldvalues == empty_values) return; /* Empty the dict... */ - DK_INCREF(Py_EMPTY_KEYS); + dk_incref(Py_EMPTY_KEYS); mp->ma_keys = Py_EMPTY_KEYS; mp->ma_values = empty_values; mp->ma_used = 0; @@ -1641,11 +1657,11 @@ PyDict_Clear(PyObject *op) for (i = 0; i < n; i++) Py_CLEAR(oldvalues[i]); free_values(oldvalues); - DK_DECREF(oldkeys); + dk_decref(oldkeys); } else { assert(oldkeys->dk_refcnt == 1); - DK_DECREF(oldkeys); + dk_decref(oldkeys); } assert(_PyDict_CheckConsistency(mp)); } @@ -1910,11 +1926,11 @@ dict_dealloc(PyDictObject *mp) } free_values(values); } - DK_DECREF(keys); + dk_decref(keys); } else if (keys != NULL) { assert(keys->dk_refcnt == 1); - DK_DECREF(keys); + dk_decref(keys); } if (numfree < PyDict_MAXFREELIST && Py_TYPE(mp) == &PyDict_Type) free_list[numfree++] = mp; @@ -2563,7 +2579,7 @@ PyDict_Copy(PyObject *o) split_copy->ma_keys = mp->ma_keys; split_copy->ma_used = mp->ma_used; split_copy->ma_version_tag = DICT_NEXT_VERSION(); - DK_INCREF(mp->ma_keys); + dk_incref(mp->ma_keys); for (i = 0, n = size; i < n; i++) { PyObject *value = mp->ma_values[i]; Py_XINCREF(value); @@ -4460,7 +4476,7 @@ PyObject_GenericGetDict(PyObject *obj, void *context) if (dict == NULL) { PyTypeObject *tp = Py_TYPE(obj); if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) { - DK_INCREF(CACHED_KEYS(tp)); + dk_incref(CACHED_KEYS(tp)); *dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp)); } else { @@ -4484,7 +4500,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, assert(dictptr != NULL); dict = *dictptr; if (dict == NULL) { - DK_INCREF(cached); + dk_incref(cached); dict = new_dict_with_shared_keys(cached); if (dict == NULL) return -1; @@ -4496,7 +4512,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, // always converts dict to combined form. if ((cached = CACHED_KEYS(tp)) != NULL) { CACHED_KEYS(tp) = NULL; - DK_DECREF(cached); + dk_decref(cached); } } else { @@ -4525,7 +4541,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, else { CACHED_KEYS(tp) = NULL; } - DK_DECREF(cached); + dk_decref(cached); if (CACHED_KEYS(tp) == NULL && PyErr_Occurred()) return -1; } @@ -4550,5 +4566,5 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, void _PyDictKeys_DecRef(PyDictKeysObject *keys) { - DK_DECREF(keys); + dk_decref(keys); } From df85261e88c69c10e2d56c7bc080d6ceafe37e6b Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Wed, 14 Nov 2018 18:11:44 +0900 Subject: [PATCH 2/3] Change prefix from dk_ to dictkeys_ --- Objects/dictobject.c | 72 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index b826fc8fb45f9f..25134e0706358b 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -308,14 +308,14 @@ PyDict_Fini(void) static void free_keys_object(PyDictKeysObject *keys); static inline void -dk_incref(PyDictKeysObject *dk) +dictkeys_incref(PyDictKeysObject *dk) { _Py_INC_REFTOTAL; dk->dk_refcnt++; } static inline void -dk_decref(PyDictKeysObject *dk) +dictkeys_decref(PyDictKeysObject *dk) { _Py_DEC_REFTOTAL; if (--dk->dk_refcnt == 0) { @@ -325,7 +325,7 @@ dk_decref(PyDictKeysObject *dk) /* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */ static inline Py_ssize_t -dk_get_index(PyDictKeysObject *keys, Py_ssize_t i) +dictkeys_get_index(PyDictKeysObject *keys, Py_ssize_t i) { Py_ssize_t s = DK_SIZE(keys); Py_ssize_t ix; @@ -354,7 +354,7 @@ dk_get_index(PyDictKeysObject *keys, Py_ssize_t i) /* write to indices. */ static inline void -dk_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) +dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) { Py_ssize_t s = DK_SIZE(keys); @@ -477,7 +477,7 @@ _PyDict_CheckConsistency(PyDictObject *mp) #ifdef DEBUG_PYDICT for (i=0; i < keys->dk_size; i++) { - Py_ssize_t ix = dk_get_index(keys, i); + Py_ssize_t ix = dictkeys_get_index(keys, i); ASSERT(DKIX_DUMMY <= ix && ix <= usable); } @@ -601,7 +601,7 @@ new_dict(PyDictKeysObject *keys, PyObject **values) else { mp = PyObject_GC_New(PyDictObject, &PyDict_Type); if (mp == NULL) { - dk_decref(keys); + dictkeys_decref(keys); free_values(values); return NULL; } @@ -624,7 +624,7 @@ new_dict_with_shared_keys(PyDictKeysObject *keys) size = USABLE_FRACTION(DK_SIZE(keys)); values = new_values(size); if (values == NULL) { - dk_decref(keys); + dictkeys_decref(keys); return PyErr_NoMemory(); } for (i = 0; i < size; i++) { @@ -679,7 +679,7 @@ clone_combined_dict(PyDictObject *orig) /* Since we copied the keys table we now have an extra reference in the system. Manually call _Py_INC_REFTOTAL to signal that - we have it now; calling dk_incref would be an error as + we have it now; calling dictkeys_incref would be an error as keys->dk_refcnt is already set to 1 (after memcpy). */ _Py_INC_REFTOTAL; @@ -704,7 +704,7 @@ lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index) size_t i = (size_t)hash & mask; for (;;) { - Py_ssize_t ix = dk_get_index(k, i); + Py_ssize_t ix = dictkeys_get_index(k, i); if (ix == index) { return i; } @@ -757,7 +757,7 @@ lookdict(PyDictObject *mp, PyObject *key, i = (size_t)hash & mask; for (;;) { - Py_ssize_t ix = dk_get_index(dk, i); + Py_ssize_t ix = dictkeys_get_index(dk, i); if (ix == DKIX_EMPTY) { *value_addr = NULL; return ix; @@ -817,7 +817,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, size_t i = (size_t)hash & mask; for (;;) { - Py_ssize_t ix = dk_get_index(mp->ma_keys, i); + Py_ssize_t ix = dictkeys_get_index(mp->ma_keys, i); if (ix == DKIX_EMPTY) { *value_addr = NULL; return DKIX_EMPTY; @@ -860,7 +860,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, size_t i = (size_t)hash & mask; for (;;) { - Py_ssize_t ix = dk_get_index(mp->ma_keys, i); + Py_ssize_t ix = dictkeys_get_index(mp->ma_keys, i); assert (ix != DKIX_DUMMY); if (ix == DKIX_EMPTY) { *value_addr = NULL; @@ -905,7 +905,7 @@ lookdict_split(PyDictObject *mp, PyObject *key, size_t i = (size_t)hash & mask; for (;;) { - Py_ssize_t ix = dk_get_index(mp->ma_keys, i); + Py_ssize_t ix = dictkeys_get_index(mp->ma_keys, i); assert (ix != DKIX_DUMMY); if (ix == DKIX_EMPTY) { *value_addr = NULL; @@ -997,11 +997,11 @@ find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash) const size_t mask = DK_MASK(keys); size_t i = hash & mask; - Py_ssize_t ix = dk_get_index(keys, i); + Py_ssize_t ix = dictkeys_get_index(keys, i); for (size_t perturb = hash; ix >= 0;) { perturb >>= PERTURB_SHIFT; i = (i*5 + perturb + 1) & mask; - ix = dk_get_index(keys, i); + ix = dictkeys_get_index(keys, i); } return i; } @@ -1058,7 +1058,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) } Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash); ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries]; - dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); + dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); ep->me_key = key; ep->me_hash = hash; if (mp->ma_values) { @@ -1112,11 +1112,11 @@ build_indices(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n) for (Py_ssize_t ix = 0; ix != n; ix++, ep++) { Py_hash_t hash = ep->me_hash; size_t i = hash & mask; - for (size_t perturb = hash; dk_get_index(keys, i) != DKIX_EMPTY;) { + for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) { perturb >>= PERTURB_SHIFT; i = mask & (i*5 + perturb + 1); } - dk_set_index(keys, i, ix); + dictkeys_set_index(keys, i, ix); } } @@ -1185,7 +1185,7 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) newentries[i].me_value = oldvalues[i]; } - dk_decref(oldkeys); + dictkeys_decref(oldkeys); mp->ma_values = NULL; if (oldvalues != empty_values) { free_values(oldvalues); @@ -1263,7 +1263,7 @@ make_keys_shared(PyObject *op) mp->ma_keys->dk_lookup = lookdict_split; mp->ma_values = values; } - dk_incref(mp->ma_keys); + dictkeys_incref(mp->ma_keys); return mp->ma_keys; } @@ -1515,7 +1515,7 @@ delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix, mp->ma_used--; mp->ma_version_tag = DICT_NEXT_VERSION(); ep = &DK_ENTRIES(mp->ma_keys)[ix]; - dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY); + dictkeys_set_index(mp->ma_keys, hashpos, DKIX_DUMMY); ENSURE_ALLOWS_DELETIONS(mp); old_key = ep->me_key; ep->me_key = NULL; @@ -1646,7 +1646,7 @@ PyDict_Clear(PyObject *op) if (oldvalues == empty_values) return; /* Empty the dict... */ - dk_incref(Py_EMPTY_KEYS); + dictkeys_incref(Py_EMPTY_KEYS); mp->ma_keys = Py_EMPTY_KEYS; mp->ma_values = empty_values; mp->ma_used = 0; @@ -1657,11 +1657,11 @@ PyDict_Clear(PyObject *op) for (i = 0; i < n; i++) Py_CLEAR(oldvalues[i]); free_values(oldvalues); - dk_decref(oldkeys); + dictkeys_decref(oldkeys); } else { assert(oldkeys->dk_refcnt == 1); - dk_decref(oldkeys); + dictkeys_decref(oldkeys); } assert(_PyDict_CheckConsistency(mp)); } @@ -1785,7 +1785,7 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d assert(old_value != NULL); mp->ma_used--; mp->ma_version_tag = DICT_NEXT_VERSION(); - dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY); + dictkeys_set_index(mp->ma_keys, hashpos, DKIX_DUMMY); ep = &DK_ENTRIES(mp->ma_keys)[ix]; ENSURE_ALLOWS_DELETIONS(mp); old_key = ep->me_key; @@ -1926,11 +1926,11 @@ dict_dealloc(PyDictObject *mp) } free_values(values); } - dk_decref(keys); + dictkeys_decref(keys); } else if (keys != NULL) { assert(keys->dk_refcnt == 1); - dk_decref(keys); + dictkeys_decref(keys); } if (numfree < PyDict_MAXFREELIST && Py_TYPE(mp) == &PyDict_Type) free_list[numfree++] = mp; @@ -2579,7 +2579,7 @@ PyDict_Copy(PyObject *o) split_copy->ma_keys = mp->ma_keys; split_copy->ma_used = mp->ma_used; split_copy->ma_version_tag = DICT_NEXT_VERSION(); - dk_incref(mp->ma_keys); + dictkeys_incref(mp->ma_keys); for (i = 0, n = size; i < n; i++) { PyObject *value = mp->ma_values[i]; Py_XINCREF(value); @@ -2844,7 +2844,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash); ep0 = DK_ENTRIES(mp->ma_keys); ep = &ep0[mp->ma_keys->dk_nentries]; - dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); + dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); Py_INCREF(key); Py_INCREF(value); MAINTAIN_TRACKING(mp, key, value); @@ -2965,8 +2965,8 @@ dict_popitem(PyDictObject *mp, PyObject *Py_UNUSED(ignored)) ep = &ep0[i]; j = lookdict_index(mp->ma_keys, ep->me_hash, i); assert(j >= 0); - assert(dk_get_index(mp->ma_keys, j) == i); - dk_set_index(mp->ma_keys, j, DKIX_DUMMY); + assert(dictkeys_get_index(mp->ma_keys, j) == i); + dictkeys_set_index(mp->ma_keys, j, DKIX_DUMMY); PyTuple_SET_ITEM(res, 0, ep->me_key); PyTuple_SET_ITEM(res, 1, ep->me_value); @@ -4476,7 +4476,7 @@ PyObject_GenericGetDict(PyObject *obj, void *context) if (dict == NULL) { PyTypeObject *tp = Py_TYPE(obj); if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) { - dk_incref(CACHED_KEYS(tp)); + dictkeys_incref(CACHED_KEYS(tp)); *dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp)); } else { @@ -4500,7 +4500,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, assert(dictptr != NULL); dict = *dictptr; if (dict == NULL) { - dk_incref(cached); + dictkeys_incref(cached); dict = new_dict_with_shared_keys(cached); if (dict == NULL) return -1; @@ -4512,7 +4512,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, // always converts dict to combined form. if ((cached = CACHED_KEYS(tp)) != NULL) { CACHED_KEYS(tp) = NULL; - dk_decref(cached); + dictkeys_decref(cached); } } else { @@ -4541,7 +4541,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, else { CACHED_KEYS(tp) = NULL; } - dk_decref(cached); + dictkeys_decref(cached); if (CACHED_KEYS(tp) == NULL && PyErr_Occurred()) return -1; } @@ -4566,5 +4566,5 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, void _PyDictKeys_DecRef(PyDictKeysObject *keys) { - dk_decref(keys); + dictkeys_decref(keys); } From 5b10f1b186cc3e9216845faba503e1886f0b94cb Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Wed, 14 Nov 2018 18:12:59 +0900 Subject: [PATCH 3/3] Add assertion --- Objects/dictobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 25134e0706358b..df92bfd6a97816 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -317,6 +317,7 @@ dictkeys_incref(PyDictKeysObject *dk) static inline void dictkeys_decref(PyDictKeysObject *dk) { + assert(dk->dk_refcnt > 0); _Py_DEC_REFTOTAL; if (--dk->dk_refcnt == 0) { free_keys_object(dk);