mirror of
https://github.com/apple/swift.git
synced 2026-06-20 15:42:51 +02:00
453277eb74
Functions like withUnsafeBufferPointer are, by themselves, safe to call. It's only the operations on the unsafe pointers passed into the closure that are the safety issue. This was the intent spelled out in SE-0458 but was not fully realized in the library. Fixes rdar://174519372.
365 lines
12 KiB
Swift
365 lines
12 KiB
Swift
//===----------------------------------------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// This file contains Swift wrappers for functions defined in the C++ runtime.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SwiftShims
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Atomics
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@_transparent
|
|
public // @testable
|
|
func _stdlib_atomicCompareExchangeStrongPtr(
|
|
object target: UnsafeMutablePointer<UnsafeRawPointer?>,
|
|
expected: UnsafeMutablePointer<UnsafeRawPointer?>,
|
|
desired: UnsafeRawPointer?
|
|
) -> Bool {
|
|
// We use Builtin.Word here because Builtin.RawPointer can't be nil.
|
|
let (oldValue, won) = unsafe Builtin.cmpxchg_seqcst_seqcst_Word(
|
|
target._rawValue,
|
|
UInt(bitPattern: expected.pointee)._builtinWordValue,
|
|
UInt(bitPattern: desired)._builtinWordValue)
|
|
unsafe expected.pointee = UnsafeRawPointer(bitPattern: Int(oldValue))
|
|
return Bool(won)
|
|
}
|
|
|
|
/// Atomic compare and exchange of `UnsafeMutablePointer<T>` with sequentially
|
|
/// consistent memory ordering. Precise semantics are defined in C++11 or C11.
|
|
///
|
|
/// - Warning: This operation is extremely tricky to use correctly because of
|
|
/// writeback semantics.
|
|
///
|
|
/// It is best to use it directly on an
|
|
/// `UnsafeMutablePointer<UnsafeMutablePointer<T>>` that is known to point
|
|
/// directly to the memory where the value is stored.
|
|
///
|
|
/// In a call like this:
|
|
///
|
|
/// _stdlib_atomicCompareExchangeStrongPtr(&foo.property1.property2, ...)
|
|
///
|
|
/// you need to manually make sure that:
|
|
///
|
|
/// - all properties in the chain are physical (to make sure that no writeback
|
|
/// happens; the compare-and-exchange instruction should operate on the
|
|
/// shared memory); and
|
|
///
|
|
/// - the shared memory that you are accessing is located inside a heap
|
|
/// allocation (a class instance property, a `_BridgingBuffer`, a pointer to
|
|
/// an `Array` element etc.)
|
|
///
|
|
/// If the conditions above are not met, the code will still compile, but the
|
|
/// compare-and-exchange instruction will operate on the writeback buffer, and
|
|
/// you will get a *race* while doing writeback into shared memory.
|
|
@_transparent
|
|
public // @testable
|
|
func _stdlib_atomicCompareExchangeStrongPtr<T>(
|
|
object target: UnsafeMutablePointer<UnsafeMutablePointer<T>>,
|
|
expected: UnsafeMutablePointer<UnsafeMutablePointer<T>>,
|
|
desired: UnsafeMutablePointer<T>
|
|
) -> Bool {
|
|
let rawTarget = unsafe UnsafeMutableRawPointer(target).assumingMemoryBound(
|
|
to: Optional<UnsafeRawPointer>.self)
|
|
let rawExpected = unsafe UnsafeMutableRawPointer(expected).assumingMemoryBound(
|
|
to: Optional<UnsafeRawPointer>.self)
|
|
return unsafe _stdlib_atomicCompareExchangeStrongPtr(
|
|
object: rawTarget,
|
|
expected: rawExpected,
|
|
desired: UnsafeRawPointer(desired))
|
|
}
|
|
|
|
/// Atomic compare and exchange of `UnsafeMutablePointer<T>` with sequentially
|
|
/// consistent memory ordering. Precise semantics are defined in C++11 or C11.
|
|
///
|
|
/// - Warning: This operation is extremely tricky to use correctly because of
|
|
/// writeback semantics.
|
|
///
|
|
/// It is best to use it directly on an
|
|
/// `UnsafeMutablePointer<UnsafeMutablePointer<T>>` that is known to point
|
|
/// directly to the memory where the value is stored.
|
|
///
|
|
/// In a call like this:
|
|
///
|
|
/// _stdlib_atomicCompareExchangeStrongPtr(&foo.property1.property2, ...)
|
|
///
|
|
/// you need to manually make sure that:
|
|
///
|
|
/// - all properties in the chain are physical (to make sure that no writeback
|
|
/// happens; the compare-and-exchange instruction should operate on the
|
|
/// shared memory); and
|
|
///
|
|
/// - the shared memory that you are accessing is located inside a heap
|
|
/// allocation (a class instance property, a `_BridgingBuffer`, a pointer to
|
|
/// an `Array` element etc.)
|
|
///
|
|
/// If the conditions above are not met, the code will still compile, but the
|
|
/// compare-and-exchange instruction will operate on the writeback buffer, and
|
|
/// you will get a *race* while doing writeback into shared memory.
|
|
@_transparent
|
|
public // @testable
|
|
func _stdlib_atomicCompareExchangeStrongPtr<T>(
|
|
object target: UnsafeMutablePointer<UnsafeMutablePointer<T>?>,
|
|
expected: UnsafeMutablePointer<UnsafeMutablePointer<T>?>,
|
|
desired: UnsafeMutablePointer<T>?
|
|
) -> Bool {
|
|
let rawTarget = unsafe UnsafeMutableRawPointer(target).assumingMemoryBound(
|
|
to: Optional<UnsafeRawPointer>.self)
|
|
let rawExpected = unsafe UnsafeMutableRawPointer(expected).assumingMemoryBound(
|
|
to: Optional<UnsafeRawPointer>.self)
|
|
return unsafe _stdlib_atomicCompareExchangeStrongPtr(
|
|
object: rawTarget,
|
|
expected: rawExpected,
|
|
desired: UnsafeRawPointer(desired))
|
|
}
|
|
|
|
@_transparent
|
|
@discardableResult
|
|
@_unavailableInEmbedded
|
|
public // @testable
|
|
func _stdlib_atomicInitializeARCRef(
|
|
object target: UnsafeMutablePointer<AnyObject?>,
|
|
desired: AnyObject
|
|
) -> Bool {
|
|
// Note: this assumes that AnyObject? is layout-compatible with a RawPointer
|
|
// that simply points to the same memory.
|
|
var expected: UnsafeRawPointer? = nil
|
|
let unmanaged = unsafe Unmanaged.passRetained(desired)
|
|
let desiredPtr = unsafe unmanaged.toOpaque()
|
|
let rawTarget = unsafe UnsafeMutableRawPointer(target).assumingMemoryBound(
|
|
to: Optional<UnsafeRawPointer>.self)
|
|
let wonRace = withUnsafeMutablePointer(to: &expected) {
|
|
unsafe _stdlib_atomicCompareExchangeStrongPtr(
|
|
object: rawTarget, expected: $0, desired: desiredPtr
|
|
)
|
|
}
|
|
if !wonRace {
|
|
// Some other thread initialized the value. Balance the retain that we
|
|
// performed on 'desired'.
|
|
unsafe unmanaged.release()
|
|
}
|
|
return wonRace
|
|
}
|
|
|
|
@_transparent
|
|
@_unavailableInEmbedded
|
|
public // @testable
|
|
func _stdlib_atomicLoadARCRef(
|
|
object target: UnsafeMutablePointer<AnyObject?>
|
|
) -> AnyObject? {
|
|
let value = Builtin.atomicload_seqcst_Word(target._rawValue)
|
|
if let unwrapped = unsafe UnsafeRawPointer(bitPattern: Int(value)) {
|
|
return unsafe Unmanaged<AnyObject>.fromOpaque(unwrapped).takeUnretainedValue()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
@_transparent
|
|
@_alwaysEmitIntoClient
|
|
@discardableResult
|
|
public func _stdlib_atomicAcquiringInitializeARCRef<T: AnyObject>(
|
|
object target: UnsafeMutablePointer<T?>,
|
|
desired: __owned T
|
|
) -> Unmanaged<T> {
|
|
// Note: this assumes that AnyObject? is layout-compatible with a RawPointer
|
|
// that simply points to the same memory, and that `nil` is represented by an
|
|
// all-zero bit pattern.
|
|
let unmanaged = unsafe Unmanaged.passRetained(desired)
|
|
let desiredPtr = unsafe unmanaged.toOpaque()
|
|
|
|
let (value, won) = Builtin.cmpxchg_acqrel_acquire_Word(
|
|
target._rawValue,
|
|
0._builtinWordValue,
|
|
Builtin.ptrtoint_Word(desiredPtr._rawValue))
|
|
|
|
if Bool(won) { return unsafe unmanaged }
|
|
|
|
// Some other thread initialized the value before us. Balance the retain that
|
|
// we performed on 'desired', and return what we loaded.
|
|
unsafe unmanaged.release()
|
|
let ptr = UnsafeRawPointer(Builtin.inttoptr_Word(value))
|
|
return unsafe Unmanaged<T>.fromOpaque(ptr)
|
|
}
|
|
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public func _stdlib_atomicAcquiringLoadARCRef<T: AnyObject>(
|
|
object target: UnsafeMutablePointer<T?>
|
|
) -> Unmanaged<T>? {
|
|
let value = Builtin.atomicload_acquire_Word(target._rawValue)
|
|
if Int(value) == 0 { return nil }
|
|
let opaque = UnsafeRawPointer(Builtin.inttoptr_Word(value))
|
|
return unsafe Unmanaged<T>.fromOpaque(opaque)
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Conversion of primitive types to `String`
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@inlinable
|
|
internal func _rawPointerToString(_ value: Builtin.RawPointer) -> String {
|
|
var result = _uint64ToString(
|
|
UInt64(UInt(bitPattern: UnsafeRawPointer(value))),
|
|
radix: 16,
|
|
uppercase: false
|
|
)
|
|
for _ in unsafe 0..<(2 * MemoryLayout<UnsafeRawPointer>.size - result.utf16.count) {
|
|
result = "0" + result
|
|
}
|
|
return "0x" + result
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
// At runtime, these classes are derived from `__SwiftNativeNSXXXBase`,
|
|
// which are derived from `NSXXX`.
|
|
//
|
|
// The @swift_native_objc_runtime_base attribute
|
|
// allows us to subclass an Objective-C class and still use the fast Swift
|
|
// memory allocator.
|
|
//
|
|
// NOTE: older runtimes called these _SwiftNativeNSXXX. The two must
|
|
// coexist, so they were renamed. The old names must not be used in the
|
|
// new runtime.
|
|
|
|
@_fixed_layout
|
|
@usableFromInline
|
|
@objc @_swift_native_objc_runtime_base(__SwiftNativeNSArrayBase)
|
|
internal class __SwiftNativeNSArray {
|
|
@inlinable
|
|
@nonobjc
|
|
internal init() {}
|
|
// @objc public init(coder: AnyObject) {}
|
|
@inlinable
|
|
deinit {}
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
extension __SwiftNativeNSArray: Sendable {}
|
|
|
|
@_fixed_layout
|
|
@usableFromInline
|
|
@objc @_swift_native_objc_runtime_base(__SwiftNativeNSMutableArrayBase)
|
|
internal class _SwiftNativeNSMutableArray {
|
|
@inlinable
|
|
@nonobjc
|
|
internal init() {}
|
|
// @objc public init(coder: AnyObject) {}
|
|
@inlinable
|
|
deinit {}
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
extension _SwiftNativeNSMutableArray: Sendable {}
|
|
|
|
@_fixed_layout
|
|
@usableFromInline
|
|
@objc @_swift_native_objc_runtime_base(__SwiftNativeNSDictionaryBase)
|
|
internal class __SwiftNativeNSDictionary {
|
|
@nonobjc
|
|
internal init() {}
|
|
@objc public init(coder: AnyObject) {}
|
|
deinit {}
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
extension __SwiftNativeNSDictionary: Sendable {}
|
|
|
|
@_fixed_layout
|
|
@usableFromInline
|
|
@objc @_swift_native_objc_runtime_base(__SwiftNativeNSSetBase)
|
|
internal class __SwiftNativeNSSet {
|
|
@nonobjc
|
|
internal init() {}
|
|
@objc public init(coder: AnyObject) {}
|
|
deinit {}
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
extension __SwiftNativeNSSet: Sendable {}
|
|
|
|
@objc
|
|
@_swift_native_objc_runtime_base(__SwiftNativeNSEnumeratorBase)
|
|
internal class __SwiftNativeNSEnumerator {
|
|
@nonobjc
|
|
internal init() {}
|
|
@objc public init(coder: AnyObject) {}
|
|
deinit {}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Support for reliable testing of the return-autoreleased optimization
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@objc
|
|
internal class __stdlib_ReturnAutoreleasedDummy {
|
|
@objc
|
|
internal init() {}
|
|
|
|
// Use 'dynamic' to force Objective-C dispatch, which uses the
|
|
// return-autoreleased call sequence.
|
|
@objc
|
|
internal dynamic func returnsAutoreleased(_ x: AnyObject) -> AnyObject {
|
|
return x
|
|
}
|
|
}
|
|
|
|
/// This function ensures that the return-autoreleased optimization works.
|
|
///
|
|
/// On some platforms (for example, x86_64), the first call to
|
|
/// `objc_autoreleaseReturnValue` will always autorelease because it would fail
|
|
/// to verify the instruction sequence in the caller. On x86_64 certain PLT
|
|
/// entries would be still pointing to the resolver function, and sniffing
|
|
/// the call sequence would fail.
|
|
///
|
|
/// This code should live in the core stdlib dylib because PLT tables are
|
|
/// separate for each dylib.
|
|
///
|
|
/// Call this function in a fresh autorelease pool.
|
|
public func _stdlib_initializeReturnAutoreleased() {
|
|
#if arch(x86_64)
|
|
// On x86_64 it is sufficient to perform one cycle of return-autoreleased
|
|
// call sequence in order to initialize all required PLT entries.
|
|
let dummy = __stdlib_ReturnAutoreleasedDummy()
|
|
_ = dummy.returnsAutoreleased(dummy)
|
|
#endif
|
|
}
|
|
#else
|
|
|
|
@_fixed_layout
|
|
@usableFromInline
|
|
internal class __SwiftNativeNSArray {
|
|
@inlinable
|
|
internal init() {}
|
|
@inlinable
|
|
deinit {}
|
|
}
|
|
@_fixed_layout
|
|
@usableFromInline
|
|
internal class __SwiftNativeNSDictionary {
|
|
@inlinable
|
|
internal init() {}
|
|
@inlinable
|
|
deinit {}
|
|
}
|
|
@_fixed_layout
|
|
@usableFromInline
|
|
internal class __SwiftNativeNSSet {
|
|
@inlinable
|
|
internal init() {}
|
|
@inlinable
|
|
deinit {}
|
|
}
|
|
|
|
#endif
|