Index: Python/pythonrun.c =================================================================== --- Python/pythonrun.c (revision 46986) +++ Python/pythonrun.c (working copy) @@ -451,8 +451,8 @@ PyCFunction_Fini(); PyTuple_Fini(); PyList_Fini(); + PyString_Fini(); PySet_Fini(); - PyString_Fini(); PyInt_Fini(); PyFloat_Fini(); Index: Include/setobject.h =================================================================== --- Include/setobject.h (revision 46986) +++ Include/setobject.h (working copy) @@ -85,6 +85,7 @@ PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry); PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); +PyAPI_FUNC(PyObject *) _PySet_LookString(PyObject *set, PyObject *key); #ifdef __cplusplus } Index: Objects/setobject.c =================================================================== --- Objects/setobject.c (revision 46986) +++ Objects/setobject.c (working copy) @@ -2049,6 +2049,22 @@ return set_update_internal((PySetObject *)set, iterable); } +PyObject * +_PySet_LookString(PyObject *set, PyObject *key) +{ + register long hash; + register setentry *entry; + register PyObject *res; + if ((hash = ((PyStringObject *) key)->ob_shash) == -1) + hash = PyObject_Hash(key); + entry = set_lookkey_string((PySetObject *)set, key, hash); + res = entry->key; + if (res == NULL || res == dummy) + return NULL; + Py_INCREF(res); + return res; +} + #ifdef Py_DEBUG /* Test code to be called with any three element set. Index: Objects/stringobject.c =================================================================== --- Objects/stringobject.c (revision 46986) +++ Objects/stringobject.c (working copy) @@ -521,8 +521,8 @@ case SSTATE_INTERNED_MORTAL: /* revive dead object temporarily for DelItem */ - op->ob_refcnt = 3; - if (PyDict_DelItem(interned, op) != 0) + op->ob_refcnt = 2; + if (PySet_Discard(interned, op) < 0) Py_FatalError( "deletion of interned string failed"); break; @@ -4911,13 +4911,13 @@ if (PyString_CHECK_INTERNED(s)) return; if (interned == NULL) { - interned = PyDict_New(); + interned = PySet_New(NULL); if (interned == NULL) { PyErr_Clear(); /* Don't leave an exception */ return; } } - t = PyDict_GetItem(interned, (PyObject *)s); + t = _PySet_LookString(interned, (PyObject *)s); if (t) { Py_INCREF(t); Py_DECREF(*p); @@ -4925,13 +4925,13 @@ return; } - if (PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s) < 0) { + if (PySet_Add(interned, (PyObject *)s) < 0) { PyErr_Clear(); return; } /* The two references in interned are not counted by refcnt. The string deallocator will take care of this */ - s->ob_refcnt -= 2; + s->ob_refcnt -= 1; PyString_CHECK_INTERNED(s) = SSTATE_INTERNED_MORTAL; } @@ -4970,17 +4970,11 @@ void _Py_ReleaseInternedStrings(void) { - PyObject *keys; + PyObject *key; PyStringObject *s; - Py_ssize_t i, n; - if (interned == NULL || !PyDict_Check(interned)) + if (interned == NULL || interned->ob_type != &PySet_Type) return; - keys = PyDict_Keys(interned); - if (keys == NULL || !PyList_Check(keys)) { - PyErr_Clear(); - return; - } /* Since _Py_ReleaseInternedStrings() is intended to help a leak detector, interned strings are not forcibly deallocated; rather, we @@ -4988,9 +4982,8 @@ the interned dict. */ fprintf(stderr, "releasing interned strings\n"); - n = PyList_GET_SIZE(keys); - for (i = 0; i < n; i++) { - s = (PyStringObject *) PyList_GET_ITEM(keys, i); + while ((key = PySet_Pop(interned))) { + s = (PyStringObject *) key; switch (s->ob_sstate) { case SSTATE_NOT_INTERNED: /* XXX Shouldn't happen */ @@ -5006,8 +4999,6 @@ } s->ob_sstate = SSTATE_NOT_INTERNED; } - Py_DECREF(keys); - PyDict_Clear(interned); Py_DECREF(interned); interned = NULL; }