diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -706,7 +706,6 @@ PyAPI_DATA(Py_ssize_t) _Py_RefTotal; PyAPI_FUNC(void) _Py_NegativeRefcount(const char *fname, int lineno, PyObject *op); PyAPI_FUNC(PyObject *) _PyDict_Dummy(void); -PyAPI_FUNC(PyObject *) _PySet_Dummy(void); PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); #define _Py_INC_REFTOTAL _Py_RefTotal++ #define _Py_DEC_REFTOTAL _Py_RefTotal-- diff --git a/Include/setobject.h b/Include/setobject.h --- a/Include/setobject.h +++ b/Include/setobject.h @@ -61,6 +61,10 @@ struct _setobject { PyAPI_DATA(PyTypeObject) PySet_Type; PyAPI_DATA(PyTypeObject) PyFrozenSet_Type; PyAPI_DATA(PyTypeObject) PySetIter_Type; +#ifndef Py_LIMITED_API +PyAPI_DATA(PyObject *) _PySet_Dummy; +#endif + /* Invariants for frozensets: * data is immutable. diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -22,7 +22,7 @@ Py_ssize_t o = _PyDict_Dummy(); if (o != NULL) total -= o->ob_refcnt; - o = _PySet_Dummy(); + o = _PySet_Dummy; if (o != NULL) total -= o->ob_refcnt; return total; diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -29,15 +29,7 @@ set_key_error(PyObject *arg) #define PERTURB_SHIFT 5 /* Object used as dummy key to fill deleted entries */ -static PyObject *dummy = NULL; /* Initialized by first call to make_new_set() */ - -#ifdef Py_REF_DEBUG -PyObject * -_PySet_Dummy(void) -{ - return dummy; -} -#endif +PyObject *_PySet_Dummy = NULL; /* Initialized by first call to make_new_set() */ #define INIT_NONZERO_SET_SLOTS(so) do { \ (so)->table = (so)->smalltable; \ @@ -108,9 +100,9 @@ set_lookkey(PySetObject *so, PyObject *k } } - freeslot = (entry->key == dummy) ? entry : NULL; + freeslot = (entry->key == _PySet_Dummy) ? entry : NULL; - /* In the loop, key == dummy is by far (factor of 100s) + /* In the loop, key == _PySet_Dummy is by far (factor of 100s) the least likely outcome, so test for that last. */ for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { i = i * 5 + perturb + 1; @@ -140,7 +132,7 @@ set_lookkey(PySetObject *so, PyObject *k return set_lookkey(so, key, hash); } } - if (entry->key == dummy && freeslot == NULL) + if (entry->key == _PySet_Dummy && freeslot == NULL) freeslot = entry; } return entry; @@ -173,7 +165,7 @@ set_lookkey_unicode(PySetObject *so, PyO entry = &table[i]; if (entry->key == NULL || entry->key == key) return entry; - if (entry->key == dummy) + if (entry->key == _PySet_Dummy) freeslot = entry; else { if (entry->hash == hash && unicode_eq(entry->key, key)) @@ -181,7 +173,7 @@ set_lookkey_unicode(PySetObject *so, PyO freeslot = NULL; } - /* In the loop, key == dummy is by far (factor of 100s) the + /* In the loop, key == _PySet_Dummy is by far (factor of 100s) the least likely outcome, so test for that last. */ for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { i = i * 5 + perturb + 1; @@ -190,10 +182,10 @@ set_lookkey_unicode(PySetObject *so, PyO return freeslot == NULL ? entry : freeslot; if (entry->key == key || (entry->hash == hash - && entry->key != dummy + && entry->key != _PySet_Dummy && unicode_eq(entry->key, key))) return entry; - if (entry->key == dummy && freeslot == NULL) + if (entry->key == _PySet_Dummy && freeslot == NULL) freeslot = entry; } assert(0); /* NOT REACHED */ @@ -220,12 +212,12 @@ set_insert_key(PySetObject *so, PyObject entry->key = key; entry->hash = hash; so->used++; - } else if (entry->key == dummy) { + } else if (entry->key == _PySet_Dummy) { /* DUMMY */ entry->key = key; entry->hash = hash; so->used++; - Py_DECREF(dummy); + Py_DECREF(_PySet_Dummy); } else { /* ACTIVE */ Py_DECREF(key); @@ -332,7 +324,7 @@ set_table_resize(PySetObject *so, Py_ssi /* Copy the data over; this is refcount-neutral for active entries; dummy entries aren't copied over, of course */ - dummy_entry = dummy; + dummy_entry = _PySet_Dummy; for (entry = oldtable; i > 0; entry++) { if (entry->key == NULL) { /* UNUSED */ @@ -340,7 +332,7 @@ set_table_resize(PySetObject *so, Py_ssi } else if (entry->key == dummy_entry) { /* DUMMY */ --i; - assert(entry->key == dummy); + assert(entry->key == _PySet_Dummy); Py_DECREF(entry->key); } else { /* ACTIVE */ @@ -410,11 +402,11 @@ set_discard_entry(PySetObject *so, seten entry = (so->lookup)(so, oldentry->key, oldentry->hash); if (entry == NULL) return -1; - if (entry->key == NULL || entry->key == dummy) + if (entry->key == NULL || entry->key == _PySet_Dummy) return DISCARD_NOTFOUND; old_key = entry->key; - Py_INCREF(dummy); - entry->key = dummy; + Py_INCREF(_PySet_Dummy); + entry->key = _PySet_Dummy; so->used--; Py_DECREF(old_key); return DISCARD_FOUND; @@ -438,11 +430,11 @@ set_discard_key(PySetObject *so, PyObjec entry = (so->lookup)(so, key, hash); if (entry == NULL) return -1; - if (entry->key == NULL || entry->key == dummy) + if (entry->key == NULL || entry->key == _PySet_Dummy) return DISCARD_NOTFOUND; old_key = entry->key; - Py_INCREF(dummy); - entry->key = dummy; + Py_INCREF(_PySet_Dummy); + entry->key = _PySet_Dummy; so->used--; Py_DECREF(old_key); return DISCARD_FOUND; @@ -537,7 +529,7 @@ set_next(PySetObject *so, Py_ssize_t *po assert(i >= 0); table = so->table; mask = so->mask; - while (i <= mask && (table[i].key == NULL || table[i].key == dummy)) + while (i <= mask && (table[i].key == NULL || table[i].key == _PySet_Dummy)) i++; *pos_ptr = i+1; if (i > mask) @@ -652,7 +644,7 @@ set_merge(PySetObject *so, PyObject *oth key = entry->key; hash = entry->hash; if (key != NULL && - key != dummy) { + key != _PySet_Dummy) { Py_INCREF(key); if (set_insert_key(so, key, hash) == -1) { Py_DECREF(key); @@ -679,7 +671,7 @@ set_contains_key(PySetObject *so, PyObje if (entry == NULL) return -1; key = entry->key; - return key != NULL && key != dummy; + return key != NULL && key != _PySet_Dummy; } static int @@ -692,7 +684,7 @@ set_contains_entry(PySetObject *so, sete if (lu_entry == NULL) return -1; key = lu_entry->key; - return key != NULL && key != dummy; + return key != NULL && key != _PySet_Dummy; } static PyObject * @@ -708,14 +700,14 @@ set_pop(PySetObject *so) return NULL; } - /* Set entry to "the first" unused or dummy set entry. We abuse + /* Set entry to "the first" unused or _PySet_Dummy set entry. We abuse * the hash field of slot 0 to hold a search finger: * If slot 0 has a value, use slot 0. * Else slot 0 is being used to hold a search finger, * and we use its hash value as the first index to look. */ entry = &so->table[0]; - if (entry->key == NULL || entry->key == dummy) { + if (entry->key == NULL || entry->key == _PySet_Dummy) { i = entry->hash; /* The hash field may be a real hash value, or it may be a * legit search finger, or it may be a once-legit search @@ -724,15 +716,15 @@ set_pop(PySetObject *so) */ if (i > so->mask || i < 1) i = 1; /* skip slot 0 */ - while ((entry = &so->table[i])->key == NULL || entry->key==dummy) { + while ((entry = &so->table[i])->key == NULL || entry->key==_PySet_Dummy) { i++; if (i > so->mask) i = 1; } } key = entry->key; - Py_INCREF(dummy); - entry->key = dummy; + Py_INCREF(_PySet_Dummy); + entry->key = _PySet_Dummy; so->used--; so->table[0].hash = i + 1; /* next place to start */ return key; @@ -885,7 +877,7 @@ static PyObject *setiter_iternext(setite assert(i>=0); entry = so->table; mask = so->mask; - while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) + while (i <= mask && (entry[i].key == NULL || entry[i].key == _PySet_Dummy)) i++; si->si_pos = i+1; if (i > mask) @@ -1023,9 +1015,9 @@ make_new_set(PyTypeObject *type, PyObjec { PySetObject *so = NULL; - if (dummy == NULL) { /* Auto-initialize dummy */ - dummy = _PyObject_New(&PyBaseObject_Type); - if (dummy == NULL) + if (_PySet_Dummy == NULL) { /* Auto-initialize _PySet_Dummy */ + _PySet_Dummy = _PyObject_New(&PyBaseObject_Type); + if (_PySet_Dummy == NULL) return NULL; } @@ -1125,7 +1117,7 @@ void PySet_Fini(void) { PySet_ClearFreeList(); - Py_CLEAR(dummy); + Py_CLEAR(_PySet_Dummy); Py_CLEAR(emptyfrozenset); } diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -963,20 +963,19 @@ class PySetObjectPtr(PyObjectPtr): out.write(tp_name) out.write('(') + dummy_ptr = gdb.lookup_global_symbol('_PySet_Dummy').value() out.write('{') first = True table = self.field('table') for i in safe_range(self.field('mask')+1): setentry = table[i] key = setentry['key'] - if key != 0: + if key != 0 and key != dummy_ptr: pyop_key = PyObjectPtr.from_pyobject_ptr(key) - key_proxy = pyop_key.proxyval(visited) # FIXME! - if key_proxy != '': - if not first: - out.write(', ') - first = False - pyop_key.write_repr(out, visited) + if not first: + out.write(', ') + first = False + pyop_key.write_repr(out, visited) out.write('}') if tp_name != 'set':