@@ -7256,8 +7256,8 @@ decref_maybe_delay(PyObject *obj, bool delay)
72567256 }
72577257}
72587258
7259- static int
7260- set_or_clear_managed_dict (PyObject * obj , PyObject * new_dict , bool clear )
7259+ int
7260+ _PyObject_SetManagedDict (PyObject * obj , PyObject * new_dict )
72617261{
72627262 assert (Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_MANAGED_DICT );
72637263#ifndef NDEBUG
@@ -7292,8 +7292,7 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
72927292
72937293 // Decref for the dictionary we incref'd in try_set_dict_inline_only_or_other_dict
72947294 // while the object was locked
7295- decref_maybe_delay ((PyObject * )prev_dict ,
7296- !clear && prev_dict != cur_dict );
7295+ decref_maybe_delay ((PyObject * )prev_dict , prev_dict != cur_dict );
72977296 if (err != 0 ) {
72987297 return err ;
72997298 }
@@ -7303,7 +7302,7 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
73037302
73047303 if (prev_dict != NULL ) {
73057304 // decref for the dictionary that we replaced
7306- decref_maybe_delay ((PyObject * )prev_dict , ! clear );
7305+ decref_maybe_delay ((PyObject * )prev_dict , true );
73077306 }
73087307
73097308 return 0 ;
@@ -7333,45 +7332,68 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
73337332 (PyDictObject * )Py_XNewRef (new_dict ));
73347333
73357334 Py_END_CRITICAL_SECTION ();
7336- decref_maybe_delay ((PyObject * )dict , ! clear );
7335+ decref_maybe_delay ((PyObject * )dict , true );
73377336 }
73387337 assert (_PyObject_InlineValuesConsistencyCheck (obj ));
73397338 return err ;
73407339}
73417340
7342- int
7343- _PyObject_SetManagedDict (PyObject * obj , PyObject * new_dict )
7344- {
7345- return set_or_clear_managed_dict (obj , new_dict , false);
7346- }
7347-
73487341void
73497342PyObject_ClearManagedDict (PyObject * obj )
73507343{
7351- if (set_or_clear_managed_dict (obj , NULL , true) < 0 ) {
7352- /* Must be out of memory */
7353- assert (PyErr_Occurred () == PyExc_MemoryError );
7354- PyErr_FormatUnraisable ("Exception ignored while "
7355- "clearing an object managed dict" );
7356- /* Clear the dict */
7344+ // This is called when the object is being freed and therefore
7345+ // has no other references or during GC when the world is stopped
7346+ // so we don't need any locking.
7347+ if (Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_INLINE_VALUES ) {
73577348 PyDictObject * dict = _PyObject_GetManagedDict (obj );
7358- Py_BEGIN_CRITICAL_SECTION2 (dict , obj );
7359- dict = _PyObject_ManagedDictPointer (obj )-> dict ;
7360- PyInterpreterState * interp = _PyInterpreterState_GET ();
7361- PyDictKeysObject * oldkeys = dict -> ma_keys ;
7362- set_keys (dict , Py_EMPTY_KEYS );
7363- dict -> ma_values = NULL ;
7364- dictkeys_decref (interp , oldkeys , IS_DICT_SHARED (dict ));
7365- STORE_USED (dict , 0 );
7366- set_dict_inline_values (obj , NULL );
7367- Py_END_CRITICAL_SECTION2 ();
7349+ if (dict == NULL ) {
7350+ // We have no materialized dictionary and inline values
7351+ // that just need to be cleared.
7352+ PyDictValues * values = _PyObject_InlineValues (obj );
7353+ if (values -> valid ) {
7354+ values -> valid = 0 ;
7355+ for (Py_ssize_t i = 0 ; i < values -> capacity ; i ++ ) {
7356+ Py_CLEAR (values -> values [i ]);
7357+ }
7358+ }
7359+ // No dict to clear, we're done
7360+ return ;
7361+ } else if (FT_ATOMIC_LOAD_PTR_RELAXED (dict -> ma_values ) ==
7362+ _PyObject_InlineValues (obj )) {
7363+ // We have a materialized object which points at the inline
7364+ // values. We need to materialize the keys. Nothing can modify
7365+ // this object, but we need to lock the dictionary.
7366+ int err ;
7367+ Py_BEGIN_CRITICAL_SECTION (dict );
7368+ err = _PyDict_DetachFromObject (dict , obj );
7369+ Py_END_CRITICAL_SECTION ();
7370+
7371+ if (err ) {
7372+ /* Must be out of memory */
7373+ assert (PyErr_Occurred () == PyExc_MemoryError );
7374+ PyErr_FormatUnraisable ("Exception ignored while "
7375+ "clearing an object managed dict" );
7376+ /* Clear the dict */
7377+ Py_BEGIN_CRITICAL_SECTION2 (dict , obj );
7378+ PyInterpreterState * interp = _PyInterpreterState_GET ();
7379+ PyDictKeysObject * oldkeys = dict -> ma_keys ;
7380+ set_keys (dict , Py_EMPTY_KEYS );
7381+ dict -> ma_values = NULL ;
7382+ dictkeys_decref (interp , oldkeys , IS_DICT_SHARED (dict ));
7383+ STORE_USED (dict , 0 );
7384+ set_dict_inline_values (obj , NULL );
7385+ Py_END_CRITICAL_SECTION2 ();
7386+ }
7387+ }
7388+ // Else we have a materialized dict which doesn't point at the inline
7389+ // values, we can just clear it.
73687390 }
7391+ Py_CLEAR (_PyObject_ManagedDictPointer (obj )-> dict );
73697392}
73707393
73717394int
73727395_PyDict_DetachFromObject (PyDictObject * mp , PyObject * obj )
73737396{
7374- ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED (obj );
73757397 assert (_PyObject_ManagedDictPointer (obj )-> dict == mp );
73767398 assert (_PyObject_InlineValuesConsistencyCheck (obj ));
73777399
0 commit comments