12
12
13
13
import SwiftShims
14
14
15
+ /// Class object and class metadata structures
16
+
15
17
public struct ClassMetadata {
16
18
var superclassMetadata : UnsafeMutablePointer < ClassMetadata > ?
17
19
@@ -39,6 +41,10 @@ public struct HeapObject {
39
41
static let immortalRefCount = - 1
40
42
}
41
43
44
+
45
+
46
+ /// Allocations
47
+
42
48
func alignedAlloc( size: Int , alignment: Int ) -> UnsafeMutableRawPointer ? {
43
49
let alignment = max ( alignment, MemoryLayout< UnsafeRawPointer> . size)
44
50
var r : UnsafeMutableRawPointer ? = nil
@@ -94,52 +100,98 @@ public func swift_initStackObject(metadata: UnsafeMutablePointer<ClassMetadata>,
94
100
return object
95
101
}
96
102
103
+
104
+
105
+ /// Refcounting
106
+
97
107
@_silgen_name ( " swift_setDeallocating " )
98
108
public func swift_setDeallocating( object: UnsafeMutablePointer < HeapObject > ) {
99
109
}
100
110
101
- // TODO/FIXME: Refcounting and swift_once is not thread-safe, the following only works in single-threaded environments.
102
-
103
111
@_silgen_name ( " swift_isUniquelyReferenced_nonNull_native " )
104
112
public 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
107
115
}
108
116
109
117
@_silgen_name ( " swift_retain " )
110
118
public func swift_retain( object: Builtin . RawPointer ) -> Builtin . RawPointer {
111
119
return swift_retain_n ( object: object, n: 1 )
112
120
}
113
121
122
+ // Cannot use UnsafeMutablePointer<HeapObject>? directly in the function argument or return value as it causes IRGen crashes
114
123
@_silgen_name ( " swift_retain_n " )
115
124
public func swift_retain_n( object: Builtin . RawPointer , n: UInt32 ) -> Builtin . RawPointer {
116
125
if Int ( Builtin . ptrtoint_Word ( object) ) == 0 { return object }
117
126
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
122
139
}
123
140
124
141
@_silgen_name ( " swift_release " )
125
- public func swift_release( object: Builtin . RawPointer ) {
142
+ public func swift_release( object: UnsafeMutablePointer < HeapObject > ? ) {
126
143
swift_release_n ( object: object, n: 1 )
127
144
}
128
145
129
146
@_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 {
139
161
fatalError ( " negative refcount " )
140
162
}
141
163
}
142
164
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
+
143
195
@_silgen_name ( " swift_beginAccess " )
144
196
public func swift_beginAccess( pointer: UnsafeMutableRawPointer , buffer: UnsafeMutableRawPointer , flags: UInt , pc: UnsafeMutableRawPointer ) {
145
197
// TODO: Add actual exclusivity checking.
@@ -150,6 +202,10 @@ public func swift_endAccess(buffer: UnsafeMutableRawPointer) {
150
202
// TODO: Add actual exclusivity checking.
151
203
}
152
204
205
+
206
+
207
+ // Once
208
+
153
209
@_silgen_name ( " swift_once " )
154
210
public func swift_once( predicate: UnsafeMutablePointer < Int > , fn: ( @convention ( c) ( UnsafeMutableRawPointer ) -> ( ) ) , context: UnsafeMutableRawPointer ) {
155
211
// TODO/FIXME: The following only works in single-threaded environments.
@@ -160,6 +216,10 @@ public func swift_once(predicate: UnsafeMutablePointer<Int>, fn: (@convention(c)
160
216
}
161
217
}
162
218
219
+
220
+
221
+ // Misc
222
+
163
223
@_silgen_name ( " swift_deletedMethodError " )
164
224
public func swift_deletedMethodError( ) -> Never {
165
225
Builtin . int_trap ( )
0 commit comments