@@ -7163,6 +7163,17 @@ PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
71637163 return 0 ;
71647164}
71657165
7166+ static void
7167+ clear_inline_values (PyDictValues * values )
7168+ {
7169+ if (values -> valid ) {
7170+ FT_ATOMIC_STORE_UINT8 (values -> valid , 0 );
7171+ for (Py_ssize_t i = 0 ; i < values -> capacity ; i ++ ) {
7172+ Py_CLEAR (values -> values [i ]);
7173+ }
7174+ }
7175+ }
7176+
71667177static void
71677178set_dict_inline_values (PyObject * obj , PyDictObject * new_dict )
71687179{
@@ -7173,12 +7184,7 @@ set_dict_inline_values(PyObject *obj, PyDictObject *new_dict)
71737184 Py_XINCREF (new_dict );
71747185 FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict , new_dict );
71757186
7176- if (values -> valid ) {
7177- FT_ATOMIC_STORE_UINT8 (values -> valid , 0 );
7178- for (Py_ssize_t i = 0 ; i < values -> capacity ; i ++ ) {
7179- Py_CLEAR (values -> values [i ]);
7180- }
7181- }
7187+ clear_inline_values (values );
71827188}
71837189
71847190#ifdef Py_GIL_DISABLED
@@ -7256,8 +7262,8 @@ decref_maybe_delay(PyObject *obj, bool delay)
72567262 }
72577263}
72587264
7259- static int
7260- set_or_clear_managed_dict (PyObject * obj , PyObject * new_dict , bool clear )
7265+ int
7266+ _PyObject_SetManagedDict (PyObject * obj , PyObject * new_dict )
72617267{
72627268 assert (Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_MANAGED_DICT );
72637269#ifndef NDEBUG
@@ -7292,8 +7298,7 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
72927298
72937299 // Decref for the dictionary we incref'd in try_set_dict_inline_only_or_other_dict
72947300 // while the object was locked
7295- decref_maybe_delay ((PyObject * )prev_dict ,
7296- !clear && prev_dict != cur_dict );
7301+ decref_maybe_delay ((PyObject * )prev_dict , prev_dict != cur_dict );
72977302 if (err != 0 ) {
72987303 return err ;
72997304 }
@@ -7303,7 +7308,7 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
73037308
73047309 if (prev_dict != NULL ) {
73057310 // decref for the dictionary that we replaced
7306- decref_maybe_delay ((PyObject * )prev_dict , ! clear );
7311+ decref_maybe_delay ((PyObject * )prev_dict , true );
73077312 }
73087313
73097314 return 0 ;
@@ -7333,45 +7338,15 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
73337338 (PyDictObject * )Py_XNewRef (new_dict ));
73347339
73357340 Py_END_CRITICAL_SECTION ();
7336- decref_maybe_delay ((PyObject * )dict , ! clear );
7341+ decref_maybe_delay ((PyObject * )dict , true );
73377342 }
73387343 assert (_PyObject_InlineValuesConsistencyCheck (obj ));
73397344 return err ;
73407345}
73417346
7342- int
7343- _PyObject_SetManagedDict (PyObject * obj , PyObject * new_dict )
7344- {
7345- return set_or_clear_managed_dict (obj , new_dict , false);
7346- }
7347-
7348- void
7349- PyObject_ClearManagedDict (PyObject * obj )
7350- {
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 */
7357- 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 ();
7368- }
7369- }
7370-
7371- int
7372- _PyDict_DetachFromObject (PyDictObject * mp , PyObject * obj )
7347+ static int
7348+ detach_dict_from_object (PyDictObject * mp , PyObject * obj )
73737349{
7374- ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED (obj );
73757350 assert (_PyObject_ManagedDictPointer (obj )-> dict == mp );
73767351 assert (_PyObject_InlineValuesConsistencyCheck (obj ));
73777352
@@ -7401,6 +7376,60 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
74017376 return 0 ;
74027377}
74037378
7379+
7380+ void
7381+ PyObject_ClearManagedDict (PyObject * obj )
7382+ {
7383+ // This is called when the object is being freed or cleared
7384+ // by the GC and therefore known to have no references.
7385+ if (Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_INLINE_VALUES ) {
7386+ PyDictObject * dict = _PyObject_GetManagedDict (obj );
7387+ if (dict == NULL ) {
7388+ // We have no materialized dictionary and inline values
7389+ // that just need to be cleared.
7390+ // No dict to clear, we're done
7391+ clear_inline_values (_PyObject_InlineValues (obj ));
7392+ return ;
7393+ }
7394+ else if (FT_ATOMIC_LOAD_PTR_RELAXED (dict -> ma_values ) ==
7395+ _PyObject_InlineValues (obj )) {
7396+ // We have a materialized object which points at the inline
7397+ // values. We need to materialize the keys. Nothing can modify
7398+ // this object, but we need to lock the dictionary.
7399+ int err ;
7400+ Py_BEGIN_CRITICAL_SECTION (dict );
7401+ err = detach_dict_from_object (dict , obj );
7402+ Py_END_CRITICAL_SECTION ();
7403+
7404+ if (err ) {
7405+ /* Must be out of memory */
7406+ assert (PyErr_Occurred () == PyExc_MemoryError );
7407+ PyErr_FormatUnraisable ("Exception ignored while "
7408+ "clearing an object managed dict" );
7409+ /* Clear the dict */
7410+ Py_BEGIN_CRITICAL_SECTION (dict );
7411+ PyInterpreterState * interp = _PyInterpreterState_GET ();
7412+ PyDictKeysObject * oldkeys = dict -> ma_keys ;
7413+ set_keys (dict , Py_EMPTY_KEYS );
7414+ dict -> ma_values = NULL ;
7415+ dictkeys_decref (interp , oldkeys , IS_DICT_SHARED (dict ));
7416+ STORE_USED (dict , 0 );
7417+ clear_inline_values (_PyObject_InlineValues (obj ));
7418+ Py_END_CRITICAL_SECTION ();
7419+ }
7420+ }
7421+ }
7422+ Py_CLEAR (_PyObject_ManagedDictPointer (obj )-> dict );
7423+ }
7424+
7425+ int
7426+ _PyDict_DetachFromObject (PyDictObject * mp , PyObject * obj )
7427+ {
7428+ ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED (obj );
7429+
7430+ return detach_dict_from_object (mp , obj );
7431+ }
7432+
74047433static inline PyObject *
74057434ensure_managed_dict (PyObject * obj )
74067435{
0 commit comments