@@ -1680,31 +1680,6 @@ insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode)
1680
1680
return dictresize (interp , mp , calculate_log2_keysize (GROWTH_RATE (mp )), unicode );
1681
1681
}
1682
1682
1683
- static Py_ssize_t
1684
- insert_into_splitdictkeys (PyDictKeysObject * keys , PyObject * name , Py_hash_t hash )
1685
- {
1686
- assert (PyUnicode_CheckExact (name ));
1687
- ASSERT_KEYS_LOCKED (keys );
1688
-
1689
- Py_ssize_t ix = unicodekeys_lookup_unicode (keys , name , hash );
1690
- if (ix == DKIX_EMPTY ) {
1691
- if (keys -> dk_usable <= 0 ) {
1692
- return DKIX_EMPTY ;
1693
- }
1694
- /* Insert into new slot. */
1695
- keys -> dk_version = 0 ;
1696
- Py_ssize_t hashpos = find_empty_slot (keys , hash );
1697
- ix = keys -> dk_nentries ;
1698
- PyDictUnicodeEntry * ep = & DK_UNICODE_ENTRIES (keys )[ix ];
1699
- dictkeys_set_index (keys , hashpos , ix );
1700
- assert (ep -> me_key == NULL );
1701
- ep -> me_key = Py_NewRef (name );
1702
-
E864
split_keys_entry_added (keys );
1703
- }
1704
- assert (ix < SHARED_KEYS_MAX_SIZE );
1705
- return ix ;
1706
- }
1707
-
1708
1683
static inline int
1709
1684
insert_combined_dict (PyInterpreterState * interp , PyDictObject * mp ,
1710
1685
Py_hash_t hash , PyObject * key , PyObject * value )
@@ -1738,76 +1713,57 @@ insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
1738
1713
return 0 ;
1739
1714
}
1740
1715
1741
- // Performs an insert into a split dictionary when the key is not already
1742
- // present. Returns 0 on success, -1 on error, and 1 if a race occured and
1743
- // the key got added by another thread. Consumes key and value references
1744
- // if the key and value are successfully inserted.
1745
- static inline int
1746
- insert_split_dict (PyInterpreterState * interp , PyDictObject * mp ,
1747
- Py_hash_t hash , PyObject * key , PyObject * value ,
1748
- Py_ssize_t * ix , PyObject * * result )
1716
+ static int
1717
+ insert_split_key (PyDictKeysObject * keys , PyObject * key , Py_hash_t hash )
1749
1718
{
1750
- ASSERT_DICT_LOCKED (mp );
1719
+ assert (PyUnicode_CheckExact (key ));
1720
+ Py_ssize_t ix ;
1751
1721
1752
- PyDictKeysObject * keys = mp -> ma_keys ;
1753
- LOCK_KEYS (keys );
1754
1722
1755
1723
#ifdef Py_GIL_DISABLED
1756
- PyObject * existing_value ;
1757
- // We could have raced between our lookup before and the insert,
1758
- // so we need to lookup again with the keys locked
1759
- * ix = splitdict_lookup_keys_lock_held (mp , key , hash ,
1760
- & existing_value );
1761
- if (* ix >= 0 ) {
1762
- UNLOCK_KEYS (keys );
1763
- * result = existing_value ;
1764
- // There was a race with someone else inserting the key, the
1765
- // caller needs to handle it as they may not want to replace
1766
- // the existing value.
1767
- return 1 ;
1724
+ ix = unicodekeys_lookup_unicode_threadsafe (keys , key , hash );
1725
+ if (ix >= 0 ) {
1726
+ return ix ;
1768
1727
}
1769
1728
#endif
1770
1729
1771
- uint64_t new_version = _PyDict_NotifyEvent (
1772
- interp , PyDict_EVENT_ADDED , mp , key , value );
1773
- keys -> dk_version = 0 ;
1774
- if (keys -> dk_usable <= 0 ) {
1775
- /* Need to resize. */
1776
- UNLOCK_KEYS (keys );
1777
- int ins = insertion_resize (interp , mp , 1 );
1778
- if (ins < 0 ) {
1779
- return -1 ;
1780
- }
1781
- assert (!_PyDict_HasSplitTable (mp ));
1782
- if (insert_combined_dict (interp , mp , hash , key , value ) < 0 ) {
1783
- * result = NULL ;
1784
- return -1 ;
1785
- }
1730
+ LOCK_KEYS (keys );
1731
+ ix = unicodekeys_lookup_unicode (keys , key , hash );
1732
+ if (ix == DKIX_EMPTY && keys -> dk_usable > 0 ) {
1733
+ // Insert into new slot
1734
+ keys -> dk_version = 0 ;
1735
+ Py_ssize_t hashpos = find_empty_slot (keys , hash );
1736
+ ix = keys -> dk_nentries ;
1737
+ dictkeys_set_index (keys , hashpos , ix );
1738
+ PyDictUnicodeEntry * ep = & DK_UNICODE_ENTRIES (keys )[ix ];
1739
+ STORE_SHARED_KEY (ep -> me_key , Py_NewRef (key ));
1740
+ split_keys_entry_added (keys );
1741
+ }
1742
+ assert (ix < SHARED_KEYS_MAX_SIZE );
1743
+ UNLOCK_KEYS (keys );
1744
+ return ix ;
1745
+ }
1786
1746
1787
- * result = value ;
1747
+ static void
1748
+ insert_split_value (PyInterpreterState * interp , PyDictObject * mp , PyObject * key , PyObject * value , Py_ssize_t ix )
1749
+ {
1750
+ assert (PyUnicode_CheckExact (key ));
1751
+ MAINTAIN_TRACKING (mp , key , value );
1752
+ PyObject * old_value = mp -> ma_values -> values [ix ];
1753
+ if (old_value == NULL ) {
1754
+ uint64_t new_version = _PyDict_NotifyEvent (interp , PyDict_EVENT_ADDED , mp , key , value );
1755
+ STORE_SPLIT_VALUE (mp , ix , Py_NewRef (value ));
1756
+ _PyDictValues_AddToInsertionOrder (mp -> ma_values , ix );
1757
+ mp -> ma_used ++ ;
1788
1758
mp -> ma_version_tag = new_version ;
1789
- return 0 ;
1790
1759
}
1791
-
1792
- Py_ssize_t hashpos = find_empty_slot (keys , hash );
1793
- dictkeys_set_index (keys , hashpos , keys -> dk_nentries );
1794
-
1795
- PyDictUnicodeEntry * ep ;
1796
- ep = & DK_UNICODE_ENTRIES (keys )[keys -> dk_nentries ];
1797
- STORE_SHARED_KEY (ep -> me_key , key );
1798
-
1799
- Py_ssize_t index = keys -> dk_nentries ;
1800
- _PyDictValues_AddToInsertionOrder (mp -> ma_values , index );
1801
- assert (mp -> ma_values -> values [index ] == NULL );
1802
- STORE_SPLIT_VALUE (mp , index , value );
1803
-
1804
- split_keys_entry_added (keys );
1805
- assert (keys -> dk_usable >= 0 );
1806
-
1807
- UNLOCK_KEYS (keys );
1808
- * result = value ;
1809
- mp -> ma_version_tag = new_version ;
1810
- return 0 ;
1760
+ else {
1761
+ uint64_t new_version = _PyDict_NotifyEvent (interp , PyDict_EVENT_MODIFIED , mp , key , value );
1762
+ STORE_SPLIT_VALUE (mp , ix , Py_NewRef (value ));
1763
+ mp -> ma_version_tag = new_version ;
1764
+ Py_DECREF (old_value );
1765
+ }
1766
+ ASSERT_CONSISTENT (mp );
1811
1767
}
1812
1768
1813
1769
/*
@@ -1830,62 +1786,55 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
1830
1786
assert (mp -> ma_keys -> dk_kind == DICT_KEYS_GENERAL );
1831
1787
}
1832
1788
1789
+ if (_PyDict_HasSplitTable (mp )) {
1790
+ Py_ssize_t ix = insert_split_key (mp -> ma_keys , key , hash );
1791
+ if (ix != DKIX_EMPTY ) {
1792
+ insert_split_value (interp , mp , key , value , ix );
1793
+ Py_DECREF (key );
1794
+ Py_DECREF (value );
1795
+ return 0 ;
1796
+ }
1797
+
1798
+ /* No space in shared keys. Resize and continue below. */
1799
+ if (insertion_resize (interp , mp , 1 ) < 0 ) {
1800
+ goto Fail ;
1801
+ }
1802
+ }
1803
+
1833
1804
Py_ssize_t ix = _Py_dict_lookup (mp , key , hash , & old_value );
1834
1805
if (ix == DKIX_ERROR )
1835
1806
goto Fail ;
1836
1807
1837
1808
MAINTAIN_TRACKING (mp , key , value );
1838
1809
1839
1810
if (ix == DKIX_EMPTY ) {
1840
- if (!_PyDict_HasSplitTable (mp )) {
1841
- uint64_t new_version = _PyDict_NotifyEvent (
1842
- interp , PyDict_EVENT_ADDED , mp , key , value );
1843
- /* Insert into new slot. */
1844
- mp -> ma_keys -> dk_version = 0 ;
1845
- if (insert_combined_dict (interp , mp , hash , key , value ) < 0 ) {
1846
- goto Fail ;
1847
- }
1848
- mp -> ma_version_tag = new_version ;
1849
- }
1850
- else {
1851
- int res = insert_split_dict (interp , mp , hash , key ,
1852
- value , & ix , & old_value );
1853
- if (res < 0 ) {
1854
- return -1 ;
1855
- }
1856
- #ifdef Py_GIL_DISABLED
1857
- else if (res == 1 ) {
1858
- goto insert_on_split_race ;
1859
- }
1860
- #endif
1811
+ assert (!_PyDict_HasSplitTable (mp ));
1812
+ uint64_t new_version = _PyDict_NotifyEv
57AE
ent (
1813
+ interp , PyDict_EVENT_ADDED , mp , key , value );
1814
+ /* Insert into new slot. */
1815
+ mp -> ma_keys -> dk_version = 0 ;
1816
+ assert (old_value == NULL );
1817
+ if (insert_combined_dict (interp , mp , hash , key , value ) < 0 ) {
1818
+ goto Fail ;
1861
1819
}
1862
-
1820
+ mp -> ma_version_tag = new_version ;
1863
1821
mp -> ma_used ++ ;
1864
1822
ASSERT_CONSISTENT (mp );
1865
1823
return 0 ;
1866
1824
}
1867
1825
1868
- #ifdef Py_GIL_DISABLED
1869
- insert_on_split_race :
1870
- #endif
1871
1826
if (old_value != value ) {
1872
1827
uint64_t new_version = _PyDict_NotifyEvent (
1873
1828
interp , PyDict_EVENT_MODIFIED , mp , key , value );
1874
- if (_PyDict_HasSplitTable (mp )) {
1875
- STORE_SPLIT_VALUE (mp , ix , value );
1876
- if (old_value == NULL ) {
1877
- _PyDictValues_AddToInsertionOrder (mp -> ma_values , ix );
1878
- mp -> ma_used ++ ;
1879
- }
1829
+ assert (old_value != NULL );
1830
+ assert (!_PyDict_HasSplitTable (mp ));
1831
+ if (DK_IS_UNICODE (mp -> ma_keys )) {
1832
+ PyDictUnicodeEntry * ep = & DK_UNICODE_ENTRIES (mp -> ma_keys )[ix ];
1833
+ STORE_VALUE (ep , value );
1880
1834
}
1881
1835
else {
1882
- assert (old_value != NULL );
1883
- if (DK_IS_UNICODE (mp -> ma_keys )) {
1884
- DK_UNICODE_ENTRIES (mp -> ma_keys )[ix ].me_value = value ;
1885
- }
1886
- else {
1887
- DK_ENTRIES (mp -> ma_keys )[ix ].me_value = value ;
1888
- }
1836
+ PyDictKeyEntry * ep = & DK_ENTRIES (mp -> ma_keys )[ix ];
1837
+ STORE_VALUE (ep , value );
1889
1838
}
1890
1839
mp -> ma_version_tag = new_version ;
1891
1840
}
@@ -4294,6 +4243,29 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
4294
4243
}
4295
4244
}
4296
4245
4246
+ if (_PyDict_HasSplitTable (mp )) {
4247
+ Py_ssize_t ix = insert_split_key (mp -> ma_keys , key , hash );
4248
+ if (ix != DKIX_EMPTY ) {
4249
+ PyObject * value = mp -> ma_values -> values [ix ];
4250
+ int already_present = value != NULL ;
4251
+ if (!already_present ) {
4252
+ insert_split_value (interp , mp , key , default_value , ix );
4253
+ value = default_value ;
4254
+ }
4255
+ if (result ) {
4256
+ * result = incref_result ? Py_NewRef (value ) : value ;
4257
+ }
4258
+ return already_present ;
4259
+ }
4260
+
4261
+ /* No space in shared keys. Resize and continue below. */
4262
+ if (insertion_resize (interp , mp , 1 ) < 0 ) {
4263
+ goto error ;
4264
+ }
4265
+ }
4266
+
4267
+ assert (!_PyDict_HasSplitTable (mp ));
4268
+
4297
4269
Py_ssize_t ix = _Py_dict_lookup (mp , key , hash , & value );
4298
4270
if (ix == DKIX_ERROR ) {
4299
4271
if (result ) {
@@ -4303,79 +4275,43 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
4303
4275
}
4304
4276
4305
4277
if (ix == DKIX_EMPTY ) {
4278
+ assert (!_PyDict_HasSplitTable (mp ));
4279
+ uint64_t new_version = _PyDict_NotifyEvent (
4280
+ interp , PyDict_EVENT_ADDED , mp , key , default_value );
4281
+ mp -> ma_keys -> dk_version = 0 ;
4306
4282
value = default_value ;
4307
4283
4308
- if (!_PyDict_HasSplitTable (mp )) {
4309
- uint64_t new_version = _PyDict_NotifyEvent (
4310
- interp , PyDict_EVENT_ADDED , mp , key , default_value );
4311
- mp -> ma_keys -> dk_version = 0 ;
4312
- if (insert_combined_dict (interp , mp , hash , Py_NewRef (key ), Py_NewRef (value )) < 0 ) {
4313
- Py_DECREF (key );
4314
- Py_DECREF (value );
4315
- if (result ) {
4316
- * result = NULL ;
4317
- }
4318
- return -1 ;
4319
- }
4320
- mp -> ma_version_tag = new_version ;
4321
- }
4322
- else {
4323
- int res = insert_split_dict (interp , mp , hash , Py_NewRef (key ),
4324
- Py_NewRef (default_value ), & ix , & value );
4325
- if (res ) {
4326
- Py_DECREF (key );
4327
- Py_DECREF (value );
4328
- if (res < 0 ) {
4329
- if (result ) {
4330
- * result = NULL ;
4331
- }
4332
- return -1 ;
4333
- }
4334
-
4335
- #ifdef Py_GIL_DISABLED
4336
- // Raced with another thread inserting
4337
- goto insert_on_split_race ;
4338
- #endif
4284
+ if (insert_combined_dict (interp , mp , hash , Py_NewRef (key ), Py_NewRef (value )) < 0 ) {
4285
+ Py_DECREF (key );
4286
+ Py_DECREF (value );
4287
+ if (result ) {
4288
+ * result = NULL ;
4339
4289
}
4340
4290
}
4341
4291
4342
4292
MAINTAIN_TRACKING (mp , key , value );
4343
4293
mp -> ma_used ++ ;
4344
- assert (mp -> ma_keys -> dk_usable >= 0 );
4345
- ASSERT_CONSISTENT (mp );
4346
- if (result ) {
4347
- * result = incref_result ? Py_NewRef (value ) : value ;
4348
- }
4349
- return 0 ;
4350
- }
4351
-
4352
- #ifdef Py_GIL_DISABLED
4353
- insert_on_split_race :
4354
- #endif
4355
- if (value == NULL ) {
4356
- uint64_t new_version ;
4357
- new_version = _PyDict_NotifyEvent (
4358
- interp , PyDict_EVENT_ADDED , mp , key , default_value );
4359
- value = default_value ;
4360
- assert (_PyDict_HasSplitTable (mp ));
4361
- assert (mp -> ma_values -> values [ix ] == NULL );
4362
- MAINTAIN_TRACKING (mp , key , value );
4363
- STORE_SPLIT_VALUE (mp , ix , Py_NewRef (value ));
4364
- _PyDictValues_AddToInsertionOrder (mp -> ma_values , ix );
4365
- mp -> ma_used ++ ;
4366
4294
mp -> ma_version_tag = new_version ;
4295
+ assert (mp -> ma_keys -> dk_usable >= 0 );
4367
4296
ASSERT_CONSISTENT (mp );
4368
4297
if (result ) {
4369
4298
* result = incref_result ? Py_NewRef (value ) : value ;
4370
4299
}
4371
4300
return 0 ;
4372
4301
}
4373
4302
4303
+ assert (value != NULL );
4374
4304
ASSERT_CONSISTENT (mp );
4375
4305
if (result ) {
4376
4306
* result = incref_result ? Py_NewRef (value ) : value ;
4377
4307
}
4378
4308
return 1 ;
4309
+
4310
+ error :
4311
+ if (result ) {
4312
+ * result = NULL ;
4313
+ }
4314
+ return -1 ;
4379
4315
}
4380
4316
4381
4317
int
@@ -6830,18 +6766,7 @@ store_instance_attr_lock_held(PyObject *obj, PyDictValues *values,
6830
6766
assert (hash != -1 );
6831
6767
}
6832
6768
6833
- #ifdef Py_GIL_DISABLED
6834
- // Try a thread-safe lookup to see if the index is already allocated
6835
- ix = unicodekeys_lookup_unicode_threadsafe (keys , name , hash );
6836
- if (ix == DKIX_EMPTY || ix == DKIX_KEY_CHANGED ) {
6837
- // Lock keys and do insert
6838
- LOCK_KEYS (keys );
6839
- ix = insert_into_splitdictkeys (keys , name , hash );
6840
- UNLOCK_KEYS (keys );
6841
- }
6842
- #else
6843
- ix = insert_into_splitdictkeys (keys , name , hash );
6844
- #endif
6769
+ ix = insert_split_key (keys , name , hash );
6845
6770
6846
6771
#ifdef Py_STATS
6847
6772
if (ix == DKIX_EMPTY ) {
0 commit comments