@@ -239,8 +239,6 @@ bitflags::bitflags! {
239239 const SHARED_INLINE = 1 << 5 ;
240240 /// Use deferred reference counting
241241 const DEFERRED = 1 << 6 ;
242- /// Object has ObjExt prefix (dict, weak_list, slots)
243- const HAS_EXT = 1 << 7 ;
244242 }
245243}
246244
@@ -285,7 +283,8 @@ impl fmt::Debug for ObjExt {
285283const EXT_OFFSET : usize = core:: mem:: size_of :: < ObjExt > ( ) ;
286284// Guarantee: ObjExt size is a multiple of its alignment, and its alignment
287285// is >= any PyInner alignment, so Layout::extend produces no inter-padding.
288- const _: ( ) = assert ! ( core:: mem:: size_of:: <ObjExt >( ) . is_multiple_of( core:: mem:: align_of:: <ObjExt >( ) ) ) ;
286+ const _: ( ) =
287+ assert ! ( core:: mem:: size_of:: <ObjExt >( ) . is_multiple_of( core:: mem:: align_of:: <ObjExt >( ) ) ) ;
289288const _: ( ) = assert ! ( core:: mem:: align_of:: <ObjExt >( ) >= core:: mem:: align_of:: <PyInner <( ) >>( ) ) ;
290289
291290/// This is an actual python object. It consists of a `typ` which is the
@@ -305,16 +304,34 @@ pub(super) struct PyInner<T> {
305304pub ( crate ) const SIZEOF_PYOBJECT_HEAD : usize = core:: mem:: size_of :: < PyInner < ( ) > > ( ) ;
306305
307306impl < T > PyInner < T > {
307+ /// Check if this object has an ObjExt prefix by examining type flags.
308+ /// Equivalent to Py_TPFLAGS_PREHEADER (MANAGED_DICT | MANAGED_WEAKREF)
309+ /// plus member slots.
310+ #[ inline( always) ]
311+ fn has_ext ( & self ) -> bool {
312+ let typ = self . typ . deref ( ) ;
313+ typ. slots
314+ . flags
315+ . has_feature ( crate :: types:: PyTypeFlags :: HAS_DICT )
316+ || typ
317+ . slots
318+ . flags
319+ . has_feature ( crate :: types:: PyTypeFlags :: HAS_WEAKREF )
320+ || typ. slots . member_count > 0
321+ }
322+
308323 /// Access the ObjExt prefix at a negative offset from this PyInner.
309324 /// Returns None if this object was allocated without the prefix.
310325 ///
326+ /// Uses type flags (HAS_DICT, HAS_WEAKREF, member_count) to determine
327+ /// if the prefix exists, matching CPython's Py_TPFLAGS_PREHEADER approach.
328+ ///
311329 /// Uses exposed provenance to reconstruct a pointer covering the entire
312330 /// allocation (ObjExt prefix + PyInner). The allocation pointer's provenance
313331 /// is exposed at allocation time via `expose_provenance()`.
314332 #[ inline( always) ]
315333 pub ( super ) fn ext_ref ( & self ) -> Option < & ObjExt > {
316- if !GcBits :: from_bits_retain ( self . gc_bits . load ( Ordering :: Relaxed ) ) . contains ( GcBits :: HAS_EXT )
317- {
334+ if !self . has_ext ( ) {
318335 return None ;
319336 }
320337 let self_addr = ( self as * const Self as * const u8 ) . addr ( ) ;
@@ -859,10 +876,7 @@ impl<T: PyPayload> PyInner<T> {
859876 /// `ptr` must be a valid pointer from `PyInner::new` and must not be used after this call.
860877 unsafe fn dealloc ( ptr : * mut Self ) {
861878 unsafe {
862- let has_ext = GcBits :: from_bits_retain ( ( * ptr) . gc_bits . load ( Ordering :: Relaxed ) )
863- . contains ( GcBits :: HAS_EXT ) ;
864-
865- if has_ext {
879+ if ( * ptr) . has_ext ( ) {
866880 let ext_layout = core:: alloc:: Layout :: new :: < ObjExt > ( ) ;
867881 let inner_layout = core:: alloc:: Layout :: new :: < Self > ( ) ;
868882 let ( combined, inner_offset) = ext_layout. extend ( inner_layout) . unwrap ( ) ;
@@ -887,7 +901,10 @@ impl<T: PyPayload + core::fmt::Debug> PyInner<T> {
887901 /// For objects with ext, the allocation layout is: [ObjExt][PyInner<T>]
888902 fn new ( payload : T , typ : PyTypeRef , dict : Option < PyDictRef > ) -> * mut Self {
889903 let member_count = typ. slots . member_count ;
890- let needs_ext = dict. is_some ( )
904+ let needs_ext = typ
905+ . slots
906+ . flags
907+ . has_feature ( crate :: types:: PyTypeFlags :: HAS_DICT )
891908 || typ
892909 . slots
893910 . flags
@@ -915,7 +932,7 @@ impl<T: PyPayload + core::fmt::Debug> PyInner<T> {
915932 inner_ptr. write ( Self {
916933 ref_count : RefCount :: new ( ) ,
917934 vtable : PyObjVTable :: of :: < T > ( ) ,
918- gc_bits : Radium :: new ( GcBits :: HAS_EXT . bits ( ) ) ,
935+ gc_bits : Radium :: new ( 0 ) ,
919936 typ : PyAtomicRef :: from ( typ) ,
920937 payload,
921938 } ) ;
@@ -2132,7 +2149,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
21322149 PyInner :: <PyType > {
21332150 ref_count: RefCount :: new( ) ,
21342151 vtable: PyObjVTable :: of:: <PyType >( ) ,
2135- gc_bits: Radium :: new( GcBits :: HAS_EXT . bits ( ) ) ,
2152+ gc_bits: Radium :: new( 0 ) ,
21362153 payload: type_payload,
21372154 } ,
21382155 Uninit { typ }
@@ -2145,7 +2162,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
21452162 PyInner :: <PyType > {
21462163 ref_count: RefCount :: new( ) ,
21472164 vtable: PyObjVTable :: of:: <PyType >( ) ,
2148- gc_bits: Radium :: new( GcBits :: HAS_EXT . bits ( ) ) ,
2165+ gc_bits: Radium :: new( 0 ) ,
21492166 payload: object_payload,
21502167 } ,
21512168 Uninit { typ } ,
0 commit comments