Skip to content

Commit a41484e

Browse files
authored
Add UnsafeRawPointer type and API. (#3677)
* Add UnsafeRawPointer type and API. As proposed in SE-0107: UnsafeRawPointer. https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md The fundamental difference between Unsafe[Mutable]RawPointer and Unsafe[Mutable]Pointer<Pointee> is simply that the former is used for "untyped" memory access, and the later is used for "typed" memory access. Let's refer to these as "raw pointers" and "typed pointers". Because operations on raw pointers access untyped memory, the compiler cannot make assumptions about the underlying type of memory and must be conservative. With operations on typed pointers, the compiler may make strict assumptions about the type of the underlying memory, which allows more aggressive optimization. Memory can only be accessed by a typed pointer when it is currently bound to the Pointee type. Memory can be bound to type `T` via: - `UnsafePointer<T>.allocate(capacity: n)` - `UnsafePointer<Pointee>.withMemoryRebound(to: T.self, capacity: n) {...}` - `UnsafeMutableRawPointer.initializeMemory(as: T.self, at: i, count: n, to: x)` - `UnsafeMutableRawPointer.initializeMemory(as: T.self, from: p, count: n)` - `UnsafeMutableRawPointer.moveInitializeMemory(as: T.self, from: p, count: n)` - `UnsafeMutableRawPointer.bindMemory(to: T.self, capacity: n)` Mangle UnsafeRawPointer as predefined substitution 'Sv' for Swift void pointer ([urp] are taken). * UnsafeRawPointer minor improvements. Incorporate Dmitri's feedback. Properly use a _memmove helper. Add load/storeBytes alignment precondition checks. Reword comments. Demangler tests. * Fix name mangling test cases. * Fix bind_memory specialization.
1 parent 3bc1c78 commit a41484e

21 files changed

+1030
-92
lines changed

docs/ABI.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,8 @@ Predefined Substitutions
12211221
known-nominal-type ::= 'Sd' // Swift.Float64
12221222
known-nominal-type ::= 'Sf' // Swift.Float32
12231223
known-nominal-type ::= 'Si' // Swift.Int
1224+
known-nominal-type ::= 'SV' // Swift.UnsafeRawPointer
1225+
known-nominal-type ::= 'Sv' // Swift.UnsafeMutableRawPointer
12241226
known-nominal-type ::= 'SP' // Swift.UnsafePointer
12251227
known-nominal-type ::= 'Sp' // Swift.UnsafeMutablePointer
12261228
known-nominal-type ::= 'SQ' // Swift.ImplicitlyUnwrappedOptional

include/swift/SIL/SILCloner.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ SILCloner<ImplClass>::visitBindMemoryInst(BindMemoryInst *Inst) {
796796
getBuilder().createBindMemory(getOpLocation(Inst->getLoc()),
797797
getOpValue(Inst->getBase()),
798798
getOpValue(Inst->getIndex()),
799-
Inst->getBoundType()));
799+
getOpType(Inst->getBoundType())));
800800
}
801801

802802
template<typename ImplClass>

