1212
1313import SwiftShims
1414
15+ /// Class object and class metadata structures
16+
1517public struct ClassMetadata {
1618 var superclassMetadata : UnsafeMutablePointer < ClassMetadata > ?
1719
@@ -39,6 +41,10 @@ public struct HeapObject {
3941 static let immortalRefCount = - 1
4042}
4143
44+
45+
46+ /// Allocations
47+
4248func alignedAlloc( size: Int , alignment: Int ) -> UnsafeMutableRawPointer ? {
4349 let alignment = max ( alignment, MemoryLayout< UnsafeRawPointer> . size)
4450 var r : UnsafeMutableRawPointer ? = nil
@@ -94,52 +100,98 @@ public func swift_initStackObject(metadata: UnsafeMutablePointer<ClassMetadata>,
94100 return object
95101}
96102
103+
104+
105+ /// Refcounting
106+
97107@_silgen_name ( " swift_setDeallocating " )
98108public func swift_setDeallocating( object: UnsafeMutablePointer < HeapObject > ) {
99109}
100110
101- // TODO/FIXME: Refcounting and swift_once is not thread-safe, the following only works in single-threaded environments.
102-
103111@_silgen_name ( " swift_isUniquelyReferenced_nonNull_native " )
104112public func swift_isUniquelyReferenced_nonNull_native( object: UnsafeMutablePointer < HeapObject > ) -> Bool {
105- // TODO/FIXME: Refcounting is not thread-safe, the following only works in single-threaded environments.
106- return object . pointee . refcount == 1
113+ let refcount = refcountPointer ( for : object )
114+ return loadAcquire ( refcount) == 1
107115}
108116
109117@_silgen_name ( " swift_retain " )
110118public func swift_retain( object: Builtin . RawPointer ) -> Builtin . RawPointer {
111119 return swift_retain_n ( object: object, n: 1 )
112120}
113121
122+ // Cannot use UnsafeMutablePointer<HeapObject>? directly in the function argument or return value as it causes IRGen crashes
114123@_silgen_name ( " swift_retain_n " )
115124public func swift_retain_n( object: Builtin . RawPointer , n: UInt32 ) -> Builtin . RawPointer {
116125 if Int ( Builtin . ptrtoint_Word ( object) ) == 0 { return object }
117126 let o = UnsafeMutablePointer < HeapObject > ( object)
118- // TODO/FIXME: Refcounting is not thread-safe, the following only works in single-threaded environments.
119- if o. pointee. refcount == HeapObject . immortalRefCount { return o. _rawValue }
120- o. pointee. refcount += Int ( n)
121- return o. _rawValue
127+ return swift_retain_n_ ( object: o, n: n) . _rawValue
128+ }
129+
130+ func swift_retain_n_( object: UnsafeMutablePointer < HeapObject > , n: UInt32 ) -> UnsafeMutablePointer < HeapObject > {
131+ let refcount = refcountPointer ( for: object)
132+ if loadRelaxed ( refcount) == HeapObject . immortalRefCount {
133+ return object
134+ }
135+
136+ addRelaxed ( refcount, n: Int ( n) )
137+
138+ return object
122139}
123140
124141@_silgen_name ( " swift_release " )
125- public func swift_release( object: Builtin . RawPointer ) {
142+ public func swift_release( object: UnsafeMutablePointer < HeapObject > ? ) {
126143 swift_release_n ( object: object, n: 1 )
127144}
128145
129146@_silgen_name ( " swift_release_n " )
130- public func swift_release_n( object: Builtin . RawPointer , n: UInt32 ) {
131- if Int ( Builtin . ptrtoint_Word ( object) ) == 0 { return }
132- let o = UnsafeMutablePointer < HeapObject > ( object)
133- // TODO/FIXME: Refcounting is not thread-safe, the following only works in single-threaded environments.
134- if o. pointee. refcount == HeapObject . immortalRefCount { return }
135- o. pointee. refcount -= Int ( n)
136- if ( o. pointee. refcount & HeapObject . refcountMask) == 0 {
137- _swift_embedded_invoke_heap_object_destroy ( o)
138- } else if ( o. pointee. refcount & HeapObject . refcountMask) < 0 {
147+ public func swift_release_n( object: UnsafeMutablePointer < HeapObject > ? , n: UInt32 ) {
148+ guard let object else {
149+ return
150+ }
151+
152+ let refcount = refcountPointer ( for: object)
153+ if loadRelaxed ( refcount) == HeapObject . immortalRefCount {
154+ return
155+ }
156+
157+ let resultingRefcount = subFetchAcquireRelease ( refcount, n: Int ( n) ) & HeapObject . refcountMask
158+ if resultingRefcount == 0 {
159+ _swift_embedded_invoke_heap_object_destroy ( object)
160+ } else if resultingRefcount < 0 {
139161 fatalError ( " negative refcount " )
140162 }
141163}
142164
165+
166+
167+ /// Refcount helpers
168+
169+ fileprivate func refcountPointer( for object: UnsafeMutablePointer < HeapObject > ) -> UnsafeMutablePointer < Int > {
170+ // TODO: This should use MemoryLayout<HeapObject>.offset(to: \.refcount) but we don't have KeyPaths yet
171+ return UnsafeMutablePointer < Int > ( UnsafeRawPointer ( object) . advanced ( by: MemoryLayout< Int> . size) . _rawValue)
172+ }
173+
174+ fileprivate func loadRelaxed( _ refcount: UnsafeMutablePointer < Int > ) -> Int {
175+ Int ( Builtin . atomicload_monotonic_Word ( refcount. _rawValue) )
176+ }
177+
178+ fileprivate func loadAcquire( _ refcount: UnsafeMutablePointer < Int > ) -> Int {
179+ Int ( Builtin . atomicload_acquire_Word ( refcount. _rawValue) )
180+ }
181+
182+ fileprivate func subFetchAcquireRelease( _ refcount: UnsafeMutablePointer < Int > , n: Int ) -> Int {
183+ let oldValue = Int ( Builtin . atomicrmw_sub_acqrel_Word ( refcount. _rawValue, n. _builtinWordValue) )
184+ return oldValue - n
185+ }
186+
187+ fileprivate func addRelaxed( _ refcount: UnsafeMutablePointer < Int > , n: Int ) {
188+ _ = Builtin . atomicrmw_add_monotonic_Word ( refcount. _rawValue, n. _builtinWordValue)
189+ }
190+
191+
192+
193+ /// Exclusivity checking
194+
143195@_silgen_name ( " swift_beginAccess " )
144196public func swift_beginAccess( pointer: UnsafeMutableRawPointer , buffer: UnsafeMutableRawPointer , flags: UInt , pc: UnsafeMutableRawPointer ) {
145197 // TODO: Add actual exclusivity checking.
@@ -150,6 +202,10 @@ public func swift_endAccess(buffer: UnsafeMutableRawPointer) {
150202 // TODO: Add actual exclusivity checking.
151203}
152204
205+
206+
207+ // Once
208+
153209@_silgen_name ( " swift_once " )
154210public func swift_once( predicate: UnsafeMutablePointer < Int > , fn: ( @convention ( c) ( UnsafeMutableRawPointer ) -> ( ) ) , context: UnsafeMutableRawPointer ) {
155211 // TODO/FIXME: The following only works in single-threaded environments.
@@ -160,6 +216,10 @@ public func swift_once(predicate: UnsafeMutablePointer<Int>, fn: (@convention(c)
160216 }
161217}
162218
219+
220+
221+ // Misc
222+
163223@_silgen_name ( " swift_deletedMethodError " )
164224public func swift_deletedMethodError( ) -> Never {
165225 Builtin . int_trap ( )
0 commit comments