@@ -6659,6 +6659,22 @@ _PyObject_MaterializeManagedDict(PyObject *obj)
6659
6659
return dict ;
6660
6660
}
6661
6661
6662
+ static int
6663
+ set_or_del_lock_held (PyDictObject * dict , PyObject * name , PyObject * value )
6664
+ {
6665
+ if (value == NULL ) {
6666
+ Py_hash_t hash ;
6667
+ if (!PyUnicode_CheckExact (name ) || (hash = unicode_get_hash (name )) == -1 ) {
6668
+ hash = PyObject_Hash (name );
6669
+ if (hash == -1 )
6670
+ return -1 ;
6671
+ }
6672
+ return delitem_knownhash_lock_held ((PyObject * )dict , name , hash );
6673
+ } else {
6674
+ return setitem_lock_held (dict , name , value );
6675
+ }
6676
+ }
6677
+
6662
6678
// Called with either the object's lock or the dict's lock held
6663
6679
// depending on whether or not a dict has been materialized for
6664
6680
// the object.
@@ -6713,33 +6729,22 @@ store_instance_attr_lock_held(PyObject *obj, PyDictValues *values,
6713
6729
if (ix == DKIX_EMPTY ) {
6714
6730
int res ;
6715
6731
if (dict == NULL ) {
6716
- dict = materialize_managed_dict_lock_held (obj );
6717
- if (dict == NULL ) {
6732
+ // Make the dict but don't publish it in the object
6733
+ // so that no one else will see it.
6734
+ dict = make_dict_from_instance_attributes (PyInterpreterState_Get (), keys , values );
6735
+ if (dict == NULL ||
6736
+ set_or_del_lock_held (dict , name , value ) < 0 ) {
6718
6737
return -1 ;
6719
6738
}
6720
6739
6721
- if (value == NULL ) {
6722
- res = PyDict_DelItem ((PyObject * )dict , name );
6723
- } else {
6724
- res = PyDict_SetItem ((PyObject * )dict , name , value );
6725
- }
6726
-
6727
- return res ;
6740
+ FT_ATOMIC_STORE_PTR_RELEASE (_PyObject_ManagedDictPointer (obj )-> dict ,
6741
+ (PyDictObject * )dict );
6742
+ return 0 ;
6728
6743
}
6729
6744
6730
6745
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (dict );
6731
6746
6732
- if (value == NULL ) {
6733
- Py_hash_t hash ;
6734
- if (!PyUnicode_CheckExact (name ) || (hash = unicode_get_hash (name )) == -1 ) {
6735
- hash = PyObject_Hash (name );
6736
- if (hash == -1 )
6737
- return -1 ;
6738
- }
6739
- res = delitem_knownhash_lock_held ((PyObject * )dict , name , hash );
6740
- } else {
6741
- res = setitem_lock_held (dict , name , value );
6742
- }
6747
+ res = set_or_del_lock_held (dict , name , value );
6743
6748
return res ;
6744
6749
}
6745
6750
@@ -6782,11 +6787,7 @@ store_instance_attr_dict(PyObject *obj, PyDictObject *dict, PyObject *name, PyOb
6782
6787
res = store_instance_attr_lock_held (obj , values , name , value );
6783
6788
}
6784
6789
else {
6785
- if (value == NULL ) {
6786
- res = PyDict_DelItem ((PyObject * )dict , name );
6787
- } else {
6788
- res = PyDict_SetItem ((PyObject * )dict , name , value );
6789
- }
6790
+ res = set_or_del_lock_held (dict , name , value );
6790
6791
}
6791
6792
Py_END_CRITICAL_SECTION ();
6792
6793
return res ;
@@ -6870,9 +6871,8 @@ _PyObject_ManagedDictValidityCheck(PyObject *obj)
6870
6871
}
6871
6872
#endif
6872
6873
6873
- // Attempts to get an instance attribute from the inline values. Returns 0 if
6874
- // the lookup from the inline values was successful or 1 if the inline values
6875
- // are no longer valid. No error is set in either case.
6874
+ // Attempts to get an instance attribute from the inline values. Returns true
6875
+ // if successful, or false if the caller needs to lookup in the dictionary.
6876
6876
bool
6877
6877
_PyObject_TryGetInstanceAttribute (PyObject * obj , PyObject * name , PyObject * * attr )
6878
6878
{
@@ -7048,27 +7048,22 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
7048
7048
7049
7049
Py_BEGIN_CRITICAL_SECTION2 (dict , obj );
7050
7050
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.
7051
+ #ifdef Py_DEBUG
7052
+ // If the dict in the object has been replaced between when we got
7053
+ // the dict and unlocked the objects then it's definitely no longer
7054
+ // inline and there's no need to detach it, we can just replace it.
7055
+ // The call to _PyDict_DetachFromObject will be a nop.
7055
7056
PyDictObject * cur_dict = _PyObject_ManagedDictPointer (obj )-> dict ;
7056
7057
assert (cur_dict == dict ||
7057
7058
(cur_dict -> ma_values != _PyObject_InlineValues (obj ) &&
7059
+ dict -> ma_values != _PyObject_InlineValues (obj ) &&
7058
7060
!_PyObject_InlineValues (obj )-> valid ));
7061
+ #endif
7059
7062
7060
- Py_XINCREF (new_dict );
7061
7063
FT_ATOMIC_STORE_PTR (_PyObject_ManagedDictPointer (obj )-> dict ,
7062
7064
(PyDictObject * )Py_XNewRef (new_dict ));
7063
7065
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 );
7071
- }
7066
+ _PyDict_DetachFromObject (dict , obj );
7072
7067
7073
7068
Py_END_CRITICAL_SECTION2 ();
7074
7069
0 commit comments