Skip to content

Commit 8b57921

Browse files
committed
Assorted bridging changes:
• Convert _AbstractStringStorage to a protocol, and the free functions used to deduplicate implementations to extensions on that protocol. • Move 'start' into the abstract type and use that to simplify some code • Move the ASCII fast path for length into UTF16View. • Add a weirder but faster way to check which (if any) of our NSString subclasses a given object is, and adopt it
1 parent 8a27e89 commit 8b57921

File tree

6 files changed

+293
-231
lines changed

6 files changed

+293
-231
lines changed

stdlib/public/SwiftShims/CoreFoundationShims.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ _swift_stdlib_NSStringGetCStringTrampoline(id _Nonnull obj,
137137
_swift_shims_UInt8 *buffer,
138138
_swift_shims_CFIndex maxLength,
139139
unsigned long encoding);
140+
141+
SWIFT_RUNTIME_STDLIB_API
142+
__swift_uintptr_t
143+
_swift_stdlib_unsafeAddressOfClass(id _Nonnull obj);
140144

141145
#endif // __OBJC2__
142146

stdlib/public/core/StringBridge.swift

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ internal func _cocoaCStringUsingEncodingTrampoline(
107107
}
108108

109109

110+
111+
110112
@_effects(releasenone)
111113
internal func _cocoaGetCStringTrampoline(
112114
_ string: _CocoaString,
@@ -131,6 +133,40 @@ private var kCFStringEncodingUTF8 : _swift_shims_CFStringEncoding {
131133
@inline(__always) get { return 0x8000100 }
132134
}
133135

136+
@_effects(readonly)
137+
private func _unsafeAddressOfCocoaStringClass(_ str: _CocoaString) -> UInt {
138+
return _swift_stdlib_unsafeAddressOfClass(str)
139+
}
140+
141+
internal enum _KnownCocoaString {
142+
case storage
143+
case shared
144+
case cocoa
145+
#if !(arch(i386) || arch(arm))
146+
case tagged
147+
#endif
148+
149+
@inline(__always)
150+
init(_ str: _CocoaString) {
151+
152+
#if !(arch(i386) || arch(arm))
153+
if _isObjCTaggedPointer(str) {
154+
self = .tagged
155+
return
156+
}
157+
#endif
158+
159+
switch _unsafeAddressOfCocoaStringClass(str) {
160+
case unsafeBitCast(_StringStorage.self, to: UInt.self):
161+
self = .storage
162+
case unsafeBitCast(_SharedStringStorage.self, to: UInt.self):
163+
self = .shared
164+
default:
165+
self = .cocoa
166+
}
167+
}
168+
}
169+
134170
#if !(arch(i386) || arch(arm))
135171
// Resiliently write a tagged cocoa string's contents into a buffer
136172
@_effects(releasenone) // @opaque
@@ -185,47 +221,49 @@ private func _getCocoaStringPointer(
185221
@usableFromInline
186222
@_effects(releasenone) // @opaque
187223
internal func _bridgeCocoaString(_ cocoaString: _CocoaString) -> _StringGuts {
188-
if let abstract = cocoaString as? _AbstractStringStorage {
189-
return abstract.asString._guts
190-
}
224+
switch _KnownCocoaString(cocoaString) {
225+
case .storage:
226+
return _unsafeUncheckedDowncast(cocoaString, to: _StringStorage.self).asString._guts
227+
case .shared:
228+
return _unsafeUncheckedDowncast(cocoaString, to: _SharedStringStorage.self).asString._guts
191229
#if !(arch(i386) || arch(arm))
192-
if _isObjCTaggedPointer(cocoaString) {
193-
return _StringGuts(_SmallString(taggedCocoa: cocoaString))
194-
}
230+
case .tagged:
231+
return _StringGuts(_SmallString(taggedCocoa: cocoaString))
195232
#endif
196-
197-
// "copy" it into a value to be sure nobody will modify behind
198-
// our backs. In practice, when value is already immutable, this
199-
// just does a retain.
200-
//
201-
// TODO: Only in certain circumstances should we emit this call:
202-
// 1) If it's immutable, just retain it.
203-
// 2) If it's mutable with no associated information, then a copy must
204-
// happen; might as well eagerly bridge it in.
205-
// 3) If it's mutable with associated information, must make the call
206-
//
207-
let immutableCopy
208-
= _stdlib_binary_CFStringCreateCopy(cocoaString) as AnyObject
209-
210-
#if !(arch(i386) || arch(arm))
211-
if _isObjCTaggedPointer(immutableCopy) {
212-
return _StringGuts(_SmallString(taggedCocoa: immutableCopy))
213-
}
214-
#endif
215-
216-
let (fastUTF8, isASCII): (Bool, Bool)
217-
switch _getCocoaStringPointer(immutableCopy) {
233+
case .cocoa:
234+
// "copy" it into a value to be sure nobody will modify behind
235+
// our backs. In practice, when value is already immutable, this
236+
// just does a retain.
237+
//
238+
// TODO: Only in certain circumstances should we emit this call:
239+
// 1) If it's immutable, just retain it.
240+
// 2) If it's mutable with no associated information, then a copy must
241+
// happen; might as well eagerly bridge it in.
242+
// 3) If it's mutable with associated information, must make the call
243+
//
244+
let immutableCopy
245+
= _stdlib_binary_CFStringCreateCopy(cocoaString) as AnyObject
246+
247+
#if !(arch(i386) || arch(arm))
248+
if _isObjCTaggedPointer(immutableCopy) {
249+
return _StringGuts(_SmallString(taggedCocoa: immutableCopy))
250+
}
251+
#endif
252+
253+
let (fastUTF8, isASCII): (Bool, Bool)
254+
switch _getCocoaStringPointer(immutableCopy) {
218255
case .ascii(_): (fastUTF8, isASCII) = (true, true)
219256
case .utf8(_): (fastUTF8, isASCII) = (true, false)
220257
default: (fastUTF8, isASCII) = (false, false)
258+
}
259+
let length = _stdlib_binary_CFStringGetLength(immutableCopy)
260+
261+
return _StringGuts(
262+
cocoa: immutableCopy,
263+
providesFastUTF8: fastUTF8,
264+
isASCII: isASCII,
265+
length: length)
221266
}
222-
let length = _stdlib_binary_CFStringGetLength(immutableCopy)
223-
224-
return _StringGuts(
225-
cocoa: immutableCopy,
226-
providesFastUTF8: fastUTF8,
227-
isASCII: isASCII,
228-
length: length)
229267
}
230268

231269
extension String {

0 commit comments

Comments
 (0)