Skip to content

Commit 363b6df

Browse files
lorenteymilseman
authored andcommitted
Custom enum for _StringObject on 32-bit platforms (swiftlang#18)
* [32bit] Use a custom enum type instead of AnyObject? in _StringObject This allows us to eliminate the _StringGuts._extraBits stored property, reducing the size of String to three words on 32-bit platforms. In exchange, we don't have uniform flag bits on 32-bit platforms any more, likely reducing performance of our existing _StringObject accessors. (The flag bits are now encoded in the enum representation in the tagged cases.) * [test] Update tests for 3-word Strings on 32-bit platforms * [test] Work around a spurious test failure in 32-bit builds * isEmptyLiteral -> isEmptySingleton * _StringObject: Add sanityChecks to referenceBits and payloadBits
1 parent 7a01bde commit 363b6df

File tree

9 files changed

+325
-318
lines changed

9 files changed

+325
-318
lines changed

stdlib/public/core/String.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,7 @@ extension String {
10111011
/// - Parameter other: Another string.
10121012
@_inlineable // FIXME(sil-serialize-all)
10131013
public mutating func append(_ other: String) {
1014-
if self._guts._isEmptyLiteral {
1014+
if self._guts._isEmptySingleton {
10151015
// We must be careful not to discard any capacity that
10161016
// may have been reserved for the append -- this is why
10171017
// we check for the empty string singleton rather than

stdlib/public/core/StringGuts.swift

Lines changed: 20 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,6 @@ struct _StringGuts {
4040
public // FIXME for testing only
4141
var _otherBits: UInt // (Mostly) count or inline storage
4242

43-
#if arch(i386) || arch(arm)
44-
public // FIXME for testing only
45-
var _extraBits: UInt // Start address or inline storage
46-
#endif
47-
48-
#if arch(i386) || arch(arm)
49-
@_inlineable
50-
@inline(__always)
51-
public
52-
init(object: _StringObject, otherBits: UInt, extraBits: UInt) {
53-
self._object = object
54-
self._otherBits = otherBits
55-
self._extraBits = extraBits
56-
_invariantCheck()
57-
}
58-
#else
5943
@_inlineable
6044
@inline(__always)
6145
public
@@ -64,36 +48,22 @@ struct _StringGuts {
6448
self._otherBits = otherBits
6549
_invariantCheck()
6650
}
67-
#endif
6851

69-
public typealias _RawBitPattern = (UInt64, UInt64)
52+
public typealias _RawBitPattern = (_StringObject._RawBitPattern, UInt)
7053

7154
@_versioned
7255
@_inlineable
7356
internal var rawBits: _RawBitPattern {
7457
@inline(__always)
7558
get {
76-
#if arch(i386) || arch(arm)
77-
return (_object.rawBits,
78-
UInt64(truncatingIfNeeded: _extraBits) &<< 32 |
79-
UInt64(truncatingIfNeeded: _otherBits))
80-
#else
81-
return (_object.rawBits, UInt64(truncatingIfNeeded: _otherBits))
82-
#endif
59+
return (_object.rawBits, _otherBits)
8360
}
8461
}
8562

8663
init(rawBits: _RawBitPattern) {
87-
#if arch(i386) || arch(arm)
88-
self.init(
89-
object: _StringObject(rawBits: rawBits.0),
90-
otherBits: UInt(truncatingIfNeeded: rawBits.1),
91-
extraBits: UInt(truncatingIfNeeded: rawBits.1 &>> 32))
92-
#else
9364
self.init(
9465
object: _StringObject(rawBits: rawBits.0),
95-
otherBits: UInt(rawBits.1))
96-
#endif
66+
otherBits: rawBits.1)
9767
}
9868
}
9969

@@ -103,25 +73,6 @@ extension _StringGuts {
10373
internal func _invariantCheck() {
10474
#if INTERNAL_CHECKS_ENABLED
10575
_object._invariantCheck()
106-
#if arch(i386) || arch(arm)
107-
if _object.isContiguous {
108-
_sanityCheck(_extraBits != 0) // TODO: in ABI's address space
109-
} else {
110-
_sanityCheck(_extraBits == 0)
111-
}
112-
if _object.isNative {
113-
_sanityCheck(UInt(_object.nativeRawStorage.count) == self._otherBits)
114-
_sanityCheck(
115-
UInt(bitPattern: _object.nativeRawStorage.rawStart) == self._extraBits)
116-
} else if _object.isUnmanaged {
117-
} else if _object.isCocoa {
118-
_sanityCheck(_otherBits != 0)
119-
} else if _object.isSmall {
120-
fatalError("Small strings aren't supported yet")
121-
} else {
122-
fatalError("Unimplemented string form")
123-
}
124-
#else // 64-bit
12576
if _object.isNative {
12677
_sanityCheck(UInt(_object.nativeRawStorage.count) == self._otherBits)
12778
} else if _object.isUnmanaged {
@@ -135,7 +86,6 @@ extension _StringGuts {
13586
} else {
13687
fatalError("Unimplemented string form")
13788
}
138-
#endif // arch(i386) || arch(arm)
13989
#endif // INTERNAL_CHECKS_ENABLED
14090
}
14191

@@ -158,7 +108,6 @@ extension _StringGuts {
158108
var bitPattern = _object.referenceBits
159109
return _isUnique_native(&bitPattern)
160110
}
161-
162111
}
163112

164113
extension _StringGuts {
@@ -211,12 +160,8 @@ extension _StringGuts {
211160
@_versioned
212161
@_inlineable
213162
internal
214-
var _isEmptyLiteral: Bool {
215-
#if arch(i386) || arch(arm)
216-
return _extraBits == UInt(bitPattern: _emptyStringBase)
217-
#else
218-
return _object.isEmptyLiteral
219-
#endif
163+
var _isEmptySingleton: Bool {
164+
return _object.isEmptySingleton
220165
}
221166

222167
@_inlineable
@@ -246,16 +191,9 @@ extension _StringGuts {
246191
init<CodeUnit>(_ storage: _SwiftStringStorage<CodeUnit>)
247192
where CodeUnit : FixedWidthInteger & UnsignedInteger {
248193
_sanityCheck(storage.count >= 0)
249-
#if arch(i386) || arch(arm)
250-
self.init(
251-
object: _StringObject(storage),
252-
otherBits: UInt(bitPattern: storage.count),
253-
extraBits: UInt(bitPattern: storage.rawStart))
254-
#else
255194
self.init(
256195
object: _StringObject(storage),
257196
otherBits: UInt(bitPattern: storage.count))
258-
#endif
259197
}
260198
}
261199

@@ -264,14 +202,7 @@ extension _StringGuts {
264202
@inline(__always)
265203
public // @testable
266204
init() {
267-
#if arch(i386) || arch(arm)
268-
self.init(
269-
object: _StringObject(),
270-
otherBits: 0,
271-
extraBits: UInt(bitPattern: _emptyStringBase))
272-
#else
273205
self.init(object: _StringObject(), otherBits: 0)
274-
#endif
275206
_invariantCheck()
276207
}
277208
}
@@ -340,22 +271,12 @@ extension _StringGuts {
340271
self.init()
341272
return
342273
}
343-
#if arch(i386) || arch(arm)
344-
self.init(
345-
object: _StringObject(
346-
cocoaObject: s,
347-
isSingleByte: isSingleByte,
348-
isContiguous: start != nil),
349-
otherBits: UInt(bitPattern: count),
350-
extraBits: UInt(bitPattern: start))
351-
#else
352274
self.init(
353275
object: _StringObject(
354276
cocoaObject: s,
355277
isSingleByte: isSingleByte,
356278
isContiguous: start != nil),
357279
otherBits: UInt(bitPattern: start))
358-
#endif
359280
if start == nil {
360281
_sanityCheck(_object.isOpaque)
361282
} else {
@@ -392,11 +313,7 @@ extension _StringGuts {
392313
internal var _unmanagedRawStart: UnsafeRawPointer {
393314
@inline(__always) get {
394315
_sanityCheck(_object.isUnmanaged)
395-
#if arch(i386) || arch(arm)
396-
return Builtin.reinterpretCast(_extraBits)
397-
#else
398316
return _object.asUnmanagedRawStart
399-
#endif
400317
}
401318
}
402319

@@ -430,16 +347,9 @@ extension _StringGuts {
430347
init<CodeUnit>(_ s: _UnmanagedString<CodeUnit>)
431348
where CodeUnit : FixedWidthInteger & UnsignedInteger {
432349
_sanityCheck(s.count >= 0)
433-
#if arch(i386) || arch(arm)
434-
self.init(
435-
object: _StringObject(unmanagedWithBitWidth: CodeUnit.bitWidth),
436-
otherBits: UInt(bitPattern: s.count),
437-
extraBits: UInt(bitPattern: s.rawStart))
438-
#else
439350
self.init(
440351
object: _StringObject(unmanaged: s.start),
441352
otherBits: UInt(bitPattern: s.count))
442-
#endif
443353
_sanityCheck(_object.isUnmanaged)
444354
_sanityCheck(_unmanagedRawStart == s.rawStart)
445355
_sanityCheck(_unmanagedCount == s.count)
@@ -455,24 +365,34 @@ extension _StringGuts {
455365
@_versioned
456366
@_inlineable
457367
internal var _taggedCocoaCount: Int {
458-
_sanityCheck(_object.isSmall)
459-
return Int(truncatingIfNeeded: _object.payloadBits)
368+
@inline(__always) get {
369+
#if arch(i386) || arch(arm)
370+
_sanityCheckFailure("Tagged Cocoa objects aren't supported on 32-bit platforms")
371+
#else
372+
_sanityCheck(_object.isSmall)
373+
return Int(truncatingIfNeeded: _object.payloadBits)
374+
#endif
375+
}
460376
}
461377

462378
@_versioned
463379
@_inlineable
464380
internal var _taggedCocoaObject: _CocoaString {
465381
@inline(__always) get {
382+
#if arch(i386) || arch(arm)
383+
_sanityCheckFailure("Tagged Cocoa objects aren't supported on 32-bit platforms")
384+
#else
466385
_sanityCheck(_object.isSmall)
467386
return Builtin.reinterpretCast(_otherBits)
387+
#endif
468388
}
469389
}
470390

471391
@_versioned
472392
@inline(never) // Hide CF dependency
473393
internal init(_taggedCocoaObject object: _CocoaString) {
474394
#if arch(i386) || arch(arm)
475-
_sanityCheckFailure("32-bit platforms don't have tagged Cocoa objects")
395+
_sanityCheckFailure("Tagged Cocoa objects aren't supported on 32-bit platforms")
476396
#else
477397
_sanityCheck(_isObjCTaggedPointer(object))
478398
let count = _stdlib_binary_CFStringGetLength(object)
@@ -494,14 +414,6 @@ extension _StringGuts {
494414
@effects(readonly)
495415
get {
496416
_sanityCheck(_object.isContiguousASCII)
497-
#if arch(i386) || arch(arm)
498-
_sanityCheck(self._extraBits != 0)
499-
let start = UnsafePointer<UInt8>(bitPattern: _extraBits)
500-
let count = Int(bitPattern: _otherBits)
501-
return _UnmanagedASCIIString(
502-
start: start._unsafelyUnwrappedUnchecked,
503-
count: count)
504-
#else
505417
if _object.isUnmanaged {
506418
return _asUnmanaged()
507419
} else if _object.isNative {
@@ -514,7 +426,6 @@ extension _StringGuts {
514426
Builtin.unreachable()
515427
#endif
516428
}
517-
#endif // arch(i386) || arch(arm)
518429
}
519430
}
520431

@@ -525,14 +436,6 @@ extension _StringGuts {
525436
@effects(readonly)
526437
get {
527438
_sanityCheck(_object.isContiguousUTF16)
528-
#if arch(i386) || arch(arm)
529-
_sanityCheck(_extraBits != 0)
530-
let start = UnsafePointer<UTF16.CodeUnit>(bitPattern: _extraBits)
531-
let count = Int(bitPattern: _otherBits)
532-
return _UnmanagedUTF16String(
533-
start: start._unsafelyUnwrappedUnchecked,
534-
count: count)
535-
#else
536439
if _object.isUnmanaged {
537440
return _asUnmanaged()
538441
} else if _object.isNative {
@@ -545,7 +448,6 @@ extension _StringGuts {
545448
Builtin.unreachable()
546449
#endif
547450
}
548-
#endif // arch(i386) || arch(arm)
549451
}
550452
}
551453
}
@@ -1138,7 +1040,7 @@ extension _StringGuts {
11381040
@_inlineable
11391041
public // TODO(StringGuts): for testing only
11401042
mutating func append(_ other: _StringGuts) {
1141-
if _isEmptyLiteral {
1043+
if _isEmptySingleton {
11421044
self = other
11431045
return
11441046
}
@@ -1157,7 +1059,7 @@ extension _StringGuts {
11571059
mutating func append(_ other: _StringGuts, range: Range<Int>) {
11581060
_sanityCheck(range.lowerBound >= 0 && range.upperBound <= other.count)
11591061
guard range.count > 0 else { return }
1160-
if _isEmptyLiteral && range.count == other.count {
1062+
if _isEmptySingleton && range.count == other.count {
11611063
self = other
11621064
return
11631065
}

0 commit comments

Comments
 (0)