@@ -307,9 +307,13 @@ pub(super) struct ObjExt {
307307}
308308
309309impl ObjExt {
310- fn new ( dict : Option < PyDictRef > , member_count : usize ) -> Self {
310+ fn new ( dict : Option < PyDictRef > , member_count : usize , has_dict : bool ) -> Self {
311311 Self {
312- dict : dict. map ( InstanceDict :: new) ,
312+ dict : if has_dict {
313+ Some ( InstanceDict :: from_opt ( dict) )
314+ } else {
315+ None
316+ } ,
313317 slots : core:: iter:: repeat_with ( || PyRwLock :: new ( None ) )
314318 . take ( member_count)
315319 . collect_vec ( )
@@ -928,6 +932,13 @@ impl InstanceDict {
928932 }
929933 }
930934
935+ #[ inline]
936+ pub const fn from_opt ( d : Option < PyDictRef > ) -> Self {
937+ Self {
938+ d : PyRwLock :: new ( d) ,
939+ }
940+ }
941+
931942 #[ inline]
932943 pub fn get ( & self ) -> Option < PyDictRef > {
933944 self . d . read ( ) . clone ( )
@@ -950,11 +961,14 @@ impl InstanceDict {
950961 }
951962
952963 pub ( crate ) fn get_or_insert ( & self , vm : & VirtualMachine ) -> PyDictRef {
964+ if let Some ( existing) = self . d . read ( ) . as_ref ( ) {
965+ return existing. clone ( ) ;
966+ }
967+ let dict = vm. ctx . new_dict ( ) ;
953968 let mut d = self . d . write ( ) ;
954969 if let Some ( existing) = d. as_ref ( ) {
955970 existing. clone ( )
956971 } else {
957- let dict = vm. ctx . new_dict ( ) ;
958972 * d = Some ( dict. clone ( ) ) ;
959973 dict
960974 }
@@ -1071,7 +1085,8 @@ impl<T: PyPayload + core::fmt::Debug> PyInner<T> {
10711085 unsafe {
10721086 if let Some ( offset) = ext_start {
10731087 let ext_ptr = alloc_ptr. add ( offset) as * mut ObjExt ;
1074- ext_ptr. write ( ObjExt :: new ( dict, member_count) ) ;
1088+ let has_dict = typ. slots . flags . has_feature ( crate :: types:: PyTypeFlags :: HAS_DICT ) ;
1089+ ext_ptr. write ( ObjExt :: new ( dict, member_count, has_dict) ) ;
10751090 }
10761091
10771092 if let Some ( offset) = weakref_start {
@@ -1785,9 +1800,8 @@ impl PyObject {
17851800 let ext_ptr =
17861801 core:: ptr:: with_exposed_provenance_mut :: < ObjExt > ( self_addr. wrapping_sub ( offset) ) ;
17871802 let ext = unsafe { & mut * ext_ptr } ;
1788- if let Some ( old_dict) = ext. dict . take ( ) {
1789- // Get the dict ref before dropping InstanceDict
1790- if let Some ( dict_ref) = old_dict. into_inner ( ) {
1803+ if let Some ( instance_dict) = & ext. dict {
1804+ if let Some ( dict_ref) = instance_dict. replace ( None ) {
17911805 result. push ( dict_ref. into ( ) ) ;
17921806 }
17931807 }
0 commit comments