Skip to content

Commit 6482c34

Browse files
author
Itai Ferber
committed
Refine inlinability of _DataStorage
1 parent 1d00e3c commit 6482c34

File tree

1 file changed

+45
-109
lines changed

1 file changed

+45
-109
lines changed

stdlib/public/Darwin/Foundation/Data.swift

Lines changed: 45 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@ internal func __NSDataIsCompact(_ data: NSData) -> Bool {
6262

6363
#endif
6464

65+
// Underlying storage representation for medium and large data.
66+
// Inlinability strategy: methods from here should not inline into InlineSlice or LargeSlice unless trivial.
6567
@usableFromInline
6668
internal final class _DataStorage {
67-
@usableFromInline
68-
static let maxSize = Int.max >> 1
69-
@usableFromInline
70-
static let vmOpsThreshold = NSPageSize() * 4
69+
@usableFromInline static let maxSize = Int.max >> 1
70+
@usableFromInline static let vmOpsThreshold = NSPageSize() * 4
7171

72-
@inlinable
72+
@inlinable // This is @inlinable as trivially forwarding, and does not escape the _DataStorage boundary layer.
7373
static func allocate(_ size: Int, _ clear: Bool) -> UnsafeMutableRawPointer? {
7474
if clear {
7575
return calloc(1, size)
@@ -78,7 +78,7 @@ internal final class _DataStorage {
7878
}
7979
}
8080

81-
@inlinable
81+
@usableFromInline // This is not @inlinable as it is a non-trivial, non-generic function.
8282
static func move(_ dest_: UnsafeMutableRawPointer, _ source_: UnsafeRawPointer?, _ num_: Int) {
8383
var dest = dest_
8484
var source = source_
@@ -95,50 +95,46 @@ internal final class _DataStorage {
9595
}
9696
}
9797

98-
@inlinable
98+
@inlinable // This is @inlinable as trivially forwarding, and does not escape the _DataStorage boundary layer.
9999
static func shouldAllocateCleared(_ size: Int) -> Bool {
100100
return (size > (128 * 1024))
101101
}
102102

103-
@usableFromInline
104-
var _bytes: UnsafeMutableRawPointer?
105-
@usableFromInline
106-
var _length: Int
107-
@usableFromInline
108-
var _capacity: Int
109-
@usableFromInline
110-
var _needToZero: Bool
111-
@usableFromInline
112-
var _deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?
113-
@usableFromInline
114-
var _offset: Int
103+
@usableFromInline var _bytes: UnsafeMutableRawPointer?
104+
@usableFromInline var _length: Int
105+
@usableFromInline var _capacity: Int
106+
@usableFromInline var _needToZero: Bool
107+
@usableFromInline var _deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?
108+
@usableFromInline var _offset: Int
115109

116-
@inlinable
110+
@inlinable // This is @inlinable as trivially computable.
117111
var bytes: UnsafeRawPointer? {
118112
return UnsafeRawPointer(_bytes)?.advanced(by: -_offset)
119113
}
120114

121-
@inlinable
115+
@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is generic and trivially forwarding.
122116
@discardableResult
123117
func withUnsafeBytes<Result>(in range: Range<Int>, apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
124118
return try apply(UnsafeRawBufferPointer(start: _bytes?.advanced(by: range.lowerBound - _offset), count: Swift.min(range.upperBound - range.lowerBound, _length)))
125119
}
126120

127-
@inlinable
121+
@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is generic and trivially forwarding.
128122
@discardableResult
129123
func withUnsafeMutableBytes<Result>(in range: Range<Int>, apply: (UnsafeMutableRawBufferPointer) throws -> Result) rethrows -> Result {
130124
return try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.upperBound - range.lowerBound, _length)))
131125
}
132126

133-
@inlinable
127+
@inlinable // This is @inlinable as trivially computable.
134128
var mutableBytes: UnsafeMutableRawPointer? {
135129
return _bytes?.advanced(by: -_offset)
136130
}
137131

138-
@inlinable
139-
var capacity: Int { return _capacity }
132+
@inlinable // This is @inlinable as trivially computable.
133+
var capacity: Int {
134+
return _capacity
135+
}
140136

