@@ -1606,31 +1606,6 @@ insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode)
1606
1606
return dictresize (interp , mp , calculate_log2_keysize (GROWTH_RATE (mp )), unicode );
1607
1607
}
1608
1608
1609
- static Py_ssize_t
1610
- insert_into_splitdictkeys (PyDictKeysObject * keys , PyObject * name , Py_hash_t hash )
1611
- {
1612
- assert (PyUnicode_CheckExact (name ));
1613
- ASSERT_KEYS_LOCKED (keys );
1614
-
1615
- Py_ssize_t ix = unicodekeys_lookup_unicode (keys , name , hash );
1616
- if (ix == DKIX_EMPTY ) {
1617
- if (keys -> dk_usable <= 0 ) {
1618
- return DKIX_EMPTY ;
1619
- }
1620
- /* Insert into new slot. */
1621
- keys -> dk_version = 0 ;
1622
- Py_ssize_t hashpos = find_empty_slot (keys , hash );
1623
- ix = keys -> dk_nentries ;
1624
- PyDictUnicodeEntry * ep = & DK_UNICODE_ENTRIES (keys )[ix ];
1625
- dictkeys_set_index (keys , hashpos , ix );
1626
- assert (ep -> me_key == NULL );
1627
- ep -> me_key = Py_NewRef (name );
1628
- split_keys_entry_added (keys );
1629
- }
1630
- assert (ix < SHARED_KEYS_MAX_SIZE );
1631
- return ix ;
1632
- }
1633
-
1634
1609
static inline int
1635
1610
insert_combined_dict (PyInterpreterState * interp , PyDictObject * mp ,
1636
1611
Py_hash_t hash , PyObject * key , PyObject * value )
@@ -1664,39 +1639,56 @@ insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
1664
1639
return 0 ;
1665
1640
}
1666
1641
1667
- static int
1668
- insert_split_dict (PyInterpreterState * interp , PyDictObject * mp ,
1669
- Py_hash_t hash , PyObject * key , PyObject * value )
1642
+ static Py_ssize_t
1643
+ insert_split_key (PyDictKeysObject * keys , PyObject * key , Py_hash_t hash )
1670
1644
{
1671
- PyDictKeysObject * keys = mp -> ma_keys ;
1672
- LOCK_KEYS (keys );
1673
- if (keys -> dk_usable <= 0 ) {
1674
- /* Need to resize. */
1675
- UNLOCK_KEYS (keys );
1676
- int ins = insertion_resize (interp , mp , 1 );
1677
- if (ins < 0 ) {
1678
- return -1 ;
1679
- }
1680
- assert (!_PyDict_HasSplitTable (mp ));
1681
- return insert_combined_dict (interp , mp , hash , key , value );
1682
- }
1683
-
1684
- Py_ssize_t hashpos = find_empty_slot (keys , hash );
1685
- dictkeys_set_index (keys , hashpos , keys -> dk_nentries );
1686
-
1687
- PyDictUnicodeEntry * ep ;
1688
- ep = & DK_UNICODE_ENTRIES (keys )[keys -> dk_nentries ];
1689
- STORE_SHARED_KEY (ep -> me_key , key );
1645
+ assert (PyUnicode_CheckExact (key ));
1646
+ Py_ssize_t ix ;
1690
1647
1691
- Py_ssize_t index = keys -> dk_nentries ;
1692
- _PyDictValues_AddToInsertionOrder (mp -> ma_values , index );
1693
- assert (mp -> ma_values -> values [index ] == NULL );
1694
- STORE_SPLIT_VALUE (mp , index , value );
1648
+ #ifdef Py_GIL_DISABLED
1649
+ ix = unicodekeys_lookup_unicode_threadsafe (keys , key , hash );
1650
+ if (ix >= 0 ) {
1651
+ return ix ;
1652
+ }
1653
+ #endif
1695
1654
1696
- split_keys_entry_added (keys );
1697
- assert (keys -> dk_usable >= 0 );
1655
+ LOCK_KEYS (keys );
1656
+ ix = unicodekeys_lookup_unicode (keys , key , hash );
1657
+ if (ix == DKIX_EMPTY && keys -> dk_usable > 0 ) {
1658
+ // Insert into new slot
1659
+ keys -> dk_version = 0 ;
1660
+ Py_ssize_t hashpos = find_empty_slot (keys , hash );
1661
+ ix = keys -> dk_nentries ;
1662
+ dictkeys_set_index (keys , hashpos , ix );
1663
+ PyDictUnicodeEntry * ep = & DK_UNICODE_ENTRIES (keys )[ix ];
1664
+ STORE_SHARED_KEY (ep -> me_key , Py_NewRef (key ));
1665
+ split_keys_entry_added (keys );
1666
+ }
1667
+ assert (ix < SHARED_KEYS_MAX_SIZE );
1698
1668
UNLOCK_KEYS (keys );
1699
- return 0 ;
1669
+ return ix ;
1670
+ }
1671
+
1672
+ static void
1673
+ insert_split_value (PyInterpreterState * interp , PyDictObject * mp , PyObject * key , PyObject * value , Py_ssize_t ix )
1674
+ {
1675
+ assert (PyUnicode_CheckExact (key ));
1676
+ MAINTAIN_TRACKING (mp , key , value );
1677
+ PyObject * old_value = mp -> ma_values -> values [ix ];
1678
+ if (old_value == NULL ) {
1679
+ uint64_t new_version = _PyDict_NotifyEvent (interp , PyDict_EVENT_ADDED , mp , key , value );
1680
+ STORE_SPLIT_VALUE (mp , ix , Py_NewRef (value ));
1681
+ _PyDictValues_AddToInsertionOrder (mp -> ma_values , ix );
1682
+ mp -> ma_used ++ ;
1683
+ mp -> ma_version_tag = new_version ;
1684
+ }
1685
+ else {
1686
+ uint64_t new_version = _PyDict_NotifyEvent (interp , PyDict_EVENT_MODIFIED , mp , key , value );
1687
+ STORE_SPLIT_VALUE (mp , ix , Py_NewRef (value ));
1688
+ mp -> ma_version_tag = new_version ;
1689
+ Py_DECREF (old_value );
1690
+ }
1691
+ ASSERT_CONSISTENT (mp );
1700
1692
}
1701
1693
1702
1694
/*
@@ -1719,6 +1711,21 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
1719
1711
assert (mp -> ma_keys -> dk_kind == DICT_KEYS_GENERAL );
1720
1712
}
1721
1713
1714
+ if (mp -> ma_keys -> dk_kind == DICT_KEYS_SPLIT ) {
1715
+ Py_ssize_t ix = insert_split_key (mp -> ma_keys , key , hash );
1716
+ if (ix != DKIX_EMPTY ) {
1717
+ insert_split_value (interp , mp , key , value , ix );
1718
+ Py_DECREF (key );
1719
+ Py_DECREF (value );
1720
+ return 0 ;
1721
+ }
1722
+
1723
+ /* No space in shared keys. Resize and continue below. */
1724
+ if (insertion_resize (interp , mp , 1 ) < 0 ) {
1725
+ goto Fail ;
1726
+ }
1727
+ }
1728
+
1722
1729
Py_ssize_t ix = _Py_dict_lookup (mp , key , hash , & old_value );
1723
1730
if (ix == DKIX_ERROR )
1724
1731
goto Fail ;
@@ -1731,17 +1738,9 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
1731
1738
/* Insert into new slot. */
1732
1739
mp -> ma_keys -> dk_version = 0 ;
1733
1740
assert (old_value == NULL );
1734
-
1735
- if (!_PyDict_HasSplitTable (mp )) {
1736
- if (insert_combined_dict (interp , mp , hash , key , value ) < 0 ) {
1737
- goto Fail ;
1738
- }
1739
- }
1740
- else {
1741
- if (insert_split_dict (interp , mp , hash , key , value ) < 0 )
1742
- goto Fail ;
1741
+ if (insert_combined_dict (interp , mp , hash , key , value ) < 0 ) {
1742
+ goto Fail ;
1743
1743
}
1744
-
1745
1744
mp -> ma_used ++ ;
1746
1745
mp -> ma_version_tag = new_version ;
1747
1746
ASSERT_CONSISTENT (mp );
@@ -1751,21 +1750,12 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
1751
1750
if (old_value != value ) {
1752
1751
uint64_t new_version = _PyDict_NotifyEvent (
1753
1752
interp , PyDict_EVENT_MODIFIED , mp , key , value );
1754
- if (_PyDict_HasSplitTable (mp )) {
1755
- STORE_SPLIT_VALUE (mp , ix , value );
1756
- if (old_value == NULL ) {
1757
- _PyDictValues_AddToInsertionOrder (mp -> ma_values , ix );
1758
- mp -> ma_used ++ ;
1759
- }
1753
+ assert (old_value != NULL );
1754
+ if (DK_IS_UNICODE (mp -> ma_keys )) {
1755
+ DK_UNICODE_ENTRIES (mp -> ma_keys )[ix ].me_value = value ;
1760
1756
}
1761
1757
else {
1762
- assert (old_value != NULL );
1763
- if (DK_IS_UNICODE (mp -> ma_keys )) {
1764
- DK_UNICODE_ENTRIES (mp -> ma_keys )[ix ].me_value = value ;
1765
- }
1766
- else {
1767
- DK_ENTRIES (mp -> ma_keys )[ix ].me_value = value ;
1768
- }
1758
+ DK_ENTRIES (mp -> ma_keys )[ix ].me_value = value ;
1769
1759
}
1770
1760
mp -> ma_version_tag = new_version ;
1771
1761
}
@@ -4174,6 +4164,29 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
4174
4164
}
4175
4165
}
4176
4166
4167
+ if (mp -> ma_keys -> dk_kind == DICT_KEYS_SPLIT ) {
4168
+ Py_ssize_t ix = insert_split_key (mp -> ma_keys , key , hash );
4169
+ if (ix != DKIX_EMPTY ) {
4170
+ PyObject * value = mp -> ma_values -> values [ix ];
4171
+ int already_present = value != NULL ;
4172
+ if (!already_present ) {
4173
+ insert_split_value (interp , mp , key , default_value , ix );
4174
+ value = default_value ;
4175
+ }
4176
+ if (result ) {
4177
+ * result = incref_result ? Py_NewRef (value ) : value ;
4178
+ }
4179
+ return already_present ;
4180
+ }
4181
+
4182
+ /* No space in shared keys. Resize and continue below. */
4183
+ if (insertion_resize (interp , mp , 1 ) < 0 ) {
4184
+ goto error ;
4185
+ }
4186
+ }
4187
+
4188
+ assert (!_PyDict_HasSplitTable (mp ));
4189
+
4177
4190
Py_ssize_t ix = _Py_dict_lookup (mp , key , hash , & value );
4178
4191
if (ix == DKIX_ERROR ) {
4179
4192
if (result ) {
@@ -4188,25 +4201,13 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
4188
4201
mp -> ma_keys -> dk_version = 0 ;
4189
4202
value = default_value ;
4190
4203
4191
- if (!_PyDict_HasSplitTable (mp )) {
4192
- if (insert_combined_dict (interp , mp , hash , Py_NewRef (key ), Py_NewRef (value )) < 0 ) {
4193
- Py_DECREF (key );
4194
- Py_DECREF (value );
4195
- if (result ) {
4196
- * result = NULL ;
4197
- }
4198
- return -1 ;
4199
- }
4200
- }
4201
- else {
4202
- if (insert_split_dict (interp , mp , hash , Py_NewRef (key ), Py_NewRef (value )) < 0 ) {
4203
- Py_DECREF (key );
4204
- Py_DECREF (value );
4205
- if (result ) {
4206
- * result = NULL ;
4207
- }
4208
- return -1 ;
4204
+ if (insert_combined_dict (interp , mp , hash , Py_NewRef (key ), Py_NewRef (value )) < 0 ) {
4205
+ Py_DECREF (key );
4206
+ Py_DECREF (value );
4207
+ if (result ) {
4208
+ * result = NULL ;
4209
4209
}
4210
+ return -1 ;
4210
4211
}
4211
4212
4212
4213
MAINTAIN_TRACKING (mp , key , value );
@@ -4219,29 +4220,19 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
4219
4220
}
4220
4221
return 0 ;
4221
4222
}
4222
- else if (value == NULL ) {
4223
- uint64_t new_version = _PyDict_NotifyEvent (
4224
- interp , PyDict_EVENT_ADDED , mp , key , default_value );
4225
- value = default_value ;
4226
- assert (_PyDict_HasSplitTable (mp ));
4227
- assert (mp -> ma_values -> values [ix ] == NULL );
4228
- MAINTAIN_TRACKING (mp , key , value );
4229
- STORE_SPLIT_VALUE (mp , ix , Py_NewRef (value ));
4230
- _PyDictValues_AddToInsertionOrder (mp -> ma_values , ix );
4231
- mp -> ma_used ++ ;
4232
- mp -> ma_version_tag = new_version ;
4233
- ASSERT_CONSISTENT (mp );
4234
- if (result ) {
4235
- * result = incref_result ? Py_NewRef (value ) : value ;
4236
- }
4237
- return 0 ;
4238
- }
4239
4223
4224
+ assert (value != NULL );
4240
4225
ASSERT_CONSISTENT (mp );
4241
4226
if (result ) {
4242
4227
* result = incref_result ? Py_NewRef (value ) : value ;
4243
4228
}
4244
4229
return 1 ;
4230
+
4231
+ error :
4232
+ if (result ) {
4233
+ * result = NULL ;
4234
+ }
4235
+ return -1 ;
4245
4236
}
4246
4237
4247
4238
int
@@ -6696,18 +6687,7 @@ store_instance_attr_lock_held(PyObject *obj, PyDictValues *values,
6696
6687
assert (hash != -1 );
6697
6688
}
6698
6689
6699
- #ifdef Py_GIL_DISABLED
6700
- // Try a thread-safe lookup to see if the index is already allocated
6701
- ix = unicodekeys_lookup_unicode_threadsafe (keys , name , hash );
6702
- if (ix == DKIX_EMPTY || ix == DKIX_KEY_CHANGED ) {
6703
- // Lock keys and do insert
6704
- LOCK_KEYS (keys );
6705
- ix = insert_into_splitdictkeys (keys , name , hash );
6706
- UNLOCK_KEYS (keys );
6707
- }
6708
- #else
6709
- ix = insert_into_splitdictkeys (keys , name , hash );
6710
- #endif
6690
+ ix = insert_split_key (keys , name , hash );
6711
6691
6712
6692
#ifdef Py_STATS
6713
6693
if (ix == DKIX_EMPTY ) {
0 commit comments