Skip to content

Commit 1a56da6

Browse files
authored
Native implementation of -lengthOfBytesUsingEncoding, plus handling ASCII-subset MacRoman in a few places (#81791)
Fixes rdar://154341146
1 parent 7c1dffb commit 1a56da6

File tree

7 files changed

+137
-1
lines changed

7 files changed

+137
-1
lines changed

benchmark/single-source/ObjectiveCBridging.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,24 @@ public let benchmarks = [
100100
BenchmarkInfo(name: "NSDictionary.bridged.enumerate",
101101
runFunction: run_BridgedNSDictionaryEnumerate, tags: t,
102102
setUpFunction: setup_bridgedDictionaries),
103+
BenchmarkInfo(name: "NSString.bridged.byteCount.ascii.ascii",
104+
runFunction: run_BridgedNSStringLengthASCII_ASCII, tags: ts,
105+
setUpFunction: setup_bridgedStrings),
106+
BenchmarkInfo(name: "NSString.bridged.byteCount.ascii.utf8",
107+
runFunction: run_BridgedNSStringLengthASCII_UTF8, tags: ts,
108+
setUpFunction: setup_bridgedStrings),
109+
BenchmarkInfo(name: "NSString.bridged.byteCount.ascii.utf16",
110+
runFunction: run_BridgedNSStringLengthASCII_UTF16, tags: ts,
111+
setUpFunction: setup_bridgedStrings),
112+
BenchmarkInfo(name: "NSString.bridged.byteCount.ascii.macroman",
113+
runFunction: run_BridgedNSStringLengthASCII_MacRoman, tags: ts,
114+
setUpFunction: setup_bridgedStrings),
115+
BenchmarkInfo(name: "NSString.bridged.byteCount.utf8.utf8",
116+
runFunction: run_BridgedNSStringLengthUTF8_UTF8, tags: ts,
117+
setUpFunction: setup_bridgedStrings),
118+
BenchmarkInfo(name: "NSString.bridged.byteCount.utf8.utf16",
119+
runFunction: run_BridgedNSStringLengthUTF8_UTF16, tags: ts,
120+
setUpFunction: setup_bridgedStrings),
103121
]
104122

105123
#if _runtime(_ObjC)
@@ -801,6 +819,8 @@ var bridgedDictionaryOfNumbersToNumbers:NSDictionary! = nil
801819
var bridgedArrayMutableCopy:NSMutableArray! = nil
802820
var nsArray:NSArray! = nil
803821
var nsArrayMutableCopy:NSMutableArray! = nil
822+
var bridgedASCIIString:NSString! = nil
823+
var bridgedUTF8String:NSString! = nil
804824
#endif
805825

806826
public func setup_bridgedArrays() {
@@ -822,6 +842,14 @@ public func setup_bridgedDictionaries() {
822842
bridgedDictionaryOfNumbersToNumbers = numDict as NSDictionary
823843
}
824844

845+
public func setup_bridgedStrings() {
846+
#if _runtime(_ObjC)
847+
let str = Array(repeating: "The quick brown fox jumps over the lazy dog.", count: 100).joined()
848+
bridgedASCIIString = str as NSString
849+
let str2 = Array(repeating: "The quick brown fox jumps over the lazy dög.", count: 100).joined()
850+
bridgedUTF8String = str2 as NSString
851+
#endif
852+
}
825853

826854
@inline(never)
827855
public func run_BridgedNSArrayObjectAtIndex(_ n: Int) {
@@ -914,3 +942,40 @@ public func run_RealNSArrayMutableCopyObjectAtIndex(_ n: Int) {
914942
#endif
915943
}
916944

945+
@inline(__always)
946+
fileprivate func run_BridgedNSStringLength(_ asciiBase: Bool, _ enc: UInt, _ n: Int) {
947+
let str = asciiBase ? bridgedASCIIString : bridgedUTF8String
948+
for _ in 0 ..< n * 100 {
949+
blackHole(str!.lengthOfBytes(using: enc))
950+
}
951+
}
952+
953+
@inline(never)
954+
public func run_BridgedNSStringLengthASCII_ASCII(_ n: Int) {
955+
run_BridgedNSStringLength(true, 1 /* NSASCIIStringEncoding */, n)
956+
}
957+
958+
@inline(never)
959+
public func run_BridgedNSStringLengthASCII_UTF8(_ n: Int) {
960+
run_BridgedNSStringLength(true, 4 /* NSUTF8StringEncoding */, n)
961+
}
962+
963+
@inline(never)
964+
public func run_BridgedNSStringLengthASCII_UTF16(_ n: Int) {
965+
run_BridgedNSStringLength(true, 10 /* NSUnicodeStringEncoding */, n)
966+
}
967+
968+
@inline(never)
969+
public func run_BridgedNSStringLengthASCII_MacRoman(_ n: Int) {
970+
run_BridgedNSStringLength(true, 30 /* NSMacOSRomanStringEncoding */, n)
971+
}
972+
973+
@inline(never)
974+
public func run_BridgedNSStringLengthUTF8_UTF8(_ n: Int) {
975+
run_BridgedNSStringLength(false, 4 /* NSUTF8StringEncoding */, n)
976+
}
977+
978+
@inline(never)
979+
public func run_BridgedNSStringLengthUTF8_UTF16(_ n: Int) {
980+
run_BridgedNSStringLength(false, 10 /* NSUnicodeStringEncoding */, n)
981+
}

stdlib/public/SwiftShims/swift/shims/CoreFoundationShims.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ typedef unsigned long _swift_shims_CFHashCode;
3535
typedef signed long _swift_shims_CFIndex;
3636
#endif
3737

38+
typedef unsigned long _swift_shims_NSUInteger;
39+
3840
// Consider creating SwiftMacTypes.h for these
3941
typedef unsigned char _swift_shims_Boolean;
4042
typedef __swift_uint8_t _swift_shims_UInt8;
@@ -80,6 +82,11 @@ const void * _Nullable
8082
_swift_stdlib_CreateIndirectTaggedPointerString(const __swift_uint8_t * _Nonnull bytes,
8183
_swift_shims_CFIndex len);
8284

85+
SWIFT_RUNTIME_STDLIB_API
86+
const _swift_shims_NSUInteger
87+
_swift_stdlib_NSStringLengthOfBytesInEncodingTrampoline(id _Nonnull obj,
88+
unsigned long encoding);
89+
8390
#endif // __OBJC2__
8491

8592
#ifdef __cplusplus

stdlib/public/core/StringBridge.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,13 @@ internal func _cocoaCStringUsingEncodingTrampoline(
287287
return _swift_stdlib_NSStringCStringUsingEncodingTrampoline(string, encoding)
288288
}
289289

290+
@_effects(readonly)
291+
internal func _cocoaLengthOfBytesInEncodingTrampoline(
292+
_ string: _CocoaString, _ encoding: UInt
293+
) -> UInt {
294+
return _swift_stdlib_NSStringLengthOfBytesInEncodingTrampoline(string, encoding)
295+
}
296+
290297
@_effects(releasenone)
291298
internal func _cocoaGetCStringTrampoline(
292299
_ string: _CocoaString,

stdlib/public/core/StringStorageBridge.swift

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import SwiftShims
1616

1717
internal var _cocoaASCIIEncoding:UInt { 1 } /* NSASCIIStringEncoding */
1818
internal var _cocoaUTF8Encoding:UInt { 4 } /* NSUTF8StringEncoding */
19+
internal var _cocoaUTF16Encoding:UInt { 10 } /* NSUTF16StringEncoding and NSUnicodeStringEncoding*/
20+
internal var _cocoaMacRomanEncoding:UInt { 30 } /* NSMacOSRomanStringEncoding */
1921

2022
extension String {
2123
@available(SwiftStdlib 5.6, *)
@@ -69,13 +71,14 @@ extension _AbstractStringStorage {
6971
) -> Int8 {
7072
switch (encoding, isASCII) {
7173
case (_cocoaASCIIEncoding, true),
74+
(_cocoaMacRomanEncoding, true),
7275
(_cocoaUTF8Encoding, _):
7376
guard maxLength >= count + 1 else { return 0 }
7477
unsafe outputPtr.initialize(from: start, count: count)
7578
unsafe outputPtr[count] = 0
7679
return 1
7780
default:
78-
return unsafe _cocoaGetCStringTrampoline(self, outputPtr, maxLength, encoding)
81+
return unsafe _cocoaGetCStringTrampoline(self, outputPtr, maxLength, encoding)
7982
}
8083
}
8184

@@ -84,12 +87,35 @@ extension _AbstractStringStorage {
8487
internal func _cString(encoding: UInt) -> UnsafePointer<UInt8>? {
8588
switch (encoding, isASCII) {
8689
case (_cocoaASCIIEncoding, true),
90+
(_cocoaMacRomanEncoding, true),
8791
(_cocoaUTF8Encoding, _):
8892
return unsafe start
8993
default:
9094
return _cocoaCStringUsingEncodingTrampoline(self, encoding)
9195
}
9296
}
97+
98+
@_effects(readonly)
99+
internal func _lengthOfBytes(using encoding: UInt) -> UInt {
100+
switch encoding {
101+
case _cocoaASCIIEncoding:
102+
if unsafe isASCII || _allASCII(UnsafeBufferPointer(start: start, count: count)) {
103+
return UInt(count)
104+
}
105+
return 0
106+
case _cocoaUTF8Encoding:
107+
return UInt(count)
108+
case _cocoaUTF16Encoding:
109+
return UInt(UTF16Length)
110+
case _cocoaMacRomanEncoding:
111+
if unsafe isASCII || _allASCII(UnsafeBufferPointer(start: start, count: count)) {
112+
return UInt(count)
113+
}
114+
fallthrough
115+
default:
116+
return _cocoaLengthOfBytesInEncodingTrampoline(self, encoding)
117+
}
118+
}
93119

94120
@_effects(readonly)
95121
internal func _nativeIsEqual<T:_AbstractStringStorage>(
@@ -232,6 +258,12 @@ extension __StringStorage {
232258
return _cocoaUTF8Encoding
233259
}
234260
}
261+
262+
@objc(lengthOfBytesUsingEncoding:)
263+
@_effects(readonly)
264+
final internal func lengthOfBytes(using encoding: UInt) -> UInt {
265+
_lengthOfBytes(using: encoding)
266+
}
235267

236268
@objc(isEqualToString:)
237269
@_effects(readonly)
@@ -297,6 +329,12 @@ extension __SharedStringStorage {
297329
return _cocoaUTF8Encoding
298330
}
299331
}
332+
333+
@objc(lengthOfBytesUsingEncoding:)
334+
@_effects(readonly)
335+
final internal func lengthOfBytes(using encoding: UInt) -> UInt {
336+
_lengthOfBytes(using: encoding)
337+
}
300338

301339
@objc(_fastCStringContents:)
302340
@_effects(readonly)

stdlib/public/stubs/FoundationHelpers.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,19 @@ typedef __swift_uint8_t (*getCStringImplPtr)(id,
106106

107107
}
108108

109+
SWIFT_RUNTIME_STDLIB_API
110+
const _swift_shims_NSUInteger
111+
_swift_stdlib_NSStringLengthOfBytesInEncodingTrampoline(id _Nonnull obj,
112+
unsigned long encoding) {
113+
typedef _swift_shims_NSUInteger (*getLengthImplPtr)(id,
114+
SEL,
115+
unsigned long);
116+
SEL sel = @selector(lengthOfBytesUsingEncoding:);
117+
getLengthImplPtr imp = (getLengthImplPtr)class_getMethodImplementation([obj superclass], sel);
118+
119+
return imp(obj, sel, encoding);
120+
}
121+
109122
__swift_uint8_t
110123
_swift_stdlib_dyld_is_objc_constant_string(const void *addr) {
111124
return (SWIFT_RUNTIME_WEAK_CHECK(_dyld_is_objc_constant)

test/abi/macOS/arm64/stdlib.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,3 +1086,6 @@ Added: _$ss6MirrorV12DisplayStyleO16foreignReferenceyA2DmFWC
10861086
// var InlineArray._protectedAddress
10871087
Added: _$ss11InlineArrayVsRi__rlE16_protectedBufferSRyq_GvpMV
10881088
Added: _$ss11InlineArrayVsRi__rlE17_protectedAddressSPyq_GvpMV
1089+
1090+
// lengthOfBytes(using:)
1091+
Added: __swift_stdlib_NSStringLengthOfBytesInEncodingTrampoline

test/abi/macOS/x86_64/stdlib.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,3 +1086,6 @@ Added: _$ss6MirrorV12DisplayStyleO16foreignReferenceyA2DmFWC
10861086
// var InlineArray._protectedAddress
10871087
Added: _$ss11InlineArrayVsRi__rlE16_protectedBufferSRyq_GvpMV
10881088
Added: _$ss11InlineArrayVsRi__rlE17_protectedAddressSPyq_GvpMV
1089+
1090+
// lengthOfBytes(using:)
1091+
Added: __swift_stdlib_NSStringLengthOfBytesInEncodingTrampoline

0 commit comments

Comments
 (0)