lib/AST/Mangle.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,6 +1392,12 @@ bool Mangler::tryMangleStandardSubstitution(const NominalTypeDecl *decl) {
13921392
} else if (name == "Float") {
13931393
Buffer << "Sf";
13941394
return true;
1395+
} else if (name == "UnsafeRawPointer") {
1396+
Buffer << "SV";
1397+
return true;
1398+
} else if (name == "UnsafeMutableRawPointer") {
1399+
Buffer << "Sv";
1400+
return true;
13951401
} else if (name == "UnsafePointer") {
13961402
Buffer << "SP";
13971403
return true;

lib/Basic/Demangle.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,10 @@ class Demangler {
10371037
return createSwiftType(Node::Kind::Structure, "Float");
10381038
if (Mangled.nextIf('i'))
10391039
return createSwiftType(Node::Kind::Structure, "Int");
1040+
if (Mangled.nextIf('V'))
1041+
return createSwiftType(Node::Kind::Structure, "UnsafeRawPointer");
1042+
if (Mangled.nextIf('v'))
1043+
return createSwiftType(Node::Kind::Structure, "UnsafeMutableRawPointer");
10401044
if (Mangled.nextIf('P'))
10411045
return createSwiftType(Node::Kind::Structure, "UnsafePointer");
10421046
if (Mangled.nextIf('p'))

lib/Basic/Remangle.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ bool Remangler::trySubstitution(Node *node, SubstitutionEntry &entry) {
354354
SUCCESS_IF_DECLNAME_IS("Double", "Sd");
355355
SUCCESS_IF_DECLNAME_IS("Float", "Sf");
356356
SUCCESS_IF_DECLNAME_IS("Int", "Si");
357+
SUCCESS_IF_DECLNAME_IS("UnsafeRawPointer", "SV");
358+
SUCCESS_IF_DECLNAME_IS("UnsafeMutableRawPointer", "Sv");
357359
SUCCESS_IF_DECLNAME_IS("UnsafePointer", "SP");
358360
SUCCESS_IF_DECLNAME_IS("UnsafeMutablePointer", "Sp");
359361
SUCCESS_IF_DECLNAME_IS("UnsafeBufferPointer", "SR");

stdlib/public/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ set(SWIFTLIB_ESSENTIAL
121121
UnsafeBitMap.swift
122122
UnsafeBufferPointer.swift.gyb
123123
UnsafePointer.swift.gyb
124+
UnsafeRawPointer.swift.gyb
124125
WriteBackMutableSlice.swift
125126
)
126127

stdlib/public/core/CTypes.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,24 @@ func _memcpy(
199199
/*volatile:*/ false._value)
200200
}
201201

202+
/// Copy `count` bytes of memory from `src` into `dest`.
203+
///
204+
/// The memory regions `source..<source + count` and
205+
/// `dest..<dest + count` may overlap.
206+
func _memmove(
207+
dest destination: UnsafeMutableRawPointer,
208+
src: UnsafeRawPointer,
209+
size: UInt
210+
) {
211+
let dest = destination._rawValue
212+
let src = src._rawValue
213+
let size = UInt64(size)._value
214+
Builtin.int_memmove_RawPointer_RawPointer_Int64(
215+
dest, src, size,
216+
/*alignment:*/ Int32()._value,
217+
/*volatile:*/ false._value)
218+
}
219+
202220
@available(*, unavailable, renamed: "OpaquePointer")
203221
public struct COpaquePointer {}
204222

stdlib/public/core/GroupInfo.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
"Pointer": [
116116
"Pointer.swift",
117117
"UnsafePointer.swift",
118+
"UnsafeRawPointer.swift",
118119
"UnsafeBufferPointer.swift"
119120
],
120121
"Protocols": [

stdlib/public/core/ManagedBuffer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public class ManagedBuffer<Header, Element>
117117
/// Destroy the stored Header.
118118
deinit {
119119
ManagedBufferPointer(self).withUnsafeMutablePointerToHeader {
120-
$0.deinitialize()
120+
_ = $0.deinitialize()
121121
}
122122
}
123123

stdlib/public/core/UnsafePointer.swift.gyb

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,10 @@ public struct ${Self}<Pointee>
129129
static public func allocate(capacity count: Int)
130130
-> UnsafeMutablePointer<Pointee> {
131131
let size = strideof(Pointee.self) * count
132-
return UnsafeMutablePointer(
133-
Builtin.allocRaw(size._builtinWordValue, Builtin.alignof(Pointee.self)))
132+
let rawPtr =
133+
Builtin.allocRaw(size._builtinWordValue, Builtin.alignof(Pointee.self))
134+
Builtin.bindMemory(rawPtr, count._builtinWordValue, Pointee.self)
135+
return UnsafeMutablePointer(rawPtr)
134136
}
135137
136138
/// Deallocate uninitialized memory allocated for `count` instances
@@ -169,7 +171,8 @@ public struct ${Self}<Pointee>
169171
/// Initialize `self.pointee` with `count` consecutive copies of `newValue`
170172
///
171173
/// - Precondition: The pointee is not initialized.
172-
/// `count` is non-negative.
174+
///
175+
/// - Precondition: `count` is non-negative.
173176
///
174177
/// - Postcondition: The pointee is initialized; the value should eventually
175178
/// be destroyed or moved from to avoid leaks.
@@ -262,8 +265,7 @@ public struct ${Self}<Pointee>
262265
}
263266
264267
/// Initialize memory starting at `self` with `count` `Pointee`s
265-
/// beginning at `source`, proceeding forward from `self` to `self +
266-
/// count - 1`.
268+
/// beginning at `source`.
267269
///
268270
/// - Precondition: `count >= 0`
269271
///
@@ -320,7 +322,7 @@ public struct ${Self}<Pointee>
320322
/// are uninitialized.
321323
public func moveAssign(from source: ${Self}, count: Int) {
322324
_debugPrecondition(
323-
count >= 0, "${Self}.moveAssignFrom with negative count")
325+
count >= 0, "${Self}.moveAssign(from:) with negative count")
324326
_debugPrecondition(
325327
self + count <= source || source + count <= self,
326328
"moveAssign overlapping range")
@@ -336,18 +338,40 @@ public struct ${Self}<Pointee>
336338
/// De-initialize the `count` `Pointee`s starting at `self`, returning
337339
/// their memory to an uninitialized state.
338340
///
341+
/// Returns an UnsafeMutableRawPointer to this memory.
342+
///
339343
/// - Precondition: The `Pointee`s at `self..<self + count` are
340344
/// initialized.
341345
///
342346
/// - Postcondition: The memory is uninitialized.
343-
public func deinitialize(count: Int = 1) {
347+
@discardableResult
348+
public func deinitialize(count: Int = 1) -> UnsafeMutableRawPointer {
344349
_debugPrecondition(count >= 0, "${Self}.deinitialize with negative count")
345350
// FIXME: optimization should be implemented, where if the `count` value
346351
// is 1, the `Builtin.destroy(Pointee.self, _rawValue)` gets called.
347352
Builtin.destroyArray(Pointee.self, _rawValue, count._builtinWordValue)
353+
return UnsafeMutableRawPointer(self)
348354
}
349355
% end
350356
357+
/// Rebind memory at `self` to type `T` with capacity to hold `count` adjacent
358+
/// `T` values while executing the `body` closure. After executing the
359+
/// closure, rebind memory back to `Pointee`.
360+
///
361+
/// - Precondition: Type 'T' is layout compatible with type 'Pointee'.
362+
///
363+
/// - Precondition: The memory `self..<self + count * strideof(T.self)`
364+
/// is bound to `Pointee`.
365+
public func withMemoryRebound<T, Result>(to: T.Type, capacity count: Int,
366+
_ body: @noescape (UnsafeMutablePointer<T>) throws -> Result
367+
) rethrows -> Result {
368+
Builtin.bindMemory(_rawValue, count._builtinWordValue, T.self)
369+
defer {
370+
Builtin.bindMemory(_rawValue, count._builtinWordValue, Pointee.self)
371+
}
372+
return try body(UnsafeMutablePointer<T>(_rawValue))
373+
}
374+
351375
/// Access the pointee at `self + i`.
352376
///
353377
/// - Precondition: the pointee at `self + i` is initialized.
@@ -381,7 +405,7 @@ public struct ${Self}<Pointee>
381405
/// different invocations of the same program. Do not persist the
382406
/// hash value across program runs.
383407
public var hashValue: Int {
384-
return Int(Builtin.ptrtoint_Word(_rawValue))
408+
return Int(bitPattern: self)
385409
}
386410
387411
/// Returns the next consecutive position.

0 commit comments

Comments
 (0)