@@ -38,20 +38,21 @@ public struct HeapObject {
3838 // to think about supporting (or banning) weak and/or unowned references.
3939 var refcount : Int
4040
41+ // Note: The immortalRefCount value is also hard-coded in IRGen in `irgen::emitConstantObject`.
4142#if _pointerBitWidth(_64)
42- static let doNotFreeBit = Int ( bitPattern: 0x8000_0000_0000_0000 )
43- static let refcountMask = Int ( bitPattern: 0x7fff_ffff_ffff_ffff )
43+ static let doNotFreeBit = Int ( bitPattern: 0x8000_0000_0000_0000 )
44+ static let refcountMask = Int ( bitPattern: 0x7fff_ffff_ffff_ffff )
45+ static let immortalRefCount = Int ( bitPattern: 0x7fff_ffff_ffff_ffff ) // Make sure we don't have doNotFreeBit set
4446#elseif _pointerBitWidth(_32)
45- static let doNotFreeBit = Int ( bitPattern: 0x8000_0000 )
46- static let refcountMask = Int ( bitPattern: 0x7fff_ffff )
47+ static let doNotFreeBit = Int ( bitPattern: 0x8000_0000 )
48+ static let refcountMask = Int ( bitPattern: 0x7fff_ffff )
49+ static let immortalRefCount = Int ( bitPattern: 0x7fff_ffff ) // Make sure we don't have doNotFreeBit set
4750#elseif _pointerBitWidth(_16)
48- static let doNotFreeBit = Int ( bitPattern: 0x8000 )
49- static let refcountMask = Int ( bitPattern: 0x7fff )
51+ static let doNotFreeBit = Int ( bitPattern: 0x8000 )
52+ static let refcountMask = Int ( bitPattern: 0x7fff )
53+ static let immortalRefCount = Int ( bitPattern: 0x7fff ) // Make sure we don't have doNotFreeBit set
5054#endif
5155
52- // Note: The immortalRefCount value of -1 is also hard-coded in IRGen in `irgen::emitConstantObject`.
53- static let immortalRefCount = - 1
54-
5556#if _pointerBitWidth(_64)
5657 static let immortalObjectPointerBit = UInt ( 0x8000_0000_0000_0000 )
5758#endif
@@ -158,7 +159,7 @@ public func swift_initStaticObject(metadata: Builtin.RawPointer, object: Builtin
158159
159160func swift_initStaticObject( metadata: UnsafeMutablePointer < ClassMetadata > , object: UnsafeMutablePointer < HeapObject > ) -> UnsafeMutablePointer < HeapObject > {
160161 _swift_embedded_set_heap_object_metadata_pointer ( object, metadata)
161- object. pointee. refcount = HeapObject . immortalRefCount
162+ object. pointee. refcount = HeapObject . immortalRefCount | HeapObject . doNotFreeBit
162163 return object
163164}
164165
@@ -251,7 +252,7 @@ public func swift_retain_n(object: Builtin.RawPointer, n: UInt32) -> Builtin.Raw
251252
252253func swift_retain_n_( object: UnsafeMutablePointer < HeapObject > , n: UInt32 ) -> UnsafeMutablePointer < HeapObject > {
253254 let refcount = refcountPointer ( for: object)
254- if loadRelaxed ( refcount) == HeapObject . immortalRefCount {
255+ if loadRelaxed ( refcount) & HeapObject . refcountMask == HeapObject . immortalRefCount {
255256 return object
256257 }
257258
@@ -294,7 +295,8 @@ func swift_release_n_(object: UnsafeMutablePointer<HeapObject>?, n: UInt32) {
294295 }
295296
296297 let refcount = refcountPointer ( for: object)
297- if loadRelaxed ( refcount) == HeapObject . immortalRefCount {
298+ let loadedRefcount = loadRelaxed ( refcount)
299+ if loadedRefcount & HeapObject . refcountMask == HeapObject . immortalRefCount {
298300 return
299301 }
300302
@@ -309,7 +311,8 @@ func swift_release_n_(object: UnsafeMutablePointer<HeapObject>?, n: UInt32) {
309311 // There can only be one thread with a reference at this point (because
310312 // we're releasing the last existing reference), so a relaxed store is
311313 // enough.
312- storeRelaxed ( refcount, newValue: HeapObject . immortalRefCount)
314+ let doNotFree = ( loadedRefcount & HeapObject . doNotFreeBit) != 0
315+ storeRelaxed ( refcount, newValue: HeapObject . immortalRefCount | ( doNotFree ? HeapObject . doNotFreeBit : 0 ) )
313316
314317 _swift_embedded_invoke_heap_object_destroy ( object)
315318 } else if resultingRefcount < 0 {
0 commit comments