@@ -18,7 +18,7 @@ use crate::{
1818 common:: {
1919 ascii,
2020 borrow:: BorrowedValue ,
21- lock:: { PyMutex , PyRwLock , PyRwLockReadGuard } ,
21+ lock:: { PyRwLock , PyRwLockReadGuard } ,
2222 } ,
2323 function:: { FuncArgs , KwArgs , OptionalArg , PyMethodDef , PySetterValue } ,
2424 object:: { Traverse , TraverseFn } ,
@@ -276,8 +276,6 @@ pub struct TypeSpecializationCache {
276276 pub init : PyAtomicRef < Option < PyFunction > > ,
277277 pub getitem : PyAtomicRef < Option < PyFunction > > ,
278278 pub getitem_version : AtomicU32 ,
279- // Serialize cache writes/invalidation similar to CPython's BEGIN_TYPE_LOCK.
280- write_lock : PyMutex < ( ) > ,
281279 retired : PyRwLock < Vec < PyObjectRef > > ,
282280}
283281
@@ -287,7 +285,6 @@ impl TypeSpecializationCache {
287285 init : PyAtomicRef :: from ( None :: < PyRef < PyFunction > > ) ,
288286 getitem : PyAtomicRef :: from ( None :: < PyRef < PyFunction > > ) ,
289287 getitem_version : AtomicU32 :: new ( 0 ) ,
290- write_lock : PyMutex :: new ( ( ) ) ,
291288 retired : PyRwLock :: new ( Vec :: new ( ) ) ,
292289 }
293290 }
@@ -328,9 +325,6 @@ impl TypeSpecializationCache {
328325
329326 #[ inline]
330327 fn invalidate_for_type_modified ( & self ) {
331- let _guard = self . write_lock . lock ( ) ;
332- // _spec_cache contract: type modification invalidates all cached
333- // specialization functions.
334328 self . swap_init ( None , None ) ;
335329 self . swap_getitem ( None , None ) ;
336330 }
@@ -350,7 +344,6 @@ impl TypeSpecializationCache {
350344 }
351345
352346 fn clear_into ( & self , out : & mut Vec < PyObjectRef > ) {
353- let _guard = self . write_lock . lock ( ) ;
354347 let old_init = unsafe { self . init . swap ( None ) } ;
355348 if let Some ( old_init) = old_init {
356349 out. push ( old_init. into ( ) ) ;
@@ -1009,7 +1002,6 @@ impl PyType {
10091002 if self . tp_version_tag . load ( Ordering :: Acquire ) != tp_version {
10101003 return false ;
10111004 }
1012- let _guard = ext. specialization_cache . write_lock . lock ( ) ;
10131005 if self . tp_version_tag . load ( Ordering :: Acquire ) != tp_version {
10141006 return false ;
10151007 }
@@ -1050,7 +1042,6 @@ impl PyType {
10501042 return false ;
10511043 }
10521044 Self :: with_type_lock ( vm, || {
1053- let _guard = ext. specialization_cache . write_lock . lock ( ) ;
10541045 if self . tp_version_tag . load ( Ordering :: Acquire ) != tp_version {
10551046 return false ;
10561047 }
@@ -1569,18 +1560,19 @@ impl PyType {
15691560 drop ( attrs) ;
15701561
15711562 let none = vm. ctx . none ( ) ;
1572- Ok ( Self :: with_type_lock ( vm, || {
1563+ let ( result , _prev ) = Self :: with_type_lock ( vm, || {
15731564 let mut attrs = self . attributes . write ( ) ;
15741565 if let Some ( annotate) = attrs. get ( annotate_key) . cloned ( ) {
1575- return annotate;
1566+ return ( annotate, None ) ;
15761567 }
15771568 if let Some ( annotate) = attrs. get ( annotate_func_key) . cloned ( ) {
1578- return annotate;
1569+ return ( annotate, None ) ;
15791570 }
15801571 self . modified_inner ( ) ;
1581- attrs. insert ( annotate_func_key, none. clone ( ) ) ;
1582- none
1583- } ) )
1572+ let prev = attrs. insert ( annotate_func_key, none. clone ( ) ) ;
1573+ ( none, prev)
1574+ } ) ;
1575+ Ok ( result)
15841576 }
15851577
15861578 #[ pygetset( setter) ]
@@ -1603,13 +1595,16 @@ impl PyType {
16031595 return Err ( vm. new_type_error ( "__annotate__ must be callable or None" ) ) ;
16041596 }
16051597
1606- Self :: with_type_lock ( vm, || {
1598+ let _prev_values = Self :: with_type_lock ( vm, || {
16071599 self . modified_inner ( ) ;
16081600 let mut attrs = self . attributes . write ( ) ;
1609- if !vm. is_none ( & value) {
1610- attrs. swap_remove ( identifier ! ( vm, __annotations_cache__) ) ;
1611- }
1612- attrs. insert ( identifier ! ( vm, __annotate_func__) , value) ;
1601+ let removed = if !vm. is_none ( & value) {
1602+ attrs. swap_remove ( identifier ! ( vm, __annotations_cache__) )
1603+ } else {
1604+ None
1605+ } ;
1606+ let prev = attrs. insert ( identifier ! ( vm, __annotate_func__) , value) ;
1607+ ( removed, prev)
16131608 } ) ;
16141609
16151610 Ok ( ( ) )
@@ -1672,20 +1667,21 @@ impl PyType {
16721667 vm. ctx . new_dict ( ) . into ( )
16731668 } ;
16741669
1675- Ok ( Self :: with_type_lock ( vm, || {
1670+ let ( result , _prev ) = Self :: with_type_lock ( vm, || {
16761671 let mut attrs = self . attributes . write ( ) ;
16771672 if let Some ( existing) = attrs. get ( annotations_key) . cloned ( )
16781673 && !existing. class ( ) . is ( vm. ctx . types . getset_type )
16791674 {
1680- return existing;
1675+ return ( existing, None ) ;
16811676 }
16821677 if let Some ( existing) = attrs. get ( annotations_cache_key) . cloned ( ) {
1683- return existing;
1678+ return ( existing, None ) ;
16841679 }
16851680 self . modified_inner ( ) ;
1686- attrs. insert ( annotations_cache_key, annotations. clone ( ) ) ;
1687- annotations
1688- } ) )
1681+ let prev = attrs. insert ( annotations_cache_key, annotations. clone ( ) ) ;
1682+ ( annotations, prev)
1683+ } ) ;
1684+ Ok ( result)
16891685 }
16901686
16911687 #[ pygetset( setter) ]
@@ -1701,44 +1697,42 @@ impl PyType {
17011697 ) ) ) ;
17021698 }
17031699
1704- Self :: with_type_lock ( vm, || {
1700+ let _prev_values = Self :: with_type_lock ( vm, || {
17051701 self . modified_inner ( ) ;
17061702 let mut attrs = self . attributes . write ( ) ;
17071703 let has_annotations = attrs. contains_key ( identifier ! ( vm, __annotations__) ) ;
17081704
1705+ let mut prev = Vec :: new ( ) ;
17091706 match value {
17101707 crate :: function:: PySetterValue :: Assign ( value) => {
17111708 let key = if has_annotations {
17121709 identifier ! ( vm, __annotations__)
17131710 } else {
17141711 identifier ! ( vm, __annotations_cache__)
17151712 } ;
1716- attrs. insert ( key, value) ;
1713+ prev . extend ( attrs. insert ( key, value) ) ;
17171714 if has_annotations {
1718- attrs. swap_remove ( identifier ! ( vm, __annotations_cache__) ) ;
1715+ prev . extend ( attrs. swap_remove ( identifier ! ( vm, __annotations_cache__) ) ) ;
17191716 }
17201717 }
17211718 crate :: function:: PySetterValue :: Delete => {
17221719 let removed = if has_annotations {
1723- attrs
1724- . swap_remove ( identifier ! ( vm, __annotations__) )
1725- . is_some ( )
1720+ attrs. swap_remove ( identifier ! ( vm, __annotations__) )
17261721 } else {
1727- attrs
1728- . swap_remove ( identifier ! ( vm, __annotations_cache__) )
1729- . is_some ( )
1722+ attrs. swap_remove ( identifier ! ( vm, __annotations_cache__) )
17301723 } ;
1731- if ! removed {
1724+ if removed. is_none ( ) {
17321725 return Err ( vm. new_attribute_error ( "__annotations__" ) ) ;
17331726 }
1727+ prev. extend ( removed) ;
17341728 if has_annotations {
1735- attrs. swap_remove ( identifier ! ( vm, __annotations_cache__) ) ;
1729+ prev . extend ( attrs. swap_remove ( identifier ! ( vm, __annotations_cache__) ) ) ;
17361730 }
17371731 }
17381732 }
1739- attrs. swap_remove ( identifier ! ( vm, __annotate_func__) ) ;
1740- attrs. swap_remove ( identifier ! ( vm, __annotate__) ) ;
1741- Ok ( ( ) )
1733+ prev . extend ( attrs. swap_remove ( identifier ! ( vm, __annotate_func__) ) ) ;
1734+ prev . extend ( attrs. swap_remove ( identifier ! ( vm, __annotate__) ) ) ;
1735+ Ok ( prev )
17421736 } ) ?;
17431737
17441738 Ok ( ( ) )
@@ -1772,11 +1766,12 @@ impl PyType {
17721766 #[ pygetset( setter) ]
17731767 fn set___module__ ( & self , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
17741768 self . check_set_special_type_attr ( identifier ! ( vm, __module__) , vm) ?;
1775- Self :: with_type_lock ( vm, || {
1769+ let _prev_values = Self :: with_type_lock ( vm, || {
17761770 self . modified_inner ( ) ;
1777- self . attributes
1778- . write ( )
1779- . insert ( identifier ! ( vm, __module__) , value) ;
1771+ let mut attributes = self . attributes . write ( ) ;
1772+ let removed = attributes. swap_remove ( identifier ! ( vm, __firstlineno__) ) ;
1773+ let prev = attributes. insert ( identifier ! ( vm, __module__) , value) ;
1774+ ( removed, prev)
17801775 } ) ;
17811776 Ok ( ( ) )
17821777 }
@@ -1903,9 +1898,9 @@ impl PyType {
19031898 match value {
19041899 PySetterValue :: Assign ( val) => {
19051900 self . check_set_special_type_attr ( key, vm) ?;
1906- Self :: with_type_lock ( vm, || {
1901+ let _prev_value = Self :: with_type_lock ( vm, || {
19071902 self . modified_inner ( ) ;
1908- self . attributes . write ( ) . insert ( key, val. into ( ) ) ;
1903+ self . attributes . write ( ) . insert ( key, val. into ( ) )
19091904 } ) ;
19101905 }
19111906 PySetterValue :: Delete => {
@@ -1915,9 +1910,9 @@ impl PyType {
19151910 self . slot_name( )
19161911 ) ) ) ;
19171912 }
1918- Self :: with_type_lock ( vm, || {
1913+ let _prev_value = Self :: with_type_lock ( vm, || {
19191914 self . modified_inner ( ) ;
1920- self . attributes . write ( ) . shift_remove ( & key) ;
1915+ self . attributes . write ( ) . shift_remove ( & key)
19211916 } ) ;
19221917 }
19231918 }
@@ -2542,11 +2537,11 @@ impl Py<PyType> {
25422537 // Check if we can set this special type attribute
25432538 self . check_set_special_type_attr ( identifier ! ( vm, __doc__) , vm) ?;
25442539
2545- PyType :: with_type_lock ( vm, || {
2540+ let _prev_value = PyType :: with_type_lock ( vm, || {
25462541 self . modified_inner ( ) ;
25472542 self . attributes
25482543 . write ( )
2549- . insert ( identifier ! ( vm, __doc__) , value) ;
2544+ . insert ( identifier ! ( vm, __doc__) , value)
25502545 } ) ;
25512546
25522547 Ok ( ( ) )
@@ -2609,14 +2604,17 @@ impl SetAttr for PyType {
26092604 }
26102605 let assign = value. is_assign ( ) ;
26112606
2612- Self :: with_type_lock ( vm, || {
2607+ // Drop old value OUTSIDE the type lock to avoid deadlock:
2608+ // dropping may trigger weakref callbacks → method calls →
2609+ // LOAD_ATTR specialization → version_for_specialization → type lock.
2610+ let _prev_value = Self :: with_type_lock ( vm, || {
26132611 // Invalidate inline caches before modifying attributes.
26142612 // This ensures other threads see the version invalidation before
26152613 // any attribute changes, preventing use-after-free of cached descriptors.
26162614 zelf. modified_inner ( ) ;
26172615
26182616 if let PySetterValue :: Assign ( value) = value {
2619- zelf. attributes . write ( ) . insert ( attr_name, value) ;
2617+ Ok ( zelf. attributes . write ( ) . insert ( attr_name, value) )
26202618 } else {
26212619 let prev_value = zelf. attributes . write ( ) . shift_remove ( attr_name) ; // TODO: swap_remove applicable?
26222620 if prev_value. is_none ( ) {
@@ -2626,8 +2624,8 @@ impl SetAttr for PyType {
26262624 attr_name,
26272625 ) ) ) ;
26282626 }
2627+ Ok ( prev_value)
26292628 }
2630- Ok ( ( ) )
26312629 } ) ?;
26322630
26332631 if attr_name. as_wtf8 ( ) . starts_with ( "__" ) && attr_name. as_wtf8 ( ) . ends_with ( "__" ) {
0 commit comments