@@ -161,14 +161,16 @@ ASSERT_DICT_LOCKED(PyObject *op)
161
161
#define INCREF_KEYS (dk ) _Py_atomic_add_ssize(&dk->dk_refcnt, 1)
162
162
// Dec refs the keys object, giving the previous value
163
163
#define DECREF_KEYS (dk ) _Py_atomic_add_ssize(&dk->dk_refcnt, -1)
164
+ #define LOAD_KEYS_NENTIRES (keys ) _Py_atomic_load_ssize_relaxed(&keys->dk_nentries)
165
+
164
166
static inline void split_keys_entry_added (PyDictKeysObject * keys )
165
167
{
166
168
ASSERT_KEYS_LOCKED (keys );
167
169
168
170
// We increase before we decrease so we never get too small of a value
169
171
// when we're racing with reads
170
- _Py_atomic_store_ssize (& keys -> dk_nentries , keys -> dk_nentries + 1 );
171
- _Py_atomic_store_ssize (& keys -> dk_usable , keys -> dk_usable - 1 );
172
+ _Py_atomic_store_ssize_relaxed (& keys -> dk_nentries , keys -> dk_nentries + 1 );
173
+ _Py_atomic_store_ssize_release (& keys -> dk_usable , keys -> dk_usable - 1 );
172
174
}
173
175
174
176
#else /* Py_GIL_DISABLED */
@@ -181,6 +183,8 @@ static inline void split_keys_entry_added(PyDictKeysObject *keys)
181
183
#define STORE_SHARED_KEY (key , value ) key = value
182
184
#define INCREF_KEYS (dk ) dk->dk_refcnt++
183
185
#define DECREF_KEYS (dk ) dk->dk_refcnt--
186
+ #define LOAD_KEYS_NENTIRES (keys ) keys->dk_nentries
187
+
184
188
static inline void split_keys_entry_added (PyDictKeysObject * keys )
185
189
{
186
190
keys -> dk_usable -- ;
@@ -545,7 +549,7 @@ static PyDictKeysObject empty_keys_struct = {
545
549
0 , /* dk_log2_index_bytes */
546
550
DICT_KEYS_UNICODE , /* dk_kind */
547
551
#ifdef Py_GIL_DISABLED
548
- {0 }, /* dk_lock */
552
+ {0 }, /* dk_mutex */
549
553
#endif
550
554
1 , /* dk_version */
551
555
0 , /* dk_usable (immutable) */
@@ -825,9 +829,9 @@ shared_keys_usable_size(PyDictKeysObject *keys)
825
829
{
826
830
#ifdef Py_GIL_DISABLED
827
831
// dk_usable will decrease for each instance that is created and each
828
- // value that is added. dk_entries will increase for each value that
832
+ // value that is added. dk_nentries will increase for each value that
829
833
// is added. We want to always return the right value or larger.
830
- // We therefore increase dk_entries first and we decrease dk_usable
834
+ // We therefore increase dk_nentries first and we decrease dk_usable
831
835
// second, and conversely here we read dk_usable first and dk_entries
832
836
// second (to avoid the case where we read entries before the increment
833
837
// and read usable after the decrement)
@@ -846,15 +850,13 @@ new_dict_with_shared_keys(PyInterpreterState *interp, PyDictKeysObject *keys)
846
850
PyDictValues * values = new_values (size );
847
851
if (values == NULL ) {
848
852
dictkeys_decref (interp , keys );
849
- UNLOCK_KEYS (keys );
850
853
return PyErr_NoMemory ();
851
854
}
852
855
((char * )values )[-2 ] = 0 ;
853
856
for (size_t i = 0 ; i < size ; i ++ ) {
854
857
values -> values [i ] = NULL ;
855
858
}
856
- PyObject * res = new_dict (interp , keys , values , 0 , 1 );
857
- return res ;
859
+ return new_dict (interp , keys , values , 0 , 1 );
858
860
}
859
861
860
862
@@ -1266,7 +1268,7 @@ insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode)
1266
1268
}
1267
1269
1268
1270
static Py_ssize_t
1269
- insert_into_dictkeys (PyDictKeysObject * keys , PyObject * name )
1271
+ insert_into_splitdictkeys (PyDictKeysObject * keys , PyObject * name )
1270
1272
{
1271
1273
assert (PyUnicode_CheckExact (name ));
1272
1274
ASSERT_KEYS_LOCKED (keys );
@@ -1301,7 +1303,7 @@ insert_into_dictkeys(PyDictKeysObject *keys, PyObject *name)
1301
1303
1302
1304
static inline int
1303
1305
insert_combined_dict (PyInterpreterState * interp , PyDictObject * mp ,
1304
- Py_hash_t hash , PyObject * key , PyObject * value , int unicode )
1306
+ Py_hash_t hash , PyObject * key , PyObject * value )
1305
1307
{
1306
1308
if (mp -> ma_keys -> dk_usable <= 0 ) {
1307
1309
/* Need to resize. */
@@ -1313,7 +1315,7 @@ insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
1313
1315
Py_ssize_t hashpos = find_empty_slot (mp -> ma_keys , hash );
1314
1316
dictkeys_set_index (mp -> ma_keys , hashpos , mp -> ma_keys -> dk_nentries );
1315
1317
1316
- if (unicode ) {
1318
+ if (DK_IS_UNICODE ( mp -> ma_keys ) ) {
1317
1319
PyDictUnicodeEntry * ep ;
1318
1320
ep = & DK_UNICODE_ENTRIES (mp -> ma_keys )[mp -> ma_keys -> dk_nentries ];
1319
1321
ep -> me_key = key ;
@@ -1340,14 +1342,16 @@ insert_split_dict(PyInterpreterState *interp, PyDictObject *mp,
1340
1342
LOCK_KEYS (keys );
1341
1343
if (keys -> dk_usable <= 0 ) {
1342
1344
/* Need to resize. */
1343
- if (insertion_resize (interp , mp , 1 ) < 0 ) {
1344
- UNLOCK_KEYS (keys );
1345
+ dictkeys_incref (keys );
1346
+ int ins = insertion_resize (interp , mp , 1 );
1347
+ dictkeys_decref (interp , keys );
1348
+ UNLOCK_KEYS (keys );
1349
+ if (ins < 0 ) {
1345
1350
return -1 ;
1346
1351
}
1347
1352
assert (!_PyDict_HasSplitTable (mp ));
1348
1353
assert (DK_IS_UNICODE (keys ));
1349
- UNLOCK_KEYS (keys );
1350
- return insert_combined_dict (interp , mp , hash , key , value , 1 );
1354
+ return insert_combined_dict (interp , mp , hash , key , value );
1351
1355
}
1352
1356
1353
1357
Py_ssize_t hashpos = find_empty_slot (keys , hash );
@@ -1425,9 +1429,8 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
1425
1429
mp -> ma_keys -> dk_version = 0 ;
1426
1430
assert (old_value == NULL );
1427
1431
1428
- int unicode = DK_IS_UNICODE (mp -> ma_keys );
1429
- if (!unicode || !_PyDict_HasSplitTable (mp )) {
1430
- if (insert_combined_dict (interp , mp , hash , key , value , unicode ) < 0 ) {
1432
+ if (!_PyDict_HasSplitTable (mp )) {
1433
+ if (insert_combined_dict (interp , mp , hash , key , value ) < 0 ) {
1431
1434
goto Fail ;
1432
1435
}
1433
1436
} else {
@@ -3608,21 +3611,7 @@ dict_equal_lock_held(PyDictObject *a, PyDictObject *b)
3608
3611
/* can't be equal if # of entries differ */
3609
3612
return 0 ;
3610
3613
/* Same # of entries -- check all of 'em. Exit early on any diff. */
3611
- Py_ssize_t n_entries ;
3612
- #ifdef Py_GIL_DISABLED
3613
- if (_PyDict_HasSplitTable (a )) {
3614
- // New entries can be appended, but existing ones won't change, and
3615
- // our keys won't change because the dict is locked. So capture
3616
- // the current number of keys at entry.
3617
- LOCK_KEYS (a -> ma_keys );
3618
- n_entries = a -> ma_keys -> dk_nentries ;
3619
- UNLOCK_KEYS (a -> ma_keys );
3620
- } else
3621
- #endif
3622
- {
3623
- n_entries = a -> ma_keys -> dk_nentries ;
3624
- }
3625
- for (i = 0 ; i < n_entries ; i ++ ) {
3614
+ for (i = 0 ; i < LOAD_KEYS_NENTIRES (a -> ma_keys ); i ++ ) {
3626
3615
PyObject * key , * aval ;
3627
3616
Py_hash_t hash ;
3628
3617
if (DK_IS_UNICODE (a -> ma_keys )) {
@@ -3836,9 +3825,8 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
3836
3825
mp -> ma_keys -> dk_version = 0 ;
3837
3826
value = default_value ;
3838
3827
3839
- int unicode = DK_IS_UNICODE (mp -> ma_keys );
3840
- if (!unicode || !_PyDict_HasSplitTable (mp )) {
3841
- if (insert_combined_dict (interp , mp , hash , Py_NewRef (key ), Py_NewRef (value ), unicode ) < 0 ) {
3828
+ if (!_PyDict_HasSplitTable (mp )) {
3829
+ if (insert_combined_dict (interp , mp , hash , Py_NewRef (key ), Py_NewRef (value )) < 0 ) {
3842
3830
Py_DECREF (key );
3843
3831
Py_DECREF (value );
3844
3832
if (result ) {
@@ -6048,11 +6036,13 @@ _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp)
6048
6036
PyDictKeysObject * keys = CACHED_KEYS (tp );
6049
6037
assert (keys != NULL );
6050
6038
#ifdef Py_GIL_DISABLED
6051
- Py_ssize_t usable = keys -> dk_usable ;
6052
- while (usable > 1 ) {
6053
- if (_Py_atomic_compare_exchange_ssize (& keys -> dk_usable , & usable , usable - 1 )) {
6054
- break ;
6039
+ Py_ssize_t usable = _Py_atomic_load_ssize_relaxed (& keys -> dk_usable );
6040
+ if (usable > 1 ) {
6041
+ LOCK_KEYS (keys );
6042
+ if (keys -> dk_usable > 1 ) {
6043
+ _Py_atomic_store_ssize (& keys -> dk_usable , keys -> dk_usable - 1 );
6055
6044
}
6045
+ UNLOCK_KEYS (keys );
6056
6046
}
6057
6047
#else
6058
6048
if (keys -> dk_usable > 1 ) {
@@ -6176,7 +6166,7 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
6176
6166
Py_ssize_t ix = DKIX_EMPTY ;
6177
6167
if (PyUnicode_CheckExact (name )) {
6178
6168
LOCK_KEYS (keys );
6179
- ix = insert_into_dictkeys (keys , name );
6169
+ ix = insert_into_splitdictkeys (keys , name );
6180
6170
#ifdef Py_STATS
6181
6171
if (ix == DKIX_EMPTY ) {
6182
6172
if (PyUnicode_CheckExact (name )) {
0 commit comments