mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
467 lines
15 KiB
Swift
467 lines
15 KiB
Swift
//===----------------------------------------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://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
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@asmname("swift_stdlib_atomicCompareExchangeStrongPtr")
|
|
func _stdlib_atomicCompareExchangeStrongPtrImpl(
|
|
object target: UnsafeMutablePointer<COpaquePointer>,
|
|
expected: UnsafeMutablePointer<COpaquePointer>,
|
|
desired: COpaquePointer) -> Bool
|
|
|
|
/// 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 on the
|
|
/// shared memory); and
|
|
///
|
|
/// - the shared memory that you are accessing is located inside a heap
|
|
/// allocation (a class instance property, a `_HeapBuffer`, 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 {
|
|
return _stdlib_atomicCompareExchangeStrongPtrImpl(
|
|
object: UnsafeMutablePointer(target),
|
|
expected: UnsafeMutablePointer(expected),
|
|
desired: COpaquePointer(desired))
|
|
}
|
|
|
|
@transparent
|
|
public // @testable
|
|
func _stdlib_atomicInitializeARCRef(
|
|
object target: UnsafeMutablePointer<AnyObject?>,
|
|
desired: AnyObject) -> Bool {
|
|
var expected = COpaquePointer()
|
|
let desiredPtr = Unmanaged.passRetained(desired).toOpaque()
|
|
let wonRace = _stdlib_atomicCompareExchangeStrongPtrImpl(
|
|
object: UnsafeMutablePointer(target),
|
|
expected: &expected,
|
|
desired: desiredPtr)
|
|
if !wonRace {
|
|
// Some other thread initialized the value. Balance the retain that we
|
|
// performed on 'desired'.
|
|
Unmanaged.passUnretained(desired).release()
|
|
}
|
|
return wonRace
|
|
}
|
|
|
|
% for bits in [ 32, 64 ]:
|
|
|
|
@asmname("swift_stdlib_atomicCompareExchangeStrongUInt${bits}")
|
|
func _stdlib_atomicCompareExchangeStrongUInt${bits}(
|
|
object target: UnsafeMutablePointer<UInt${bits}>,
|
|
expected: UnsafeMutablePointer<UInt${bits}>,
|
|
desired: UInt${bits}) -> Bool
|
|
|
|
func _stdlib_atomicCompareExchangeStrongInt${bits}(
|
|
object target: UnsafeMutablePointer<Int${bits}>,
|
|
expected: UnsafeMutablePointer<Int${bits}>,
|
|
desired: Int${bits}) -> Bool {
|
|
return _stdlib_atomicCompareExchangeStrongUInt${bits}(
|
|
object: UnsafeMutablePointer(target),
|
|
expected: UnsafeMutablePointer(expected),
|
|
desired: UInt${bits}(bitPattern: desired))
|
|
}
|
|
|
|
@asmname("swift_stdlib_atomicStoreUInt${bits}")
|
|
func _swift_stdlib_atomicStoreUInt${bits}(
|
|
object target: UnsafeMutablePointer<UInt${bits}>,
|
|
desired: UInt${bits})
|
|
|
|
func _swift_stdlib_atomicStoreInt${bits}(
|
|
object target: UnsafeMutablePointer<Int${bits}>,
|
|
desired: Int${bits}) {
|
|
return _swift_stdlib_atomicStoreUInt${bits}(
|
|
object: UnsafeMutablePointer(target),
|
|
desired: UInt${bits}(bitPattern: desired))
|
|
}
|
|
|
|
@asmname("swift_stdlib_atomicLoadUInt${bits}")
|
|
func _swift_stdlib_atomicLoadUInt${bits}(
|
|
object target: UnsafeMutablePointer<UInt${bits}>) -> UInt${bits}
|
|
|
|
func _swift_stdlib_atomicLoadInt${bits}(
|
|
object target: UnsafeMutablePointer<Int${bits}>) -> Int${bits} {
|
|
return Int${bits}(bitPattern:
|
|
_swift_stdlib_atomicLoadUInt${bits}(
|
|
object: UnsafeMutablePointer(target)))
|
|
}
|
|
|
|
// Warning: no overflow checking.
|
|
@asmname("swift_stdlib_atomicFetchAddUInt${bits}")
|
|
func _swift_stdlib_atomicFetchAddUInt${bits}(
|
|
object target: UnsafeMutablePointer<UInt${bits}>,
|
|
operand: UInt${bits}) -> UInt${bits}
|
|
|
|
// Warning: no overflow checking.
|
|
func _swift_stdlib_atomicFetchAddInt${bits}(
|
|
object target: UnsafeMutablePointer<Int${bits}>,
|
|
operand: Int${bits}) -> Int${bits} {
|
|
return Int${bits}(bitPattern:
|
|
_swift_stdlib_atomicFetchAddUInt${bits}(
|
|
object: UnsafeMutablePointer(target),
|
|
operand: UInt${bits}(bitPattern: operand)))
|
|
}
|
|
|
|
% end
|
|
|
|
func _stdlib_atomicCompareExchangeStrongInt(
|
|
object target: UnsafeMutablePointer<Int>,
|
|
expected: UnsafeMutablePointer<Int>,
|
|
desired: Int) -> Bool {
|
|
#if arch(i386) || arch(arm)
|
|
return _stdlib_atomicCompareExchangeStrongUInt32(
|
|
object: UnsafeMutablePointer(target),
|
|
expected: UnsafeMutablePointer(expected),
|
|
desired: UInt32(bitPattern: Int32(desired)))
|
|
#elseif arch(x86_64) || arch(arm64)
|
|
return _stdlib_atomicCompareExchangeStrongUInt64(
|
|
object: UnsafeMutablePointer(target),
|
|
expected: UnsafeMutablePointer(expected),
|
|
desired: UInt64(bitPattern: Int64(desired)))
|
|
#endif
|
|
}
|
|
|
|
func _swift_stdlib_atomicStoreInt(
|
|
object target: UnsafeMutablePointer<Int>,
|
|
desired: Int) {
|
|
#if arch(i386) || arch(arm)
|
|
return _swift_stdlib_atomicStoreUInt32(
|
|
object: UnsafeMutablePointer(target),
|
|
desired: UInt32(bitPattern: Int32(desired)))
|
|
#elseif arch(x86_64) || arch(arm64)
|
|
return _swift_stdlib_atomicStoreUInt64(
|
|
object: UnsafeMutablePointer(target),
|
|
desired: UInt64(bitPattern: Int64(desired)))
|
|
#endif
|
|
}
|
|
|
|
@transparent
|
|
public func _swift_stdlib_atomicLoadInt(
|
|
object target: UnsafeMutablePointer<Int>) -> Int {
|
|
#if arch(i386) || arch(arm)
|
|
return Int(Int32(bitPattern:
|
|
_swift_stdlib_atomicLoadUInt32(
|
|
object: UnsafeMutablePointer(target))))
|
|
#elseif arch(x86_64) || arch(arm64)
|
|
return Int(Int64(bitPattern:
|
|
_swift_stdlib_atomicLoadUInt64(
|
|
object: UnsafeMutablePointer(target))))
|
|
#endif
|
|
}
|
|
|
|
@asmname("swift_stdlib_atomicLoadPtr")
|
|
func _swift_stdlib_atomicLoadPtrImpl(
|
|
object target: UnsafeMutablePointer<COpaquePointer>
|
|
) -> COpaquePointer
|
|
|
|
@transparent
|
|
public // @testable
|
|
func _stdlib_atomicLoadARCRef(
|
|
object target: UnsafeMutablePointer<AnyObject?>
|
|
) -> AnyObject? {
|
|
let result = _swift_stdlib_atomicLoadPtrImpl(
|
|
object: UnsafeMutablePointer(target))
|
|
if result != nil {
|
|
return Unmanaged<AnyObject>.fromOpaque(result).takeUnretainedValue()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Warning: no overflow checking.
|
|
public func _swift_stdlib_atomicFetchAddInt(
|
|
object target: UnsafeMutablePointer<Int>,
|
|
operand: Int) -> Int {
|
|
#if arch(i386) || arch(arm)
|
|
return Int(Int32(bitPattern:
|
|
_swift_stdlib_atomicFetchAddUInt32(
|
|
object: UnsafeMutablePointer(target),
|
|
operand: UInt32(bitPattern: Int32(operand)))))
|
|
#elseif arch(x86_64) || arch(arm64)
|
|
return Int(Int64(bitPattern:
|
|
_swift_stdlib_atomicFetchAddUInt64(
|
|
object: UnsafeMutablePointer(target),
|
|
operand: UInt64(bitPattern: Int64(operand)))))
|
|
#endif
|
|
}
|
|
|
|
public final class _stdlib_AtomicInt {
|
|
var _value: Int
|
|
|
|
var _valuePtr: UnsafeMutablePointer<Int> {
|
|
return UnsafeMutablePointer(_getUnsafePointerToStoredProperties(self))
|
|
}
|
|
|
|
public init(_ value: Int = 0) {
|
|
_value = value
|
|
}
|
|
|
|
public func store(desired: Int) {
|
|
return _swift_stdlib_atomicStoreInt(object: _valuePtr, desired: desired)
|
|
}
|
|
|
|
public func load() -> Int {
|
|
return _swift_stdlib_atomicLoadInt(object: _valuePtr)
|
|
}
|
|
|
|
public func fetchAndAdd(operand: Int) -> Int {
|
|
return _swift_stdlib_atomicFetchAddInt(object: _valuePtr, operand: operand)
|
|
}
|
|
|
|
public func addAndFetch(operand: Int) -> Int {
|
|
return fetchAndAdd(operand) + operand
|
|
}
|
|
|
|
public func compareExchange(
|
|
inout expected expected: Int, desired: Int
|
|
) -> Bool {
|
|
var expectedVar = expected
|
|
let result = _stdlib_atomicCompareExchangeStrongInt(
|
|
object: _valuePtr,
|
|
expected: &expectedVar,
|
|
desired: desired)
|
|
expected = expectedVar
|
|
return result
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Conversion of primitive types to `String`
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// A 32 byte buffer.
|
|
struct _Buffer32 {
|
|
var x0: UInt64 = 0
|
|
var x1: UInt64 = 0
|
|
var x2: UInt64 = 0
|
|
var x3: UInt64 = 0
|
|
}
|
|
|
|
/// A 72 byte buffer.
|
|
struct _Buffer72 {
|
|
var x0: UInt64 = 0
|
|
var x1: UInt64 = 0
|
|
var x2: UInt64 = 0
|
|
var x3: UInt64 = 0
|
|
var x4: UInt64 = 0
|
|
var x5: UInt64 = 0
|
|
var x6: UInt64 = 0
|
|
var x7: UInt64 = 0
|
|
var x8: UInt64 = 0
|
|
}
|
|
|
|
% for bits in [ 32, 64, 80 ]:
|
|
|
|
% if bits == 80:
|
|
#if arch(i386) || arch(x86_64)
|
|
% end
|
|
|
|
@asmname("swift_float${bits}ToString")
|
|
func _float${bits}ToStringImpl(
|
|
buffer: UnsafeMutablePointer<UTF8.CodeUnit>,
|
|
_ bufferLength: UWord, _ value: Float${bits}
|
|
) -> UWord
|
|
|
|
func _float${bits}ToString(value: Float${bits}) -> String {
|
|
_sanityCheck(sizeof(_Buffer32.self) == 32)
|
|
_sanityCheck(sizeof(_Buffer72.self) == 72)
|
|
|
|
var buffer = _Buffer32()
|
|
return withUnsafeMutablePointer(&buffer) {
|
|
(bufferPtr) in
|
|
let bufferUTF8Ptr = UnsafeMutablePointer<UTF8.CodeUnit>(bufferPtr)
|
|
let actualLength = _float${bits}ToStringImpl(bufferUTF8Ptr, 32, value)
|
|
return String._fromWellFormedCodeUnitSequence(
|
|
UTF8.self,
|
|
input: UnsafeBufferPointer(
|
|
start: bufferUTF8Ptr, count: Int(actualLength)))
|
|
}
|
|
}
|
|
|
|
% if bits == 80:
|
|
#endif
|
|
% end
|
|
|
|
% end
|
|
|
|
@asmname("swift_int64ToString")
|
|
func _int64ToStringImpl(
|
|
buffer: UnsafeMutablePointer<UTF8.CodeUnit>,
|
|
_ bufferLength: UWord, _ value: Int64,
|
|
_ radix: Int64, _ uppercase: Bool
|
|
) -> UWord
|
|
|
|
func _int64ToString(
|
|
value: Int64, radix: Int64 = 10, uppercase: Bool = false
|
|
) -> String {
|
|
if radix >= 10 {
|
|
var buffer = _Buffer32()
|
|
return withUnsafeMutablePointer(&buffer) {
|
|
(bufferPtr) in
|
|
let bufferUTF8Ptr = UnsafeMutablePointer<UTF8.CodeUnit>(bufferPtr)
|
|
let actualLength =
|
|
_int64ToStringImpl(bufferUTF8Ptr, 32, value, radix, uppercase)
|
|
return String._fromWellFormedCodeUnitSequence(
|
|
UTF8.self,
|
|
input: UnsafeBufferPointer(
|
|
start: bufferUTF8Ptr, count: Int(actualLength)))
|
|
}
|
|
} else {
|
|
var buffer = _Buffer72()
|
|
return withUnsafeMutablePointer(&buffer) {
|
|
(bufferPtr) in
|
|
let bufferUTF8Ptr = UnsafeMutablePointer<UTF8.CodeUnit>(bufferPtr)
|
|
let actualLength =
|
|
_int64ToStringImpl(bufferUTF8Ptr, 72, value, radix, uppercase)
|
|
return String._fromWellFormedCodeUnitSequence(
|
|
UTF8.self,
|
|
input: UnsafeBufferPointer(
|
|
start: bufferUTF8Ptr, count: Int(actualLength)))
|
|
}
|
|
}
|
|
}
|
|
|
|
@asmname("swift_uint64ToString")
|
|
func _uint64ToStringImpl(
|
|
buffer: UnsafeMutablePointer<UTF8.CodeUnit>,
|
|
_ bufferLength: UWord, _ value: UInt64, _ radix: Int64, _ uppercase: Bool
|
|
) -> UWord
|
|
|
|
public // @testable
|
|
func _uint64ToString(
|
|
value: UInt64, radix: Int64 = 10, uppercase: Bool = false
|
|
) -> String {
|
|
if radix >= 10 {
|
|
var buffer = _Buffer32()
|
|
return withUnsafeMutablePointer(&buffer) {
|
|
(bufferPtr) in
|
|
let bufferUTF8Ptr = UnsafeMutablePointer<UTF8.CodeUnit>(bufferPtr)
|
|
let actualLength =
|
|
_uint64ToStringImpl(bufferUTF8Ptr, 32, value, radix, uppercase)
|
|
return String._fromWellFormedCodeUnitSequence(
|
|
UTF8.self,
|
|
input: UnsafeBufferPointer(
|
|
start: bufferUTF8Ptr, count: Int(actualLength)))
|
|
}
|
|
} else {
|
|
var buffer = _Buffer72()
|
|
return withUnsafeMutablePointer(&buffer) {
|
|
(bufferPtr) in
|
|
let bufferUTF8Ptr = UnsafeMutablePointer<UTF8.CodeUnit>(bufferPtr)
|
|
let actualLength =
|
|
_uint64ToStringImpl(bufferUTF8Ptr, 72, value, radix, uppercase)
|
|
return String._fromWellFormedCodeUnitSequence(
|
|
UTF8.self,
|
|
input: UnsafeBufferPointer(
|
|
start: bufferUTF8Ptr, count: Int(actualLength)))
|
|
}
|
|
}
|
|
}
|
|
|
|
func _rawPointerToString(value: Builtin.RawPointer) -> String {
|
|
var result = _uint64ToString(
|
|
UInt64(unsafeBitCast(value, UWord.self)), radix: 16, uppercase: false)
|
|
for _ in 0..<(2 * sizeof(Builtin.RawPointer) - 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.
|
|
|
|
@objc @_swift_native_objc_runtime_base(_SwiftNativeNSArrayBase)
|
|
class _SwiftNativeNSArray {}
|
|
|
|
@objc @_swift_native_objc_runtime_base(_SwiftNativeNSDictionaryBase)
|
|
class _SwiftNativeNSDictionary {}
|
|
|
|
@objc @_swift_native_objc_runtime_base(_SwiftNativeNSSetBase)
|
|
class _SwiftNativeNSSet {}
|
|
|
|
@objc @_swift_native_objc_runtime_base(_SwiftNativeNSEnumeratorBase)
|
|
class _SwiftNativeNSEnumerator {}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Support for reliable testing of the return-autoreleased optimization
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@objc internal class _stdlib_ReturnAutoreleasedDummy {
|
|
// Use 'dynamic' to force Objective-C dispatch, which uses the
|
|
// return-autoreleased call sequence.
|
|
@objc dynamic func returnsAutoreleased(x: AnyObject) -> AnyObject {
|
|
return x
|
|
}
|
|
|
|
// Use 'dynamic' to prevent this call to be duplicated into other modules.
|
|
@objc dynamic func initializeReturnAutoreleased() {
|
|
// On x86_64 it is sufficient to perform one cycle of return-autorelesed
|
|
// call sequence in order to initialize all required PLT entries.
|
|
self.returnsAutoreleased(self)
|
|
}
|
|
}
|
|
|
|
/// 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() {
|
|
// _stdlib_initializeReturnAutoreleasedImpl()
|
|
#if arch(x86_64)
|
|
_stdlib_ReturnAutoreleasedDummy().initializeReturnAutoreleased()
|
|
#endif
|
|
}
|
|
#endif
|