Skip to content

Commit 9886e4e

Browse files
committed
Use UnsafeRawPointer in StringCore.
This is another necessary step in introducing changes for SE-0107: UnsafeRawPointer. UnsafeRawPointer is great for bytewise pointer operations. OpaquePointer goes away. The _RawByte type goes away. StringBuffer always binds memory to the correct CodeUnit when allocating memory. Before accessing the string, a dynamic element width check allows us to assume the bound memory type. Generic entry points like atomicCompareExchange no longer handle both kinds of pointers. Normally that's good because you should not be using generics in that case, just upcast to raw pointer. However, with pointers-to-pointers you can't do that.
1 parent 3e2372b commit 9886e4e

12 files changed

+133
-119
lines changed

stdlib/public/SDK/GLKit/GLKit.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ vectorElementNames = [
3535
public func _indexHomogeneousValue<TTT, T>(_ aggregate: UnsafePointer<TTT>,
3636
_ index: Int) -> T {
3737
return UnsafeRawPointer(aggregate).load(
38-
fromByteOffset: index * strideof(T), as: T.self)
38+
fromByteOffset: index * strideof(T.self), as: T.self)
3939
}
4040

4141
%{

stdlib/public/core/Character.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public struct Character :
183183
}
184184
else {
185185
if let native = s._core.nativeBuffer,
186-
native.start == UnsafeMutablePointer(s._core._baseAddress!) {
186+
native.start == s._core._baseAddress! {
187187
_representation = .large(native._storage)
188188
return
189189
}

stdlib/public/core/Runtime.swift.gyb

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,21 @@ import SwiftShims
2020
// Atomics
2121
//===----------------------------------------------------------------------===//
2222

23+
public typealias _PointerToPointer = UnsafeMutablePointer<UnsafeRawPointer?>
24+
2325
@_transparent
2426
public // @testable
25-
func _stdlib_atomicCompareExchangeStrongPtrImpl(
26-
object target: UnsafeMutablePointer<UnsafeMutableRawPointer?>,
27-
expected: UnsafeMutablePointer<UnsafeMutableRawPointer?>,
28-
desired: UnsafeMutableRawPointer?) -> Bool {
27+
func _stdlib_atomicCompareExchangeStrongPtr(
28+
object target: _PointerToPointer,
29+
expected: _PointerToPointer,
30+
desired: UnsafeRawPointer?) -> Bool {
2931

3032
// We use Builtin.Word here because Builtin.RawPointer can't be nil.
3133
let (oldValue, won) = Builtin.cmpxchg_seqcst_seqcst_Word(
3234
target._rawValue,
3335
UInt(bitPattern: expected.pointee)._builtinWordValue,
3436
UInt(bitPattern: desired)._builtinWordValue)
35-
expected.pointee = UnsafeMutableRawPointer(bitPattern: Int(oldValue))
37+
expected.pointee = UnsafeRawPointer(bitPattern: Int(oldValue))
3638
return Bool(won)
3739
}
3840

@@ -70,23 +72,23 @@ func _stdlib_atomicCompareExchangeStrongPtr<T>(
7072
object target: UnsafeMutablePointer<UnsafeMutablePointer<T>${optional}>,
7173
expected: UnsafeMutablePointer<UnsafeMutablePointer<T>${optional}>,
7274
desired: UnsafeMutablePointer<T>${optional}) -> Bool {
73-
return _stdlib_atomicCompareExchangeStrongPtrImpl(
74-
object: UnsafeMutablePointer(target),
75-
expected: UnsafeMutablePointer(expected),
76-
desired: UnsafeMutablePointer(desired))
75+
return _stdlib_atomicCompareExchangeStrongPtr(
76+
object: unsafeBitCast(target, to: _PointerToPointer.self),
77+
expected: unsafeBitCast(expected, to: _PointerToPointer.self),
78+
desired: unsafeBitCast(desired, to: Optional<UnsafeRawPointer>.self))
7779
}
78-
% end
80+
% end # optional
7981

8082
@_transparent
8183
@discardableResult
8284
public // @testable
8385
func _stdlib_atomicInitializeARCRef(
8486
object target: UnsafeMutablePointer<AnyObject?>,
8587
desired: AnyObject) -> Bool {
86-
var expected: UnsafeMutableRawPointer? = nil
88+
var expected: UnsafeRawPointer? = nil
8789
let desiredPtr = Unmanaged.passRetained(desired).toOpaque()
88-
let wonRace = _stdlib_atomicCompareExchangeStrongPtrImpl(
89-
object: UnsafeMutablePointer(target),
90+
let wonRace = _stdlib_atomicCompareExchangeStrongPtr(
91+
object: unsafeBitCast(target, to: _PointerToPointer.self),
9092
expected: &expected,
9193
desired: desiredPtr)
9294
if !wonRace {

stdlib/public/core/String.swift

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ extension String : _ExpressibleByBuiltinUTF16StringLiteral {
400400
) {
401401
self = String(
402402
_StringCore(
403-
baseAddress: OpaquePointer(start),
403+
baseAddress: UnsafeMutableRawPointer(start),
404404
count: Int(utf16CodeUnitCount),
405405
elementShift: 1,
406406
hasCocoaBuffer: false,
@@ -418,7 +418,7 @@ extension String : _ExpressibleByBuiltinStringLiteral {
418418
if Bool(isASCII) {
419419
self = String(
420420
_StringCore(
421-
baseAddress: OpaquePointer(start),
421+
baseAddress: UnsafeMutableRawPointer(start),
422422
count: Int(utf8CodeUnitCount),
423423
elementShift: 0,
424424
hasCocoaBuffer: false,
@@ -699,13 +699,15 @@ extension String : Hashable {
699699
}
700700
#else
701701
if self._core.isASCII {
702-
return _swift_stdlib_unicode_hash_ascii(
703-
UnsafeMutablePointer<Int8>(_core.startASCII),
704-
Int32(_core.count))
702+
return _core.startASCII.withMemoryRebound(
703+
to: CChar.self, capacity: _core.count) {
704+
_swift_stdlib_unicode_hash_ascii($0, Int32(_core.count))
705+
}
705706
} else {
706-
return _swift_stdlib_unicode_hash(
707-
UnsafeMutablePointer<UInt16>(_core.startUTF16),
708-
Int32(_core.count))
707+
return _core.startUTF16.withMemoryRebound(
708+
to: UInt16.self, capacity: _core.count) {
709+
_swift_stdlib_unicode_hash($0, Int32(_core.count))
710+
}
709711
}
710712
#endif
711713
}
@@ -821,7 +823,8 @@ internal func _nativeUnicodeLowercaseString(_ str: String) -> String {
821823
capacity: str._core.count, initialSize: str._core.count, elementWidth: 2)
822824

823825
// Try to write it out to the same length.
824-
let dest = UnsafeMutablePointer<UTF16.CodeUnit>(buffer.start)
826+
let dest = buffer.start.bindMemory(
827+
to: UTF16.CodeUnit.self, capacity: str._core.count)
825828
let z = _swift_stdlib_unicode_strToLower(
826829
dest, Int32(str._core.count),
827830
str._core.startUTF16, Int32(str._core.count))
@@ -831,7 +834,8 @@ internal func _nativeUnicodeLowercaseString(_ str: String) -> String {
831834
if correctSize != str._core.count {
832835
buffer = _StringBuffer(
833836
capacity: correctSize, initialSize: correctSize, elementWidth: 2)
834-
let dest = UnsafeMutablePointer<UTF16.CodeUnit>(buffer.start)
837+
let dest = buffer.start.bindMemory(
838+
to: UTF16.CodeUnit.self, capacity: str._core.count)
835839
_swift_stdlib_unicode_strToLower(
836840
dest, Int32(correctSize), str._core.startUTF16, Int32(str._core.count))
837841
}
@@ -844,7 +848,8 @@ internal func _nativeUnicodeUppercaseString(_ str: String) -> String {
844848
capacity: str._core.count, initialSize: str._core.count, elementWidth: 2)
845849

846850
// Try to write it out to the same length.
847-
let dest = UnsafeMutablePointer<UTF16.CodeUnit>(buffer.start)
851+
let dest = buffer.start.bindMemory(
852+
to: UTF16.CodeUnit.self, capacity: str._core.count)
848853
let z = _swift_stdlib_unicode_strToUpper(
849854
dest, Int32(str._core.count),
850855
str._core.startUTF16, Int32(str._core.count))
@@ -854,7 +859,8 @@ internal func _nativeUnicodeUppercaseString(_ str: String) -> String {
854859
if correctSize != str._core.count {
855860
buffer = _StringBuffer(
856861
capacity: correctSize, initialSize: correctSize, elementWidth: 2)
857-
let dest = UnsafeMutablePointer<UTF16.CodeUnit>(buffer.start)
862+
let dest = buffer.start.bindMemory(
863+
to: UTF16.CodeUnit.self, capacity: str._core.count)
858864
_swift_stdlib_unicode_strToUpper(
859865
dest, Int32(correctSize), str._core.startUTF16, Int32(str._core.count))
860866
}
@@ -904,7 +910,7 @@ extension String {
904910
let source = self._core.startASCII
905911
let buffer = _StringBuffer(
906912
capacity: count, initialSize: count, elementWidth: 1)
907-
let dest = UnsafeMutablePointer<UInt8>(buffer.start)
913+
let dest = buffer.start
908914
for i in 0..<count {
909915
// For each character in the string, we lookup if it should be shifted
910916
// in our ascii table, then we return 0x20 if it should, 0x0 if not.
@@ -923,7 +929,8 @@ extension String {
923929
// Since we are left with either 0x0 or 0x20, we can safely truncate to
924930
// a UInt8 and add to our ASCII value (this will not overflow numbers in
925931
// the ASCII range).
926-
dest[i] = value &+ UInt8(truncatingBitPattern: add)
932+
dest.storeBytes(of: value &+ UInt8(truncatingBitPattern: add),
933+
toByteOffset: i, as: UInt8.self)
927934
}
928935
return String(_storage: buffer)
929936
}
@@ -953,15 +960,16 @@ extension String {
953960
let source = self._core.startASCII
954961
let buffer = _StringBuffer(
955962
capacity: count, initialSize: count, elementWidth: 1)
956-
let dest = UnsafeMutablePointer<UInt8>(buffer.start)
963+
let dest = buffer.start
957964
for i in 0..<count {
958965
// See the comment above in lowercaseString.
959966
let value = source[i]
960967
let isLower =
961968
_asciiLowerCaseTable >>
962969
UInt64(((value &- 1) & 0b0111_1111) >> 1)
963970
let add = (isLower & 0x1) << 5
964-
dest[i] = value &- UInt8(truncatingBitPattern: add)
971+
dest.storeBytes(of: value &- UInt8(truncatingBitPattern: add),
972+
toByteOffset: i, as: UInt8.self)
965973
}
966974
return String(_storage: buffer)
967975
}

stdlib/public/core/StringBridge.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func _cocoaStringToSwiftString_NonASCII(
5454
let start = _stdlib_binary_CFStringGetCharactersPtr(cfImmutableValue)
5555

5656
return String(_StringCore(
57-
baseAddress: OpaquePointer(start),
57+
baseAddress: start,
5858
count: length,
5959
elementShift: 1,
6060
hasCocoaBuffer: true,
@@ -81,7 +81,7 @@ internal func _cocoaStringToContiguous(
8181

8282
_swift_stdlib_CFStringGetCharacters(
8383
source, _swift_shims_CFRange(location: startIndex, length: count),
84-
UnsafeMutablePointer<_swift_shims_UniChar>(buffer.start))
84+
buffer.start.assumingMemoryBound(to: _swift_shims_UniChar.self))
8585

8686
return buffer
8787
}
@@ -163,13 +163,13 @@ extension String {
163163

164164
// start will hold the base pointer of contiguous storage, if it
165165
// is found.
166-
var start: OpaquePointer?
166+
var start: UnsafeMutableRawPointer?
167167
let isUTF16 = (nulTerminatedASCII == nil)
168168
if isUTF16 {
169169
let utf16Buf = _swift_stdlib_CFStringGetCharactersPtr(cfImmutableValue)
170-
start = OpaquePointer(utf16Buf)
170+
start = UnsafeMutableRawPointer(mutating: utf16Buf)
171171
} else {
172-
start = OpaquePointer(nulTerminatedASCII)
172+
start = UnsafeMutableRawPointer(mutating: nulTerminatedASCII)
173173
}
174174

175175
self._core = _StringCore(

stdlib/public/core/StringBuffer.swift

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct _StringBufferIVars {
1919
}
2020

2121
internal init(
22-
_usedEnd: UnsafeMutablePointer<_RawByte>,
22+
_usedEnd: UnsafeMutableRawPointer,
2323
byteCapacity: Int,
2424
elementWidth: Int
2525
) {
@@ -31,7 +31,7 @@ struct _StringBufferIVars {
3131

3232
// This stored property should be stored at offset zero. We perform atomic
3333
// operations on it using _HeapBuffer's pointer.
34-
var usedEnd: UnsafeMutablePointer<_RawByte>?
34+
var usedEnd: UnsafeMutableRawPointer?
3535

3636
var capacityAndElementShift: Int
3737
var byteCapacity: Int {
@@ -78,6 +78,14 @@ public struct _StringBuffer {
7878
_StringBufferIVars(_elementWidth: elementWidth),
7979
(capacity + capacityBump + divRound) >> divRound
8080
)
81+
// This conditional branch should fold away during code gen.
82+
if elementShift == 0 {
83+
start.bindMemory(to: UTF8.CodeUnit.self, capacity: initialSize)
84+
}
85+
else {
86+
start.bindMemory(to: UTF16.CodeUnit.self, capacity: initialSize)
87+
}
88+
8189
self.usedEnd = start + (initialSize << elementShift)
8290
_storage.value.capacityAndElementShift
8391
= ((_storage._capacity() - capacityBump) << 1) + elementShift
@@ -107,7 +115,7 @@ public struct _StringBuffer {
107115
elementWidth: isAscii ? 1 : 2)
108116

109117
if isAscii {
110-
var p = UnsafeMutablePointer<UTF8.CodeUnit>(result.start)
118+
var p = result.start.assumingMemoryBound(to: UTF8.CodeUnit.self)
111119
let sink: (UTF32.CodeUnit) -> Void = {
112120
p.pointee = UTF8.CodeUnit($0)
113121
p += 1
@@ -137,12 +145,12 @@ public struct _StringBuffer {
137145

138146
/// A pointer to the start of this buffer's data area.
139147
public // @testable
140-
var start: UnsafeMutablePointer<_RawByte> {
141-
return UnsafeMutablePointer(_storage.baseAddress)
148+
var start: UnsafeMutableRawPointer {
149+
return UnsafeMutableRawPointer(_storage.baseAddress)
142150
}
143151

144152
/// A past-the-end pointer for this buffer's stored data.
145-
var usedEnd: UnsafeMutablePointer<_RawByte> {
153+
var usedEnd: UnsafeMutableRawPointer {
146154
get {
147155
return _storage.value.usedEnd!
148156
}
@@ -156,7 +164,7 @@ public struct _StringBuffer {
156164
}
157165

158166
/// A past-the-end pointer for this buffer's available storage.
159-
var capacityEnd: UnsafeMutablePointer<_RawByte> {
167+
var capacityEnd: UnsafeMutableRawPointer {
160168
return start + _storage.value.byteCapacity
161169
}
162170

@@ -181,11 +189,11 @@ public struct _StringBuffer {
181189
// two separate phases. Operations with one-phase growth should use
182190
// "grow()," below.
183191
func hasCapacity(
184-
_ cap: Int, forSubRange r: Range<UnsafePointer<_RawByte>>
192+
_ cap: Int, forSubRange r: Range<UnsafeRawPointer>
185193
) -> Bool {
186194
// The substring to be grown could be pointing in the middle of this
187195
// _StringBuffer.
188-
let offset = (r.lowerBound - UnsafePointer(start)) >> elementShift
196+
let offset = (r.lowerBound - UnsafeRawPointer(start)) >> elementShift
189197
return cap + offset <= capacity
190198
}
191199

@@ -202,13 +210,14 @@ public struct _StringBuffer {
202210
@inline(__always)
203211
@discardableResult
204212
mutating func grow(
205-
oldBounds bounds: Range<UnsafePointer<_RawByte>>, newUsedCount: Int
213+
oldBounds bounds: Range<UnsafeRawPointer>, newUsedCount: Int
206214
) -> Bool {
207215
var newUsedCount = newUsedCount
208216
// The substring to be grown could be pointing in the middle of this
209217
// _StringBuffer. Adjust the size so that it covers the imaginary
210218
// substring from the start of the buffer to `oldUsedEnd`.
211-
newUsedCount += (bounds.lowerBound - UnsafePointer(start)) >> elementShift
219+
newUsedCount
220+
+= (bounds.lowerBound - UnsafeRawPointer(start)) >> elementShift
212221

213222
if _slowPath(newUsedCount > capacity) {
214223
return false
@@ -230,11 +239,14 @@ public struct _StringBuffer {
230239
// usedEnd = newUsedEnd
231240
// return true
232241
// }
233-
let usedEndPhysicalPtr =
234-
UnsafeMutablePointer<UnsafeMutablePointer<_RawByte>>(_storage._value)
235-
var expected = UnsafeMutablePointer<_RawByte>(bounds.upperBound)
242+
243+
// &StringBufferIVars.usedEnd
244+
let usedEndPhysicalPtr = _PointerToPointer(_storage._value)
245+
// Create a temp var to hold the exchanged `expected` value.
246+
var expected : UnsafeRawPointer? = bounds.upperBound
236247
if _stdlib_atomicCompareExchangeStrongPtr(
237-
object: usedEndPhysicalPtr, expected: &expected, desired: newUsedEnd) {
248+
object: usedEndPhysicalPtr, expected: &expected,
249+
desired: UnsafeRawPointer(newUsedEnd)) {
238250
return true
239251
}
240252

0 commit comments

Comments
 (0)