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,18 +29,12 @@ set_key_error(PyObject *arg) #define PERTURB_SHIFT 5 /* Object used as dummy key to fill deleted entries */ - static PyObject _dummy_struct; #define dummy (&_dummy_struct) -#ifdef Py_REF_DEBUG -PyObject * -_PySet_Dummy(void) -{ - return dummy; -} -#endif +/* Exported for the gdb plugin's benefit. */ +PyObject *_PySet_Dummy = dummy; #define INIT_NONZERO_SET_SLOTS(so) do { \ (so)->table = (so)->smalltable; \ diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -922,21 +922,26 @@ class PyFrameObjectPtr(PyObjectPtr): class PySetObjectPtr(PyObjectPtr): _typename = 'PySetObject' + @classmethod + def _dummy_key(self): + return gdb.lookup_global_symbol('_PySet_Dummy').value() + + def __iter__(self): + dummy_ptr = self._dummy_key() + table = self.field('table') + for i in safe_range(self.field('mask') + 1): + setentry = table[i] + key = setentry['key'] + if key != 0 and key != dummy_ptr: + yield PyObjectPtr.from_pyobject_ptr(key) + def proxyval(self, visited): # Guard against infinite loops: if self.as_address() in visited: return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name()) visited.add(self.as_address()) - members = [] - table = self.field('table') - for i in safe_range(self.field('mask')+1): - setentry = table[i] - key = setentry['key'] - if key != 0: - key_proxy = PyObjectPtr.from_pyobject_ptr(key).proxyval(visited) - if key_proxy != '': - members.append(key_proxy) + members = (key.proxyval(visited) for key in self) if self.safe_tp_name() == 'frozenset': return frozenset(members) else: @@ -965,18 +970,11 @@ class PySetObjectPtr(PyObjectPtr): 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: - 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) + for key in self: + if not first: + out.write(', ') + first = False + key.write_repr(out, visited) out.write('}') if tp_name != 'set':