Skip to content

Commit aeed04a

Browse files
committed
Fix free-threading
1 parent 992b4b6 commit aeed04a

3 files changed

Lines changed: 105 additions & 0 deletions

File tree

Include/internal/pycore_dict.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ extern void _PyDict_Clear_LockHeld(PyObject *op);
176176

177177
#ifdef Py_GIL_DISABLED
178178
PyAPI_FUNC(void) _PyDict_EnsureSharedOnRead(PyDictObject *mp);
179+
extern void _PyFrozenDict_ClearInternal(PyObject *op);
179180
#endif
180181

181182
// Export for '_elementtree' shared extension

Objects/codeobject.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "pycore_pymem.h" // _PyMem_FreeDelayed()
1515
#include "pycore_pystate.h" // _PyInterpreterState_GET()
1616
#include "pycore_setobject.h" // _PySet_NextEntry()
17+
#include "pycore_dict.h" // _PyFrozenDict_ClearInternal()
1718
#include "pycore_tuple.h" // _PyTuple_ITEMS()
1819
#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal()
1920
#include "pycore_uniqueid.h" // _PyObject_AssignUniqueId()
@@ -167,6 +168,16 @@ should_immortalize_constant(PyObject *v)
167168
}
168169
return 1;
169170
}
171+
else if (PyFrozenDict_CheckExact(v)) {
172+
Py_ssize_t pos = 0;
173+
PyObject *key, *value;
174+
while (PyDict_Next(v, &pos, &key, &value)) {
175+
if (!_Py_IsImmortal(key) || !_Py_IsImmortal(value)) {
176+
return 0;
177+
}
178+
}
179+
return 1;
180+
}
170181
else if (PySlice_Check(v)) {
171182
PySliceObject *slice = (PySliceObject *)v;
172183
return (_Py_IsImmortal(slice->start) &&
@@ -248,6 +259,53 @@ intern_constants(PyObject *tuple, int *modified)
248259
}
249260
Py_DECREF(tmp);
250261
}
262+
else if (PyFrozenDict_CheckExact(v)) {
263+
PyObject *w = v;
264+
PyObject *tmp = PyTuple_New(2 * PyDict_GET_SIZE(v));
265+
if (tmp == NULL) {
266+
return -1;
267+
}
268+
Py_ssize_t pos = 0;
269+
PyObject *k, *val;
270+
Py_ssize_t j = 0;
271+
while (PyDict_Next(v, &pos, &k, &val)) {
272+
PyTuple_SET_ITEM(tmp, j++, Py_NewRef(k));
273+
PyTuple_SET_ITEM(tmp, j++, Py_NewRef(val));
274+
}
275+
int tmp_modified = 0;
276+
if (intern_constants(tmp, &tmp_modified) < 0) {
277+
Py_DECREF(tmp);
278+
return -1;
279+
}
280+
if (tmp_modified) {
281+
PyObject *new_dict = PyDict_New();
282+
if (new_dict == NULL) {
283+
Py_DECREF(tmp);
284+
return -1;
285+
}
286+
for (j = 0; j < PyTuple_GET_SIZE(tmp); j += 2) {
287+
if (PyDict_SetItem(new_dict,
288+
PyTuple_GET_ITEM(tmp, j),
289+
PyTuple_GET_ITEM(tmp, j + 1)) < 0) {
290+
Py_DECREF(tmp);
291+
Py_DECREF(new_dict);
292+
return -1;
293+
}
294+
}
295+
v = PyFrozenDict_New(new_dict);
296+
Py_DECREF(new_dict);
297+
if (v == NULL) {
298+
Py_DECREF(tmp);
299+
return -1;
300+
}
301+
PyTuple_SET_ITEM(tuple, i, v);
302+
Py_DECREF(w);
303+
if (modified) {
304+
*modified = 1;
305+
}
306+
}
307+
Py_DECREF(tmp);
308+
}
251309
#ifdef Py_GIL_DISABLED
252310
else if (PySlice_Check(v)) {
253311
PySliceObject *slice = (PySliceObject *)v;
@@ -3199,6 +3257,21 @@ compare_constants(const void *key1, const void *key2)
31993257
}
32003258
return 1;
32013259
}
3260+
else if (PyFrozenDict_CheckExact(op1)) {
3261+
if (PyDict_GET_SIZE(op1) != PyDict_GET_SIZE(op2)) {
3262+
return 0;
3263+
}
3264+
Py_ssize_t pos1 = 0, pos2 = 0;
3265+
PyObject *k1, *k2, *v1, *v2;
3266+
while (PyDict_Next(op1, &pos1, &k1, &v1) &&
3267+
PyDict_Next(op2, &pos2, &k2, &v2))
3268+
{
3269+
if (k1 != k2 || v1 != v2) {
3270+
return 0;
3271+
}
3272+
}
3273+
return 1;
3274+
}
32023275
else if (PySlice_Check(op1)) {
32033276
PySliceObject *s1 = (PySliceObject *)op1;
32043277
PySliceObject *s2 = (PySliceObject *)op2;
@@ -3273,6 +3346,9 @@ clear_containers(_Py_hashtable_t *ht, const void *key, const void *value,
32733346
else if (PyFrozenSet_CheckExact(op)) {
32743347
_PySet_ClearInternal((PySetObject *)op);
32753348
}
3349+
else if (PyFrozenDict_CheckExact(op)) {
3350+
_PyFrozenDict_ClearInternal(op);
3351+
}
32763352
return 0;
32773353
}
32783354

Objects/dictobject.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,34 @@ _PyDict_Clear_LockHeld(PyObject *op) {
30983098
clear_lock_held(op);
30993099
}
31003100

3101+
#ifdef Py_GIL_DISABLED
3102+
void
3103+
_PyFrozenDict_ClearInternal(PyObject *op)
3104+
{
3105+
assert(PyFrozenDict_CheckExact(op));
3106+
PyDictObject *mp = (PyDictObject *)op;
3107+
PyDictKeysObject *keys = mp->ma_keys;
3108+
if (keys == Py_EMPTY_KEYS) {
3109+
return;
3110+
}
3111+
assert(mp->ma_values == NULL);
3112+
if (DK_IS_UNICODE(keys)) {
3113+
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
3114+
for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
3115+
Py_CLEAR(entries[i].me_key);
3116+
Py_CLEAR(entries[i].me_value);
3117+
}
3118+
}
3119+
else {
3120+
PyDictKeyEntry *entries = DK_ENTRIES(keys);
3121+
for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
3122+
Py_CLEAR(entries[i].me_key);
3123+
Py_CLEAR(entries[i].me_value);
3124+
}
3125+
}
3126+
}
3127+
#endif
3128+
31013129
void
31023130
PyDict_Clear(PyObject *op)
31033131
{

0 commit comments

Comments
 (0)