|
| 1 | +//===--- BridgeStorage.swift.gyb ------------------------------------------===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See http://swift.org/LICENSE.txt for license information |
| 9 | +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | +// |
| 13 | +// Bridged types are notionally single-word beasts that either store |
| 14 | +// an objc class or a native Swift class. We'd like to be able to |
| 15 | +// distinguish these cases efficiently. |
| 16 | +// |
| 17 | +//===----------------------------------------------------------------------===// |
| 18 | +// RUN: rm -rf %t && mkdir -p %t && %S/../../utils/gyb %s -o %t/out.swift |
| 19 | +// RUN: %S/../../utils/line-directive %t/out.swift -- %target-build-swift -parse-stdlib %t/out.swift -o %t/a.out |
| 20 | +// RUN: %S/../../utils/line-directive %t/out.swift -- %target-run %t/a.out |
| 21 | +// REQUIRES: executable_test |
| 22 | + |
| 23 | +// REQUIRES: objc_interop |
| 24 | + |
| 25 | +import Swift |
| 26 | + |
| 27 | +//===--- Code mimics the stdlib without using spare pointer bits ----------===// |
| 28 | +import SwiftShims |
| 29 | + |
| 30 | +protocol BridgeStorage { |
| 31 | + typealias Native : AnyObject |
| 32 | + typealias ObjC : AnyObject |
| 33 | + |
| 34 | + init(native: Native, bits: Int) |
| 35 | + init(native: Native) |
| 36 | + init(objC: ObjC) |
| 37 | + |
| 38 | + mutating func isUniquelyReferencedNative() -> Bool |
| 39 | + mutating func isUniquelyReferenced_native_noSpareBits() -> Bool |
| 40 | + var isNative: Bool {get} |
| 41 | + var isObjC: Bool {get} |
| 42 | + var nativeInstance: Native {get} |
| 43 | + var nativeInstance_noSpareBits: Native {get} |
| 44 | + var objCInstance: ObjC {get} |
| 45 | + var spareBits: Int {get} |
| 46 | +} |
| 47 | + |
| 48 | +extension _BridgeStorage : BridgeStorage {} |
| 49 | + |
| 50 | + |
| 51 | +//===----------------------------------------------------------------------===// |
| 52 | +//===--- Testing code -----------------------------------------------------===// |
| 53 | +//===----------------------------------------------------------------------===// |
| 54 | +import StdlibUnittest |
| 55 | +var allTests = TestSuite("DiscriminatedBridgeObject") |
| 56 | + |
| 57 | +class C { |
| 58 | + deinit { |
| 59 | + print("bye C!") |
| 60 | + } |
| 61 | +} |
| 62 | +import Foundation |
| 63 | + |
| 64 | +func isOSAtLeast(major: Int, _ minor: Int, patch: Int = 0) -> Bool { |
| 65 | + let vers = (majorVersion: major, minorVersion: minor, patchVersion: patch) |
| 66 | + // isOperatingSystemAtLeastVersion() is unavailable on some OS versions. |
| 67 | + if #available(iOS 8.0, OSX 10.10, *) { |
| 68 | + let procInfo: AnyObject = NSProcessInfo.processInfo() |
| 69 | + return procInfo.isOperatingSystemAtLeastVersion( |
| 70 | + NSOperatingSystemVersion(vers) |
| 71 | + ) |
| 72 | + } |
| 73 | + |
| 74 | + return false |
| 75 | +} |
| 76 | + |
| 77 | +func expectTagged(s: NSString, _ expected: Bool) -> NSString { |
| 78 | +#if arch(x86_64) |
| 79 | + let mask: UInt = 0x8000000000000001 |
| 80 | +#elseif arch(arm64) |
| 81 | + let mask: UInt = 0x8000000000000000 |
| 82 | +#else |
| 83 | + let mask: UInt = 0 |
| 84 | +#endif |
| 85 | + |
| 86 | + var osSupportsTaggedStrings: Bool |
| 87 | +#if os(iOS) |
| 88 | + // NSTaggedPointerString is enabled starting in iOS 9.0. |
| 89 | + osSupportsTaggedStrings = isOSAtLeast(9,0) |
| 90 | +#elseif os(tvOS) || os(watchOS) |
| 91 | + // NSTaggedPointerString is supported in all versions of TVOS and watchOS. |
| 92 | + osSupportsTaggedStrings = true |
| 93 | +#elseif os(OSX) |
| 94 | + // NSTaggedPointerString is enabled starting in OS X 10.10. |
| 95 | + osSupportsTaggedStrings = isOSAtLeast(10,10) |
| 96 | +#endif |
| 97 | + |
| 98 | + let taggedStringsSupported = osSupportsTaggedStrings && mask != 0 |
| 99 | + |
| 100 | + let tagged = unsafeBitCast(s, UInt.self) & mask != 0 |
| 101 | + |
| 102 | + if taggedStringsSupported && expected == tagged { |
| 103 | + // okay |
| 104 | + } else if !taggedStringsSupported && !tagged { |
| 105 | + // okay |
| 106 | + } else { |
| 107 | + let un = !tagged ? "un" : "" |
| 108 | + fatalError("Unexpectedly \(un)tagged pointer for string \"\(s)\"") |
| 109 | + } |
| 110 | + |
| 111 | + return s |
| 112 | +} |
| 113 | + |
| 114 | +var taggedNSString : NSString { |
| 115 | + return expectTagged(NSString(format: "foo"), true) |
| 116 | +} |
| 117 | + |
| 118 | +var unTaggedNSString : NSString { |
| 119 | + return expectTagged("fûtbōl" as NSString, false) |
| 120 | +} |
| 121 | + |
| 122 | +% for Self in ['_BridgeStorage']: |
| 123 | +allTests.test("${Self}") { |
| 124 | + typealias B = ${Self}<C,NSString> |
| 125 | + |
| 126 | + let oy: NSString = "oy" |
| 127 | + expectTrue(B(objC: oy).objCInstance == oy) |
| 128 | + |
| 129 | + for i in 0..<2 { |
| 130 | + if true { |
| 131 | + var b = B(native: C(), bits: i) |
| 132 | + expectFalse(b.isObjC) |
| 133 | + expectTrue(b.isNative) |
| 134 | + expectTrue(b.isUniquelyReferencedNative()) |
| 135 | + if i == 0 { |
| 136 | + expectTrue(b.isUniquelyReferenced_native_noSpareBits()) |
| 137 | + } |
| 138 | + expectEqual(i, b.spareBits) |
| 139 | + } |
| 140 | + |
| 141 | + if true { |
| 142 | + let c = C() |
| 143 | + var b = B(native: c, bits: i) |
| 144 | + expectFalse(b.isObjC) |
| 145 | + expectTrue(b.isNative) |
| 146 | + expectFalse(b.isUniquelyReferencedNative()) |
| 147 | + expectEqual(i, b.spareBits) |
| 148 | + expectTrue(b.nativeInstance === c) |
| 149 | + if i == 0 { |
| 150 | + expectTrue(b.nativeInstance_noSpareBits === c) |
| 151 | + expectFalse(b.isUniquelyReferenced_native_noSpareBits()) |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + } |
| 156 | + |
| 157 | + var b = B(native: C(), bits: 0) |
| 158 | + expectTrue(b.isUniquelyReferencedNative()) |
| 159 | + |
| 160 | + // Add a reference and verify that it's still native but no longer unique |
| 161 | + var c = b |
| 162 | + expectFalse(b.isUniquelyReferencedNative()) |
| 163 | + _fixLifetime(c) // make sure c is not killed early |
| 164 | + |
| 165 | + let n = C() |
| 166 | + var bb = B(native: n) |
| 167 | + expectEqual(0, bb.spareBits) |
| 168 | + expectTrue(bb.nativeInstance === n) |
| 169 | + expectTrue(bb.isNative) |
| 170 | + expectFalse(bb.isObjC) |
| 171 | + |
| 172 | + var d = B(objC: taggedNSString) |
| 173 | + expectFalse(d.isUniquelyReferencedNative()) |
| 174 | + expectFalse(d.isNative) |
| 175 | + expectTrue(d.isObjC) |
| 176 | + |
| 177 | + d = B(objC: unTaggedNSString) |
| 178 | + expectFalse(d.isUniquelyReferencedNative()) |
| 179 | + expectFalse(d.isNative) |
| 180 | + expectTrue(d.isObjC) |
| 181 | + |
| 182 | +} |
| 183 | +% end |
| 184 | + |
| 185 | +runAllTests() |
| 186 | + |
0 commit comments