static void free_keys_object(PyInterpreterState *interp, PyDictKeysObject *keys);
+/* PyDictKeysObject has refcounts like PyObject does, so we have the
+ following two functions to mirror what Py_INCREF() and Py_DECREF() do.
+ (Keep in mind that PyDictKeysObject isn't actually a PyObject.)
+ Likewise a PyDictKeysObject can be immortal (e.g. Py_EMPTY_KEYS),
+ so we apply a naive version of what Py_INCREF() and Py_DECREF() do
+ for immortal objects. */
+
static inline void
dictkeys_incref(PyDictKeysObject *dk)
{
+ if (dk->dk_refcnt == _Py_IMMORTAL_REFCNT) {
+ return;
+ }
#ifdef Py_REF_DEBUG
_Py_IncRefTotal(_PyInterpreterState_GET());
#endif
static inline void
dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk)
{
+ if (dk->dk_refcnt == _Py_IMMORTAL_REFCNT) {
+ return;
+ }
assert(dk->dk_refcnt > 0);
#ifdef Py_REF_DEBUG
_Py_DecRefTotal(_PyInterpreterState_GET());
* (which cannot fail and thus can do no allocation).
*/
static PyDictKeysObject empty_keys_struct = {
- 1, /* dk_refcnt */
+ _Py_IMMORTAL_REFCNT, /* dk_refcnt */
0, /* dk_log2_size */
0, /* dk_log2_index_bytes */
DICT_KEYS_UNICODE, /* dk_kind */
assert(PyDict_Check(orig));
assert(Py_TYPE(orig)->tp_iter == (getiterfunc)dict_iter);
assert(orig->ma_values == NULL);
+ assert(orig->ma_keys != Py_EMPTY_KEYS);
assert(orig->ma_keys->dk_refcnt == 1);
size_t keys_size = _PyDict_KeysSize(orig->ma_keys);
PyDict_New(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
- dictkeys_incref(Py_EMPTY_KEYS);
+ /* We don't incref Py_EMPTY_KEYS here because it is immortal. */
return new_dict(interp, Py_EMPTY_KEYS, NULL, 0, 0);
}
Py_DECREF(value);
return -1;
}
- dictkeys_decref(interp, Py_EMPTY_KEYS);
+ /* We don't decref Py_EMPTY_KEYS here because it is immortal. */
mp->ma_keys = newkeys;
mp->ma_values = NULL;
// We can not use free_keys_object here because key's reference
// are moved already.
+ if (oldkeys != Py_EMPTY_KEYS) {
#ifdef Py_REF_DEBUG
- _Py_DecRefTotal(_PyInterpreterState_GET());
+ _Py_DecRefTotal(_PyInterpreterState_GET());
#endif
- if (oldkeys == Py_EMPTY_KEYS) {
- oldkeys->dk_refcnt--;
- assert(oldkeys->dk_refcnt > 0);
- }
- else {
assert(oldkeys->dk_kind != DICT_KEYS_SPLIT);
assert(oldkeys->dk_refcnt == 1);
#if PyDict_MAXFREELIST > 0
dictkeys_decref(interp, oldkeys);
}
else {
- assert(oldkeys->dk_refcnt == 1);
- dictkeys_decref(interp, oldkeys);
+ assert(oldkeys->dk_refcnt == 1);
+ dictkeys_decref(interp, oldkeys);
}
ASSERT_CONSISTENT(mp);
}