@@ -7113,7 +7113,8 @@ try_set_dict_inline_only_or_other_dict(PyObject *obj, PyObject *new_dict, PyDict
7113
7113
(PyDictObject * )Py_XNewRef (new_dict ));
7114
7114
replaced = true;
7115
7115
goto exit_lock ;
7116
- } else {
711
8000
6
+ }
7117
+ else {
7117
7118
// We have inline values, we need to lock the dict and the object
7118
7119
// at the same time to safely dematerialize them. To do that while releasing
7119
7120
// the object lock we need a strong reference to the current dictionary.
@@ -7129,39 +7130,38 @@ try_set_dict_inline_only_or_other_dict(PyObject *obj, PyObject *new_dict, PyDict
7129
7130
// and replaced it with another dictionary though.
7130
7131
static int
7131
7132
replace_dict_probably_inline_materialized (PyObject * obj , PyDictObject * inline_dict ,
7132
- PyObject * new_dict , bool clear ,
7133
- PyDictObject * * replaced_dict )
7133
+ PyDictObject * cur_dict , PyObject * new_dict )
7134
7134
{
7135
- // But we could have had another thread race in after we released
7136
- // the object lock
7137
- int err = 0 ;
7138
- * replaced_dict = _PyObject_GetManagedDict (obj );
7139
- assert (FT_ATOMIC_LOAD_PTR_RELAXED (inline_dict -> ma_values ) == _PyObject_InlineValues (obj ));
7135
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (obj );
7136
+
7137
+ if (cur_dict == inline_dict ) {
7138
+ assert (FT_ATOMIC_LOAD_PTR_RELAXED (inline_dict -> ma_values ) == _PyObject_InlineValues (obj ));
7140
7139
7141
- if (* replaced_dict == inline_dict ) {
7142
- err = _PyDict_DetachFromObject (inline_dict , obj );
7140
+ int err = _PyDict_DetachFromObject (inline_dict , obj );
7143
7141
if (err != 0 ) {
7144
7142
assert (new_dict == NULL );
7145
7143
return err ;
7146
7144
}
7147
- // We incref'd the inline dict and the object owns a ref.
7148
- // Clear the object's reference, we'll clear the local
7149
- // reference after releasing the lock.
7150
- if (clear ) {
7151
- Py_XDECREF ((PyObject * )* replaced_dict );
7152
- } else {
7153
- _PyObject_XDecRefDelayed ((PyObject * )* replaced_dict );
7154
- }
7155
- * replaced_dict = NULL ;
7156
7145
}
7157
7146
7158
7147
FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict ,
7159
- (PyDictObject * )Py_XNewRef (new_dict ));
7160
- return err ;
7148
+ (PyDictObject * )Py_XNewRef (new_dict ));
7149
+ return 0 ;
7161
7150
}
7162
7151
7163
7152
#endif
7164
7153
7154
+ static void
7155
+ decref_maybe_delay (PyObject * obj , bool delay )
7156
+ {
7157
+ if (delay ) {
7158
+ _PyObject_XDecRefDelayed (obj );
7159
+ }
7160
+ else {
7161
+ Py_XDECREF (obj );
7162
+ }
7163
+ }
7164
+
7165
7165
static int
7166
7166
set_or_clear_managed_dict (PyObject * obj , PyObject * new_dict , bool clear )
7167
7167
{
@@ -7177,32 +7177,37 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
7177
7177
// values. We need to lock both the object and the dict at the
7178
7178
// same time to safely replace it. We can't merely lock the dictionary
7179
7179
// while the object is locked because it could suspend the object lock.
7180
- PyDictObject * replaced_dict ;
7180
+ PyDictObject * cur_dict ;
7181
7181
7182
7182
assert (prev_dict != NULL );
7183
7183
Py_BEGIN_CRITICAL_SECTION2 (obj , prev_dict );
7184
7184
7185
- err = replace_dict_probably_inline_materialized (obj , prev_dict , new_dict ,
7186
- clear , & replaced_dict );
7185
+ // We could have had another thread race in between the call to
7186
+ // try_set_dict_inline_only_or_other_dict where we locked the object
7187
+ // and when we unlocked and re-locked the dictionary.
7188
+ cur_dict = _PyObject_GetManagedDict (obj );
7189
+
7190
+ err = replace_dict_probably_inline_materialized (obj , prev_dict ,
7191
+ cur_dict , new_dict );
7187
7192
7188
7193
Py_END_CRITICAL_SECTION2 ();
7189
7194
7190
- Py_DECREF (prev_dict );
7195
+ // Decref for the dictionary we incref'd in try_set_dict_inline_only_or_other_dict
7196
+ // while the object was locked
7197
+ decref_maybe_delay ((PyObject * )prev_dict ,
7198
+ !clear && prev_dict != cur_dict );
7191
7199
if (err != 0 ) {
7192
7200
return err ;
7193
7201
}
7194
- prev_dict = replaced_dict ;
7202
+
7203
+ prev_dict = cur_dict ;
7195
7204
}
7196
7205
7197
7206
if (prev_dict != NULL ) {
7198
- // Readers from the old dictionary use a borrowed reference. We need
7199
- // to set the decref the dict at the next safe point.
7200
- if (clear ) {
7201
- Py_XDECREF ((PyObject * )prev_dict );
7202
- } else {
7203
- _PyObject_XDecRefDelayed ((PyObject * )prev_dict );
7204
- }
7207
+ // decref for the dictionary that we replaced
7208
+ decref_maybe_delay ((PyObject * )prev_dict , !clear );
7205
7209
}
7210
+
7206
7211
return 0 ;
7207
7212
#else
7208
7213
PyDictObject * dict = _PyObject_GetManagedDict (obj );
@@ -7230,11 +7235,7 @@ set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear)
7230
7235
(PyDictObject * )Py_XNewRef (new_dict ));
7231
7236
7232
7237
Py_END_CRITICAL_SECTION ();
7233
- if (clear ) {
7234
- Py_XDECREF ((PyObject * )dict );
7235
- } else {
7236
- _PyObject_XDecRefDelayed ((PyObject * )dict );
7237
- }
7238
+ decref_maybe_delay ((PyObject * )dict , !clear );
7238
7239
}
7239
7240
assert (_PyObject_InlineValuesConsistencyCheck (obj ));
7240
7241
return err ;
0 commit comments