141-
@inlinable
137+
@inlinable // This is @inlinable as trivially computable.
142138
var length: Int {
143139
get {
144140
return _length
@@ -148,14 +144,14 @@ internal final class _DataStorage {
148144
}
149145
}
150146

151-
@inlinable
147+
@inlinable // This is inlinable as trivially computable.
152148
var isExternallyOwned: Bool {
153149
// all _DataStorages will have some sort of capacity, because empty cases hit the .empty enum _Representation
154150
// anything with 0 capacity means that we have not allocated this pointer and concequently mutation is not ours to make.
155151
return _capacity == 0
156152
}
157153

158-
@inlinable
154+
@usableFromInline // This is not @inlinable as it is a non-trivial, non-generic function.
159155
func ensureUniqueBufferReference(growingTo newLength: Int = 0, clear: Bool = false) {
160156
guard isExternallyOwned || newLength > _capacity else { return }
161157

@@ -256,7 +252,7 @@ internal final class _DataStorage {
256252
}
257253
}
258254

259-
@inlinable
255+
@inlinable // This is @inlinable as it does not escape the _DataStorage boundary layer.
260256
func _freeBytes() {
261257
if let bytes = _bytes {
262258
if let dealloc = _deallocator {
@@ -268,13 +264,13 @@ internal final class _DataStorage {
268264
_deallocator = nil
269265
}
270266

271-
@usableFromInline
267+
@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is trivially computed.
272268
func enumerateBytes(in range: Range<Int>, _ block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Data.Index, _ stop: inout Bool) -> Void) {
273269
var stopv: Bool = false
274270
block(UnsafeBufferPointer<UInt8>(start: _bytes?.advanced(by: range.lowerBound - _offset).assumingMemoryBound(to: UInt8.self), count: Swift.min(range.upperBound - range.lowerBound, _length)), 0, &stopv)
275271
}
276272

277-
@inlinable
273+
@inlinable // This is @inlinable as it does not escape the _DataStorage boundary layer.
278274
func setLength(_ length: Int) {
279275
let origLength = _length
280276
let newLength = length
@@ -288,7 +284,7 @@ internal final class _DataStorage {
288284
_length = newLength
289285
}
290286

291-
@inlinable
287+
@inlinable // This is @inlinable as it does not escape the _DataStorage boundary layer.
292288
func append(_ bytes: UnsafeRawPointer, length: Int) {
293289
precondition(length >= 0, "Length of appending bytes must not be negative")
294290
let origLength = _length
@@ -300,72 +296,24 @@ internal final class _DataStorage {
300296
_DataStorage.move(_bytes!.advanced(by: origLength), bytes, length)
301297
}
302298

303-
// fast-path for appending directly from another data storage
304-
@inlinable
305-
func append(_ otherData: _DataStorage, startingAt start: Int, endingAt end: Int) {
306-
let otherLength = otherData.length
307-
if otherLength == 0 { return }
308-
if let bytes = otherData.bytes {
309-
append(bytes.advanced(by: start), length: end - start)
310-
}
311-
}
312-
313-
@inlinable
314-
func append(_ otherData: Data) {
315-
guard otherData.count > 0 else { return }
316-
otherData.withUnsafeBytes {
317-
append($0.baseAddress!, length: $0.count)
318-
}
319-
}
320-
321-
@inlinable
322-
func increaseLength(by extraLength: Int) {
323-
if extraLength == 0 { return }
324-
325-
let origLength = _length
326-
let newLength = origLength + extraLength
327-
if _capacity < newLength || _bytes == nil {
328-
ensureUniqueBufferReference(growingTo: newLength, clear: true)
329-
} else if _needToZero {
330-
memset(_bytes!.advanced(by: origLength), 0, extraLength)
331-
}
332-
_length = newLength
333-
}
334-
335-
@inlinable
299+
@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is trivially computed.
336300
func get(_ index: Int) -> UInt8 {
337301
return _bytes!.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee
338302
}
339303

340-
@inlinable
304+
@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is trivially computed.
341305
func set(_ index: Int, to value: UInt8) {
342306
ensureUniqueBufferReference()
343307
_bytes!.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee = value
344308
}
345309

346-
@inlinable
310+
@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is trivially computed.
347311
func copyBytes(to pointer: UnsafeMutableRawPointer, from range: Range<Int>) {
348312
let offsetPointer = UnsafeRawBufferPointer(start: _bytes?.advanced(by: range.lowerBound - _offset), count: Swift.min(range.upperBound - range.lowerBound, _length))
349313
UnsafeMutableRawBufferPointer(start: pointer, count: range.upperBound - range.lowerBound).copyMemory(from: offsetPointer)
350314
}
351315

352-
@inlinable
353-
func replaceBytes(in range: NSRange, with bytes: UnsafeRawPointer?) {
354-
if range.length == 0 { return }
355-
if _length < range.location + range.length {
356-
let newLength = range.location + range.length
357-
if _capacity < newLength {
358-
ensureUniqueBufferReference(growingTo: newLength, clear: false)
359-
}
360-
_length = newLength
361-
} else {
362-
ensureUniqueBufferReference()
363-
}
364-
_DataStorage.move(_bytes!.advanced(by: range.location - _offset), bytes!, range.length)
365-
366-
}
367-
368-
@inlinable
316+
@usableFromInline // This is not @inlinable as it is a non-trivial, non-generic function.
369317
func replaceBytes(in range_: NSRange, with replacementBytes: UnsafeRawPointer?, length replacementLength: Int) {
370318
let range = NSRange(location: range_.location - _offset, length: range_.length)
371319
let currentLength = _length
@@ -398,7 +346,7 @@ internal final class _DataStorage {
398346
}
399347
}
400348

401-
@inlinable
349+
@usableFromInline // This is not @inlinable as it is a non-trivial, non-generic function.
402350
func resetBytes(in range_: Range<Int>) {
403351
let range = NSRange(location: range_.lowerBound - _offset, length: range_.upperBound - range_.lowerBound)
404352
if range.length == 0 { return }
@@ -414,12 +362,7 @@ internal final class _DataStorage {
414362
memset(_bytes!.advanced(by: range.location), 0, range.length)
415363
}
416364

417-
@inlinable
418-
convenience init() {
419-
self.init(capacity: 0)
420-
}
421-
422-
@usableFromInline
365+
@usableFromInline // This is not @inlinable as a non-trivial, non-convenience initializer.
423366
init(length: Int) {
424367
precondition(length < _DataStorage.maxSize)
425368
var capacity = (length < 1024 * 1024 * 1024) ? length + (length >> 2) : length
@@ -436,8 +379,8 @@ internal final class _DataStorage {
436379
setLength(length)
437380
}
438381

439-
@usableFromInline
440-
init(capacity capacity_: Int) {
382+
@usableFromInline // This is not @inlinable as a non-convience initializer.
383+
init(capacity capacity_: Int = 0) {
441384
var capacity = capacity_
442385
precondition(capacity < _DataStorage.maxSize)
443386
if _DataStorage.vmOpsThreshold <= capacity {
@@ -450,7 +393,7 @@ internal final class _DataStorage {
450393
_offset = 0
451394
}
452395

453-
@usableFromInline
396+
@usableFromInline // This is not @inlinable as a non-convience initializer.
454397
init(bytes: UnsafeRawPointer?, length: Int) {
455398
precondition(length < _DataStorage.maxSize)
456399
_offset = 0
@@ -478,7 +421,7 @@ internal final class _DataStorage {
478421
}
479422
}
480423

481-
@usableFromInline
424+
@usableFromInline // This is not @inlinable as a non-convience initializer.
482425
init(bytes: UnsafeMutableRawPointer?, length: Int, copy: Bool, deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?, offset: Int) {
483426
precondition(length < _DataStorage.maxSize)
484427
_offset = offset
@@ -522,7 +465,7 @@ internal final class _DataStorage {
522465
}
523466
}
524467

525-
@usableFromInline
468+
@usableFromInline // This is not @inlinable as a non-convience initializer.
526469
init(immutableReference: NSData, offset: Int) {
527470
_offset = offset
528471
_bytes = UnsafeMutableRawPointer(mutating: immutableReference.bytes)
@@ -534,7 +477,7 @@ internal final class _DataStorage {
534477
}
535478
}
536479

537-
@usableFromInline
480+
@usableFromInline // This is not @inlinable as a non-convience initializer.
538481
init(mutableReference: NSMutableData, offset: Int) {
539482
_offset = offset
540483
_bytes = mutableReference.mutableBytes
@@ -546,7 +489,7 @@ internal final class _DataStorage {
546489
}
547490
}
548491

549-
@usableFromInline
492+
@usableFromInline // This is not @inlinable as a non-convience initializer.
550493
init(customReference: NSData, offset: Int) {
551494
_offset = offset
552495
_bytes = UnsafeMutableRawPointer(mutating: customReference.bytes)
@@ -558,7 +501,7 @@ internal final class _DataStorage {
558501
}
559502
}
560503

561-
@usableFromInline
504+
@usableFromInline // This is not @inlinable as a non-convience initializer.
562505
init(customMutableReference: NSMutableData, offset: Int) {
563506
_offset = offset
564507
_bytes = customMutableReference.mutableBytes
@@ -574,35 +517,28 @@ internal final class _DataStorage {
574517
_freeBytes()
575518
}
576519

577-
@inlinable
520+
@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is trivially computed.
578521
func mutableCopy(_ range: Range<Int>) -> _DataStorage {
579522
return _DataStorage(bytes: _bytes?.advanced(by: range.lowerBound - _offset), length: range.upperBound - range.lowerBound, copy: true, deallocator: nil, offset: range.lowerBound)
580523
}
581524

582-
@inlinable
525+
@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is generic and trivially computed.
583526
func withInteriorPointerReference<T>(_ range: Range<Int>, _ work: (NSData) throws -> T) rethrows -> T {
584527
if range.isEmpty {
585528
return try work(NSData()) // zero length data can be optimized as a singleton
586529
}
587530
return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound - _offset), length: range.upperBound - range.lowerBound, freeWhenDone: false))
588531
}
589532

590-
// This is used to create bridged Datas into Objective-C contexts, the class name is private and should not be emitted into clients.
591-
// Consequently this should never be inlined.
533+
@inline(never) // This is not @inlinable to avoid emission of the private `__NSSwiftData` class name into clients.
592534
@usableFromInline
593-
@inline(never)
594535
func bridgedReference(_ range: Range<Int>) -> NSData {
595536
if range.isEmpty {
596537
return NSData() // zero length data can be optimized as a singleton
597538
}
598539

599540
return __NSSwiftData(backing: self, range: range)
600541
}
601-
602-
@inlinable
603-
func subdata(in range: Range<Data.Index>) -> Data {
604-
return Data(bytes: _bytes!.advanced(by: range.lowerBound - _offset), count: range.upperBound - range.lowerBound)
605-
}
606542
}
607543

608544
// NOTE: older runtimes called this _NSSwiftData. The two must

0 commit comments

Comments
 (0)