Files
swift-mirror/stdlib/public/core/BridgeStorage.swift
Chris Lattner 415cd50ba2 Reduce array abstraction on apple platforms dealing with literals (#13665)
* Reduce array abstraction on apple platforms dealing with literals

Part of the ongoing quest to reduce swift array literal abstraction
penalties: make the SIL optimizer able to eliminate bridging overhead
 when dealing with array literals.

Introduce a new classify_bridge_object SIL instruction to handle the
logic of extracting platform specific bits from a Builtin.BridgeObject
value that indicate whether it contains a ObjC tagged pointer object,
or a normal ObjC object. This allows the SIL optimizer to eliminate
these, which allows constant folding a ton of code. On the example
added to test/SILOptimizer/static_arrays.swift, this results in 4x
less SIL code, and also leads to a lot more commonality between linux
and apple platform codegen when passing an array literal.

This also introduces a couple of SIL combines for patterns that occur
in the array literal passing case.
2018-01-02 15:23:48 -08:00

173 lines
5.1 KiB
Swift

//===--- BridgeStorage.swift - Discriminated storage for bridged types ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
// Types that are bridged to Objective-C need to manage an object
// that may be either some native class or the @objc Cocoa
// equivalent. _BridgeStorage discriminates between these two
// possibilities and stores a few extra bits when the stored type is
// native. It is assumed that the @objc class instance may in fact
// be a tagged pointer, and thus no extra bits may be available.
//
//===----------------------------------------------------------------------===//
import SwiftShims
@_fixed_layout
public // @testable
struct _BridgeStorage<
NativeClass: AnyObject, ObjCClass: AnyObject
> {
public // @testable
typealias Native = NativeClass
public // @testable
typealias ObjC = ObjCClass
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
init(native: Native, bits: Int) {
_sanityCheck(_usesNativeSwiftReferenceCounting(NativeClass.self))
// More bits are available on some platforms, but it's not portable
_sanityCheck(0...1 ~= bits,
"BridgeStorage can't store bits outside the range 0...1")
rawValue = _makeNativeBridgeObject(
native, UInt(bits) << _objectPointerLowSpareBitShift)
}
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
init(objC: ObjC) {
_sanityCheck(_usesNativeSwiftReferenceCounting(NativeClass.self))
rawValue = _makeObjCBridgeObject(objC)
}
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
init(native: Native) {
_sanityCheck(_usesNativeSwiftReferenceCounting(NativeClass.self))
rawValue = Builtin.reinterpretCast(native)
}
@_inlineable // FIXME(sil-serialize-all)
public // @testable
var spareBits: Int {
@inline(__always) get {
_sanityCheck(isNative)
return Int(
_nonPointerBits(rawValue) >> _objectPointerLowSpareBitShift)
}
}
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
mutating func isUniquelyReferencedNative() -> Bool {
return _isUnique(&rawValue)
}
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
mutating func isUniquelyReferencedOrPinnedNative() -> Bool {
return _isUniqueOrPinned(&rawValue)
}
@_inlineable // FIXME(sil-serialize-all)
public // @testable
var isNative: Bool {
@inline(__always) get {
let result = Builtin.classifyBridgeObject(rawValue)
return !Bool(Builtin.or_Int1(result.isObjCObject,
result.isObjCTaggedPointer))
}
}
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
func isNativeWithClearedSpareBits(_ bits: Int) -> Bool {
return (_bitPattern(rawValue) &
(_objCTaggedPointerBits | _objectPointerIsObjCBit |
(UInt(bits)) << _objectPointerLowSpareBitShift)) == 0
}
@_inlineable // FIXME(sil-serialize-all)
public // @testable
var isObjC: Bool {
@inline(__always) get {
return !isNative
}
}
@_inlineable // FIXME(sil-serialize-all)
public // @testable
var nativeInstance: Native {
@inline(__always) get {
_sanityCheck(isNative)
return Builtin.castReferenceFromBridgeObject(rawValue)
}
}
@_inlineable // FIXME(sil-serialize-all)
public // @testable
var nativeInstance_noSpareBits: Native {
@inline(__always) get {
_sanityCheck(isNative)
_sanityCheck(_nonPointerBits(rawValue) == 0)
return Builtin.reinterpretCast(rawValue)
}
}
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
mutating func isUniquelyReferenced_native_noSpareBits() -> Bool {
_sanityCheck(isNative)
return _isUnique_native(&rawValue)
}
@_inlineable // FIXME(sil-serialize-all)
@inline(__always)
public // @testable
mutating func isUniquelyReferencedOrPinned_native_noSpareBits() -> Bool {
_sanityCheck(isNative)
return _isUniqueOrPinned_native(&rawValue)
}
@_inlineable // FIXME(sil-serialize-all)
public // @testable
var objCInstance: ObjC {
@inline(__always) get {
_sanityCheck(isObjC)
return Builtin.castReferenceFromBridgeObject(rawValue)
}
}
//===--- private --------------------------------------------------------===//
@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
internal var _isTagged: Bool {
@inline(__always) get {
return Bool(Builtin.classifyBridgeObject(rawValue).isObjCTaggedPointer)
}
}
// rawValue is passed inout to _isUnique. Although its value
// is unchanged, it must appear mutable to the optimizer.
@_versioned
internal var rawValue: Builtin.BridgeObject
}