@@ -6796,8 +6796,15 @@ int
6796
6796
_PyObject_StoreInstanceAttribute (PyObject * obj , PyObject * name , PyObject * value )
6797
6797
{
6798
6798
PyDictValues * values = _PyObject_InlineValues (obj );
6799
- if (!FT_ATOMIC_LOAD_UINT8_RELAXED (values -> valid )) {
6800
- return store_instance_attr_dict (obj , _PyObject_GetManagedDict (obj ), name , value );
6799
+ if (!FT_ATOMIC_LOAD_UINT8 (values -> valid )) {
6800
+ PyDictObject * dict = _PyObject_GetManagedDict (obj );
6801
+ if (dict == NULL ) {
6802
+ dict = (PyDictObject * )PyObject_GenericGetDict (obj , NULL );
6803
+ if (dict == NULL ) {
6804
+ return -1 ;
6805
+ }
6806
+ }
6807
+ return store_instance_attr_dict (obj , dict , name , value );
6801
6808
}
6802
6809
6803
6810
#ifdef Py_GIL_DISABLED
@@ -6871,7 +6878,7 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
6871
6878
{
6872
6879
assert (PyUnicode_CheckExact (name ));
6873
6880
PyDictValues * values = _PyObject_InlineValues (obj );
6874
- if (!FT_ATOMIC_LOAD_UINT8_RELAXED (values -> valid )) {
6881
+ if (!FT_ATOMIC_LOAD_UINT8 (values -> valid )) {
6875
6882
return false;
6876
6883
}
6877
6884
@@ -6920,8 +6927,7 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
6920
6927
bool success ;
6921
6928
Py_BEGIN_CRITICAL_SECTION (dict );
6922
6929
6923
- if (dict -> ma_values == values &&
6924
- FT_ATOMIC_LOAD_UINT8_RELAXED (values -> valid )) {
6930
+ if (dict -> ma_values == values && FT_ATOMIC_LOAD_UINT8 (values -> valid )) {
6925
6931
value = _Py_atomic_load_ptr_relaxed (& values -> values [ix ]);
6926
6932
* attr = Py_XNewRef (value );
6927
6933
success = true;
@@ -6950,7 +6956,7 @@ _PyObject_IsInstanceDictEmpty(PyObject *obj)
6950
6956
PyDictObject * dict ;
6951
6957
if (tp -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) {
6952
6958
PyDictValues * values = _PyObject_InlineValues (obj );
6953
- if (FT_ATOMIC_LOAD_UINT8_RELAXED (values -> valid )) {
6959
+ if (FT_ATOMIC_LOAD_UINT8 (values -> valid )) {
6954
6960
PyDictKeysObject * keys = CACHED_KEYS (tp );
6955
6961
for (Py_ssize_t i = 0 ; i < keys -> dk_nentries ; i ++ ) {
6956
6962
if (FT_ATOMIC_LOAD_PTR_RELAXED (values -> values [i ]) != NULL ) {
@@ -6994,32 +7000,22 @@ PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
6994
7000
return 0 ;
6995
7001
}
6996
7002
6997
- static bool
6998
- set_dict_inline_values (PyObject * obj , PyObject * new_dict )
7003
+ static void
7004
+ set_dict_inline_values (PyObject * obj , PyDictObject * new_dict )
6999
7005
{
7000
7006
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (obj );
7001
7007
7002
7008
PyDictValues * values = _PyObject_InlineValues (obj );
7003
7009
7004
- #ifdef Py_GIL_DISABLED
7005
- PyDictObject * dict = _PyObject_ManagedDictPointer (obj )-> dict ;
7006
- if (dict != NULL ) {
7007
- // We lost a race with materialization of the dict
7008
- return false;
7009
- }
7010
- #endif
7011
-
7012
7010
Py_XINCREF (new_dict );
7013
- _PyObject_ManagedDictPointer (obj )-> dict = ( PyDictObject * ) new_dict ;
7011
+ FT_ATOMIC_STORE_PTR ( _PyObject_ManagedDictPointer (obj )-> dict , new_dict ) ;
7014
7012
7015
7013
if (values -> valid ) {
7016
- FT_ATOMIC_STORE_UINT8_RELAXED (values -> valid , 0 );
7014
+ FT_ATOMIC_STORE_UINT8 (values -> valid , 0 );
7017
7015
for (Py_ssize_t i = 0 ; i < values -> capacity ; i ++ ) {
7018
7016
Py_CLEAR (values -> values [i ]);
7019
7017
}
7020
7018
}
7021
-
7022
- return true;
7023
7019
}
7024
7020
7025
7021
void
@@ -7030,47 +7026,67 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
7030
7026
PyTypeObject * tp = Py_TYPE (obj );
7031
7027
if (tp -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) {
7032
7028
PyDictObject * dict = _PyObject_GetManagedDict (obj );
7033
- if (dict ) {
7029
+ if (dict == NULL ) {
7034
7030
#ifdef Py_GIL_DISABLED
7035
- clear_dict :
7036
- #endif
7037
- Py_BEGIN_CRITICAL_SECTION2 (dict , obj );
7038
-
7039
- _PyDict_DetachFromObject (dict , obj );
7031
+ Py_BEGIN_CRITICAL_SECTION (obj );
7040
7032
7041
- Py_XINCREF (new_dict );
7042
- _PyObject_ManagedDictPointer (obj )-> dict = (PyDictObject * )new_dict ;
7033
+ dict = _PyObject_ManagedDictPointer (obj )-> dict ;
7034
+ if (dict == NULL ) {
7035
+ set_dict_inline_values (obj , (PyDictObject * )new_dict );
7036
+ }
7043
7037
7044
- Py_END_CRITICAL_SECTION2 ();
7038
+ Py_END_CRITICAL_SECTION ();
7045
7039
7046
- Py_DECREF (dict );
7040
+ if (dict == NULL ) {
7041
+ return ;
7042
+ }
7043
+ #else
7044
+ set_dict_inline_values (obj , (PyDictObject * )new_dict );
7045
+ return ;
7046
+ #endif
7047
7047
}
7048
- else {
7049
- bool success ;
7050
- Py_BEGIN_CRITICAL_SECTION (obj );
7051
7048
7052
- success = set_dict_inline_values ( obj , new_dict );
7049
+ Py_BEGIN_CRITICAL_SECTION2 ( dict , obj );
7053
7050
7054
- Py_END_CRITICAL_SECTION ();
7051
+ // If the dict in the object has been replaced between when we
7052
+ // got the dict and unlocked the objects then it's
7053
+ // definitely no longer inline and there's no need to detach
7054
+ // it, we can just replace it.
7055
+ PyDictObject * cur_dict = _PyObject_ManagedDictPointer (obj )-> dict ;
7056
+ assert (cur_dict == dict ||
7057
+ (cur_dict -> ma_values != _PyObject_InlineValues (obj ) &&
7058
+ !_PyObject_InlineValues (obj )-> valid ));
7055
7059
7056
- (void )success ; // suppress warning when GIL isn't disabled
7060
+ Py_XINCREF (new_dict );
7061
+ FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict ,
7062
+ (PyDictObject * )Py_XNewRef (new_dict ));
7057
7063
7058
- #ifdef Py_GIL_DISABLED
7059
- if (! success ) {
7060
- dict = _PyObject_ManagedDictPointer ( obj ) -> dict ;
7061
- assert ( dict != NULL );
7062
- goto clear_dict ;
7063
- }
7064
- #endif
7064
+ // If we got a replacement dict after locking the object and the dict
7065
+ // then the old dict had to already have been detached.
7066
+ assert ( cur_dict == dict ||
7067
+ dict -> ma_values != _PyObject_InlineValues ( obj ) );
7068
+
7069
+ if ( cur_dict == dict ) {
7070
+ _PyDict_DetachFromObject ( dict , obj );
7065
7071
}
7072
+
7073
+ Py_END_CRITICAL_SECTION2 ();
7074
+
7075
+ Py_DECREF (dict );
7066
7076
}
7067
7077
else {
7078
+ PyDictObject * dict ;
7079
+
7068
7080
Py_BEGIN_CRITICAL_SECTION (obj );
7069
7081
7070
- Py_XSETREF (_PyObject_ManagedDictPointer (obj )-> dict ,
7071
- (PyDictObject * )Py_XNewRef (new_dict ));
7082
+ dict = _PyObject_ManagedDictPointer (obj )-> dict ;
7083
+
7084
+ FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict ,
7085
+ (PyDictObject * )Py_XNewRef (new_dict ));
7072
7086
7073
7087
Py_END_CRITICAL_SECTION ();
7088
+
7089
+ Py_XDECREF (dict );
7074
7090
}
7075
7091
assert (_PyObject_InlineValuesConsistencyCheck (obj ));
7076
7092
}
@@ -7085,9 +7101,8 @@ int
7085
7101
_PyDict_DetachFromObject (PyDictObject * mp , PyObject * obj )
7086
7102
{
7087
7103
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (mp );
7104
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (obj );
7088
7105
7089
- assert (_PyObject_ManagedDictPointer (obj )-> dict == mp );
7090
- assert (_PyObject_InlineValuesConsistencyCheck (obj ));
7091
7106
if (mp -> ma_values == NULL || mp -> ma_values != _PyObject_InlineValues (obj )) {
7092
7107
return 0 ;
7093
7108
}
@@ -7096,12 +7111,13 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
7096
7111
assert (Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_INLINE_VALUES );
7097
7112
7098
7113
mp -> ma_values = copy_values (mp -> ma_values );
7099
- _PyObject_InlineValues (obj )-> valid = 0 ;
7100
7114
7101
7115
if (mp -> ma_values == NULL ) {
7102
7116
return -1 ;
7103
7117
}
7104
7118
7119
+ FT_ATOMIC_STORE_UINT8 (_PyObject_InlineValues (obj )-> valid , 0 );
7120
+
7105
7121
assert (_PyObject_InlineValuesConsistencyCheck (obj ));
7106
7122
ASSERT_CONSISTENT (mp );
7107
7123
return 0 ;
@@ -7117,7 +7133,7 @@ PyObject_GenericGetDict(PyObject *obj, void *context)
7117
7133
dict = _PyObject_GetManagedDict (obj );
7118
7134
if (dict == NULL &&
7119
7135
(tp -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) &&
7120
- FT_ATOMIC_LOAD_UINT8_RELAXED (_PyObject_InlineValues (obj )-> valid )) {
7136
+ FT_ATOMIC_LOAD_UINT8 (_PyObject_InlineValues (obj )-> valid )) {
7121
7137
dict = _PyObject_MaterializeManagedDict (obj );
7122
7138
}
7123
7139
else if (dict == NULL ) {
0 commit comments