@@ -924,16 +924,15 @@ new_dict(PyInterpreterState *interp,
924924 return (PyObject * )mp ;
925925}
926926
927- /* Consumes a reference to the keys object */
928927static PyObject *
929928new_dict_with_shared_keys (PyInterpreterState * interp , PyDictKeysObject * keys )
930929{
931930 size_t size = shared_keys_usable_size (keys );
932931 PyDictValues * values = new_values (size );
933932 if (values == NULL ) {
934- dictkeys_decref (interp , keys , false);
935933 return PyErr_NoMemory ();
936934 }
935+ dictkeys_incref (keys );
937936 for (size_t i = 0 ; i < size ; i ++ ) {
938937 values -> values [i ] = NULL ;
939938 }
@@ -6693,8 +6692,6 @@ materialize_managed_dict_lock_held(PyObject *obj)
66936692{
66946693 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (obj );
66956694
6696- OBJECT_STAT_INC (dict_materialized_on_request );
6697-
66986695 PyDictValues * values = _PyObject_InlineValues (obj );
66996696 PyInterpreterState * interp = _PyInterpreterState_GET ();
67006697 PyDictKeysObject * keys = CACHED_KEYS (Py_TYPE (obj ));
@@ -7186,35 +7183,77 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
71867183 return 0 ;
71877184}
71887185
7189- PyObject *
7190- PyObject_GenericGetDict (PyObject * obj , void * context )
7186+ static inline PyObject *
7187+ ensure_managed_dict (PyObject * obj )
71917188{
7192- PyInterpreterState * interp = _PyInterpreterState_GET ();
7193- PyTypeObject * tp = Py_TYPE (obj );
7194- PyDictObject * dict ;
7195- if (_PyType_HasFeature (tp , Py_TPFLAGS_MANAGED_DICT )) {
7196- dict = _PyObject_GetManagedDict (obj );
7197- if (dict == NULL &&
7198- (tp -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) &&
7189+ PyDictObject * dict = _PyObject_GetManagedDict (obj );
7190+ if (dict == NULL ) {
7191+ PyTypeObject * tp = Py_TYPE (obj );
7192+ if ((tp -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) &&
71997193 FT_ATOMIC_LOAD_UINT8 (_PyObject_InlineValues (obj )-> valid )) {
72007194 dict = _PyObject_MaterializeManagedDict (obj );
72017195 }
7202- else if (dict == NULL ) {
7203- Py_BEGIN_CRITICAL_SECTION (obj );
7204-
7196+ else {
7197+ #ifdef Py_GIL_DISABLED
72057198 // Check again that we're not racing with someone else creating the dict
7199+ Py_BEGIN_CRITICAL_SECTION (obj );
72067200 dict = _PyObject_GetManagedDict (obj );
7207- if (dict == NULL ) {
7208- OBJECT_STAT_INC (dict_materialized_on_request );
7209- dictkeys_incref (CACHED_KEYS (tp ));
7210- dict = (PyDictObject * )new_dict_with_shared_keys (interp , CACHED_KEYS (tp ));
7211- FT_ATOMIC_STORE_PTR_RELEASE (_PyObject_ManagedDictPointer (obj )-> dict ,
7212- (PyDictObject * )dict );
7201+ if (dict != NULL ) {
7202+ goto done ;
72137203 }
7204+ #endif
7205+ dict = (PyDictObject * )new_dict_with_shared_keys (_PyInterpreterState_GET (),
7206+ CACHED_KEYS (tp ));
7207+ FT_ATOMIC_STORE_PTR_RELEASE (_PyObject_ManagedDictPointer (obj )-> dict ,
7208+ (PyDictObject * )dict );
72147209
7210+ #ifdef Py_GIL_DISABLED
7211+ done :
72157212 Py_END_CRITICAL_SECTION ();
7213+ #endif
72167214 }
7217- return Py_XNewRef ((PyObject * )dict );
7215+ }
7216+ return (PyObject * )dict ;
7217+ }
7218+
7219+ static inline PyObject *
7220+ ensure_nonmanaged_dict (PyObject * obj , PyObject * * dictptr )
7221+ {
7222+ PyDictKeysObject * cached ;
7223+
7224+ PyObject * dict = FT_ATOMIC_LOAD_PTR_ACQUIRE (* dictptr );
7225+ if (dict == NULL ) {
7226+ #ifdef Py_GIL_DISABLED
7227+ Py_BEGIN_CRITICAL_SECTION (obj );
7228+ dict = * dictptr ;
7229+ if (dict != NULL ) {
7230+ goto done ;
7231+ }
7232+ #endif
7233+ PyTypeObject * tp = Py_TYPE (obj );
7234+ if (_PyType_HasFeature (tp , Py_TPFLAGS_HEAPTYPE ) && (cached = CACHED_KEYS (tp ))) {
7235+ PyInterpreterState * interp = _PyInterpreterState_GET ();
7236+ assert (!_PyType_HasFeature (tp , Py_TPFLAGS_INLINE_VALUES ));
7237+ dict = new_dict_with_shared_keys (interp , cached );
7238+ }
7239+ else {
7240+ dict = PyDict_New ();
7241+ }
7242+ FT_ATOMIC_STORE_PTR_RELEASE (* dictptr , dict );
7243+ #ifdef Py_GIL_DISABLED
7244+ done :
7245+ Py_END_CRITICAL_SECTION ();
7246+ #endif
7247+ }
7248+ return dict ;
7249+ }
7250+
7251+ PyObject *
7252+ PyObject_GenericGetDict (PyObject * obj , void * context )
7253+ {
7254+ PyTypeObject * tp = Py_TYPE (obj );
7255+ if (_PyType_HasFeature (tp , Py_TPFLAGS_MANAGED_DICT )) {
7256+ return Py_XNewRef (ensure_managed_dict (obj ));
72187257 }
72197258 else {
72207259 PyObject * * dictptr = _PyObject_ComputedDictPointer (obj );
@@ -7223,65 +7262,28 @@ PyObject_GenericGetDict(PyObject *obj, void *context)
72237262 "This object has no __dict__" );
72247263 return NULL ;
72257264 }
7226- PyObject * dict = * dictptr ;
7227- if (dict == NULL ) {
7228- PyTypeObject * tp = Py_TYPE (obj );
7229- if (_PyType_HasFeature (tp , Py_TPFLAGS_HEAPTYPE ) && CACHED_KEYS (tp )) {
7230- dictkeys_incref (CACHED_KEYS (tp ));
7231- * dictptr = dict = new_dict_with_shared_keys (
7232- interp , CACHED_KEYS (tp ));
7233- }
7234- else {
7235- * dictptr = dict = PyDict_New ();
7236- }
7237- }
7238- return Py_XNewRef (dict );
7265+
7266+ return Py_XNewRef (ensure_nonmanaged_dict (obj , dictptr ));
72397267 }
72407268}
72417269
72427270int
7243- _PyObjectDict_SetItem (PyTypeObject * tp , PyObject * * dictptr ,
7271+ _PyObjectDict_SetItem (PyTypeObject * tp , PyObject * obj , PyObject * * dictptr ,
72447272 PyObject * key , PyObject * value )
72457273{
72467274 PyObject * dict ;
72477275 int res ;
7248- PyDictKeysObject * cached ;
7249- PyInterpreterState * interp = _PyInterpreterState_GET ();
72507276
72517277 assert (dictptr != NULL );
7252- if ((tp -> tp_flags & Py_TPFLAGS_HEAPTYPE ) && (cached = CACHED_KEYS (tp ))) {
7253- assert (dictptr != NULL );
7254- dict = * dictptr ;
7255- if (dict == NULL ) {
7256- assert (!_PyType_HasFeature (tp , Py_TPFLAGS_INLINE_VALUES ));
7257- dictkeys_incref (cached );
7258- dict = new_dict_with_shared_keys (interp , cached );
7259- if (dict == NULL )
7260- return -1 ;
7261- * dictptr = dict ;
7262- }
7263- if (value == NULL ) {
7264- res = PyDict_DelItem (dict , key );
7265- }
7266- else {
7267- res = PyDict_SetItem (dict , key , value );
7268- }
7269- } else {
7270- dict = * dictptr ;
7271- if (dict == NULL ) {
7272- dict = PyDict_New ();
7273- if (dict == NULL )
7274- return -1 ;
7275- * dictptr = dict ;
7276- }
7277- if (value == NULL ) {
7278- res = PyDict_DelItem (dict , key );
7279- } else {
7280- res = PyDict_SetItem (dict , key , value );
7281- }
7278+ dict = ensure_nonmanaged_dict (obj , dictptr );
7279+ if (dict == NULL ) {
7280+ return -1 ;
72827281 }
72837282
7283+ Py_BEGIN_CRITICAL_SECTION (dict );
7284+ res = _PyDict_SetItem_LockHeld ((PyDictObject * )dict , key , value );
72847285 ASSERT_CONSISTENT (dict );
7286+ Py_END_CRITICAL_SECTION ();
72857287 return res ;
72867288}
72877289
0 commit comments