@@ -102,9 +102,20 @@ private func _NSStringLen(_ str: _StringSelectorHolder) -> Int {
102
102
internal func _stdlib_binary_CFStringGetLength(
103
103
_ source: _CocoaString
104
104
) -> Int {
105
+ if let len = getConstantTaggedCocoaContents ( source) ? . utf16Length {
106
+ return len
107
+ }
105
108
return _NSStringLen ( _objc ( source) )
106
109
}
107
110
111
+ @_effects ( readonly)
112
+ internal func _isNSString( _ str: AnyObject ) -> Bool {
113
+ if getConstantTaggedCocoaContents ( str) != nil {
114
+ return true
115
+ }
116
+ return _swift_stdlib_isNSString ( str) != 0
117
+ }
118
+
108
119
@_effects ( readonly)
109
120
private func _NSStringCharactersPtr( _ str: _StringSelectorHolder ) -> UnsafeMutablePointer < UTF16 . CodeUnit > ? {
110
121
return UnsafeMutablePointer ( mutating: str. _fastCharacterContents ( ) )
@@ -288,13 +299,24 @@ internal enum _KnownCocoaString {
288
299
#if !(arch(i386) || arch(arm) || arch(wasm32))
289
300
case tagged
290
301
#endif
302
+ #if arch(arm64)
303
+ case constantTagged
304
+ #endif
291
305
292
306
@inline ( __always)
293
307
init ( _ str: _CocoaString ) {
294
308
295
309
#if !(arch(i386) || arch(arm))
296
310
if _isObjCTaggedPointer ( str) {
311
+ #if arch(arm64)
312
+ if let _ = getConstantTaggedCocoaContents ( str) {
313
+ self = . constantTagged
314
+ } else {
315
+ self = . tagged
316
+ }
317
+ #else
297
318
self = . tagged
319
+ #endif
298
320
return
299
321
}
300
322
#endif
@@ -333,8 +355,42 @@ private func _NSStringASCIIPointer(_ str: _StringSelectorHolder) -> UnsafePointe
333
355
}
334
356
335
357
@_effects ( readonly) // @opaque
336
- internal func _cocoaASCIIPointer( _ str: _CocoaString ) -> UnsafePointer < UInt8 > ? {
337
- return _NSStringASCIIPointer ( _objc ( str) )
358
+ private func _withCocoaASCIIPointer< R> (
359
+ _ str: _CocoaString ,
360
+ requireStableAddress: Bool ,
361
+ work: ( UnsafePointer < UInt8 > ) -> R ?
362
+ ) -> R ? {
363
+ #if !(arch(i386) || arch(arm))
364
+ if _isObjCTaggedPointer ( str) {
365
+ if let ptr = getConstantTaggedCocoaContents ( str) ? . asciiContentsPointer {
366
+ return work ( ptr)
367
+ }
368
+ if requireStableAddress {
369
+ return nil // tagged pointer strings don't support _fastCStringContents
370
+ }
371
+ let tmp = _StringGuts ( _SmallString ( taggedCocoa: str) )
372
+ return tmp. withFastUTF8 { work ( $0. baseAddress. _unsafelyUnwrappedUnchecked) }
373
+ }
374
+ #endif
375
+ defer { _fixLifetime ( str) }
376
+ if let ptr = _NSStringASCIIPointer ( _objc ( str) ) {
377
+ return work ( ptr)
378
+ }
379
+ return nil
380
+ }
381
+
382
+ @_effects ( readonly) // @opaque
383
+ internal func withCocoaASCIIPointer< R> (
384
+ _ str: _CocoaString ,
385
+ work: ( UnsafePointer < UInt8 > ) -> R ?
386
+ ) -> R ? {
387
+ return _withCocoaASCIIPointer ( str, requireStableAddress: false , work: work)
388
+ }
389
+
390
+ @_effects ( readonly)
391
+ internal func stableCocoaASCIIPointer( _ str: _CocoaString )
392
+ -> UnsafePointer < UInt8 > ? {
393
+ return _withCocoaASCIIPointer ( str, requireStableAddress: true , work: { $0 } )
338
394
}
339
395
340
396
private enum CocoaStringPointer {
@@ -348,16 +404,61 @@ private enum CocoaStringPointer {
348
404
private func _getCocoaStringPointer(
349
405
_ cfImmutableValue: _CocoaString
350
406
) -> CocoaStringPointer {
351
- if let asciiPtr = _cocoaASCIIPointer ( cfImmutableValue) {
352
- // NOTE: CFStringGetCStringPointer means ASCII
353
- return . ascii( asciiPtr)
407
+ if let ascii = stableCocoaASCIIPointer ( cfImmutableValue) {
408
+ return . ascii( ascii)
354
409
}
355
410
if let utf16Ptr = _stdlib_binary_CFStringGetCharactersPtr ( cfImmutableValue) {
356
411
return . utf16( utf16Ptr)
357
412
}
358
413
return . none
359
414
}
360
415
416
+
417
+ @inline ( __always)
418
+ private func getConstantTaggedCocoaContents( _ cocoaString: _CocoaString ) ->
419
+ ( utf16Length: Int , asciiContentsPointer: UnsafePointer < UInt8 > ? ) ? {
420
+ #if !arch(arm64)
421
+ return nil
422
+ #else
423
+
424
+ guard _isObjCTaggedPointer ( cocoaString) else {
425
+ return nil
426
+ }
427
+
428
+ let taggedValue = unsafeBitCast ( cocoaString, to: UInt . self)
429
+
430
+ //11000000..payload..111
431
+ let tagMask : UInt =
432
+ 0b1111_1111_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0111
433
+ let expectedValue : UInt =
434
+ 0b1100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0111
435
+
436
+ guard taggedValue & tagMask == expectedValue else {
437
+ return nil
438
+ }
439
+
440
+ guard _swift_stdlib_dyld_is_objc_constant_string (
441
+ cocoaString as! UnsafeRawPointer
442
+ ) == 1 else {
443
+ return nil
444
+ }
445
+
446
+ let payloadMask = ~ tagMask
447
+ let payload = taggedValue & payloadMask
448
+ let ivarPointer = UnsafePointer < _swift_shims_builtin_CFString > (
449
+ bitPattern: payload
450
+ ) !
451
+ let length = ivarPointer. pointee. length
452
+ let isUTF16Mask : UInt = 0x0000_0000_0000_0004 //CFStringFlags bit 4: isUnicode
453
+ let isASCII = ivarPointer. pointee. flags & isUTF16Mask == 0
454
+ let contentsPtr = ivarPointer. pointee. str
455
+ return (
456
+ utf16Length: Int ( length) ,
457
+ asciiContentsPointer: isASCII ? contentsPtr : nil
458
+ )
459
+ #endif
460
+ }
461
+
361
462
@usableFromInline
362
463
@_effects ( releasenone) // @opaque
363
464
internal func _bridgeCocoaString( _ cocoaString: _CocoaString ) -> _StringGuts {
@@ -371,6 +472,16 @@ internal func _bridgeCocoaString(_ cocoaString: _CocoaString) -> _StringGuts {
371
472
#if !(arch(i386) || arch(arm))
372
473
case . tagged:
373
474
return _StringGuts ( _SmallString ( taggedCocoa: cocoaString) )
475
+ #if arch(arm64)
476
+ case . constantTagged:
477
+ let taggedContents = getConstantTaggedCocoaContents ( cocoaString) !
478
+ return _StringGuts (
479
+ cocoa: cocoaString,
480
+ providesFastUTF8: false , //TODO: if contentsPtr is UTF8 compatible, use it
481
+ isASCII: taggedContents. asciiContentsPointer != nil ,
482
+ length: taggedContents. utf16Length
483
+ )
484
+ #endif
374
485
#endif
375
486
case . cocoa:
376
487
// "Copy" it into a value to be sure nobody will modify behind
0 commit comments