Skip to content

Commit 67b1c76

Browse files
[3.13] gh-132213: use relaxed atomics for set hash (#132447)
1 parent f943376 commit 67b1c76

File tree

1 file changed

+27
-14
lines changed

1 file changed

+27
-14
lines changed

Objects/setobject.c

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ set_empty_to_minsize(PySetObject *so)
400400
FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, 0);
401401
so->mask = PySet_MINSIZE - 1;
402402
so->table = so->smalltable;
403-
so->hash = -1;
403+
FT_ATOMIC_STORE_SSIZE_RELAXED(so->hash, -1);
404404
}
405405

406406
static int
@@ -718,18 +718,15 @@ _shuffle_bits(Py_uhash_t h)
718718
large primes with "interesting bit patterns" and that passed tests
719719
for good collision statistics on a variety of problematic datasets
720720
including powersets and graph structures (such as David Eppstein's
721-
graph recipes in Lib/test/test_set.py) */
721+
graph recipes in Lib/test/test_set.py). */
722722

723723
static Py_hash_t
724-
frozenset_hash(PyObject *self)
724+
frozenset_hash_impl(PyObject *self)
725725
{
726-
PySetObject *so = (PySetObject *)self;
726+
PySetObject *so = _PySet_CAST(self);
727727
Py_uhash_t hash = 0;
728728
setentry *entry;
729729

730-
if (so->hash != -1)
731-
return so->hash;
732-
733730
/* Xor-in shuffled bits from every entry's hash field because xor is
734731
commutative and a frozenset hash should be independent of order.
735732
@@ -762,7 +759,21 @@ frozenset_hash(PyObject *self)
762759
if (hash == (Py_uhash_t)-1)
763760
hash = 590923713UL;
764761

765-
so->hash = hash;
762+
return (Py_hash_t)hash;
763+
}
764+
765+
static Py_hash_t
766+
frozenset_hash(PyObject *self)
767+
{
768+
PySetObject *so = _PySet_CAST(self);
769+
Py_uhash_t hash;
770+
771+
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(so->hash) != -1) {
772+
return FT_ATOMIC_LOAD_SSIZE_RELAXED(so->hash);
773+
}
774+
775+
hash = frozenset_hash_impl(self);
776+
FT_ATOMIC_STORE_SSIZE_RELAXED(so->hash, hash);
766777
return hash;
767778
}
768779

@@ -1202,10 +1213,12 @@ set_swap_bodies(PySetObject *a, PySetObject *b)
12021213

12031214
if (PyType_IsSubtype(Py_TYPE(a), &PyFrozenSet_Type) &&
12041215
PyType_IsSubtype(Py_TYPE(b), &PyFrozenSet_Type)) {
1205-
h = a->hash; a->hash = b->hash; b->hash = h;
1216+
h = FT_ATOMIC_LOAD_SSIZE_RELAXED(a->hash);
1217+
FT_ATOMIC_STORE_SSIZE_RELAXED(a->hash, FT_ATOMIC_LOAD_SSIZE_RELAXED(b->hash));
1218+
FT_ATOMIC_STORE_SSIZE_RELAXED(b->hash, h);
12061219
} else {
1207-
a->hash = -1;
1208-
b->hash = -1;
1220+
FT_ATOMIC_STORE_SSIZE_RELAXED(a->hash, -1);
1221+
FT_ATOMIC_STORE_SSIZE_RELAXED(b->hash, -1);
12091222
}
12101223
}
12111224

@@ -2086,9 +2099,9 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
20862099
case Py_EQ:
20872100
if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
20882101
Py_RETURN_FALSE;
2089-
if (v->hash != -1 &&
2090-
((PySetObject *)w)->hash != -1 &&
2091-
v->hash != ((PySetObject *)w)->hash)
2102+
Py_hash_t v_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(v->hash);
2103+
Py_hash_t w_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(((PySetObject *)w)->hash);
2104+
if (v_hash != -1 && w_hash != -1 && v_hash != w_hash)
20922105
Py_RETURN_FALSE;
20932106
return set_issubset(v, w);
20942107
case Py_NE:

0 commit comments

Comments
 (0)