@@ -7163,6 +7163,17 @@ PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
7163
7163
return 0 ;
7164
7164
}
7165
7165
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
+
7166
7177
static void
7167
7178
set_dict_inline_values (PyObject * obj , PyDictObject * new_dict )
7168
7179
{
@@ -7173,12 +7184,7 @@ set_dict_inline_values(PyObject *obj, PyDictObject *new_dict)
7173
7184
Py_XINCREF (new_dict );
7174
7185
FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict , new_dict );
7175
7186
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 );
7182
7188
}
7183
7189
7184
7190
#ifdef Py_GIL_DISABLED
@@ -7256,8 +7262,8 @@ decref_maybe_delay(PyObject *obj, bool delay)
7256
7262
}
7257
7263
}
7258
7264
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 )
7261
7267
{
7262
7268
assert (Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_MANAGED_DICT );
7263
7269
#ifndef NDEBUG
@@ -7292,8 +7298,7 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
7292
7298
7293
7299
// Decref for the dictionary we incref'd in try_set_dict_inline_only_or_other_dict
7294
7300
// 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 );
7297
7302
if (err != 0 ) {
7298
7303
return err ;
7299
7304
}
@@ -7303,7 +7308,7 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
7303
7308
7304
7309
if (prev_dict != NULL ) {
7305
7310
// decref for the dictionary that we replaced
7306
- decref_maybe_delay ((PyObject * )prev_dict , ! clear );
7311
+ decref_maybe_delay ((PyObject * )prev_dict , true );
7307
7312
}
7308
7313
7309
7314
return 0 ;
@@ -7333,45 +7338,15 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
7333
7338
(PyDictObject * )Py_XNewRef (new_dict ));
7334
7339
7335
7340
Py_END_CRITICAL_SECTION ();
7336
- decref_maybe_delay ((PyObject * )dict , ! clear );
7341
+ decref_maybe_delay ((PyObject * )dict , true );
7337
7342
}
7338
7343
assert (_PyObject_InlineValuesConsistencyCheck (obj ));
7339
7344
return err ;
7340
7345
}
7341
7346
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 )
7373
7349
{
7374
- ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED (obj );
7375
7350
assert (_PyObject_ManagedDictPointer (obj )-> dict == mp );
7376
7351
assert (_PyObject_InlineValuesConsistencyCheck (obj ));
7377
7352
@@ -7401,6 +7376,60 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
7401
7376
return 0 ;
7402
7377
}
7403
7378
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
+
7404
7433
static inline PyObject *
7405
7434
ensure_managed_dict (PyObject * obj )
7406
7435
{
0 commit comments