forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBridgeStorage.swift.gyb
259 lines (210 loc) · 6.86 KB
/
BridgeStorage.swift.gyb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
//===--- BridgeStorage.swift.gyb ------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Bridged types are notionally single-word beasts that either store
// an objc class or a native Swift class. We'd like to be able to
// distinguish these cases efficiently.
//
//===----------------------------------------------------------------------===//
// RUN: rm -rf %t && mkdir -p %t && %S/../../utils/gyb %s -o %t/out.swift
// RUN: %S/../../utils/line-directive %t/out.swift -- %target-build-swift -parse-stdlib %t/out.swift -o %t/a.out
// RUN: %S/../../utils/line-directive %t/out.swift -- %target-run %t/a.out
// REQUIRES: executable_test
// REQUIRES: objc_interop
import Swift
//===--- Code mimics the stdlib without using spare pointer bits ----------===//
import SwiftShims
protocol BridgeStorage {
typealias Native : AnyObject
typealias ObjC : AnyObject
init(native: Native, bits: Int)
init(native: Native)
init(objC: ObjC)
mutating func isUniquelyReferencedNative() -> Bool
mutating func isUniquelyReferenced_native_noSpareBits() -> Bool
var isNative: Bool {get}
var isObjC: Bool {get}
var nativeInstance: Native {get}
var nativeInstance_noSpareBits: Native {get}
var objCInstance: ObjC {get}
var spareBits: Int {get}
}
extension _BridgeStorage : BridgeStorage {}
struct BridgeObject<NativeType : AnyObject, ObjCType : AnyObject>
: BridgeStorage {
typealias Native = NativeType
typealias ObjC = ObjCType
init(native: Native, bits: Int) {
_sanityCheck(
bits >= 0 && bits < 2,
"BridgeObject can't store bits outside the range 0-1")
self.object = native
self.bits = UInt8(truncatingBitPattern: bits)
}
init(native: Native) {
self.object = native
self.bits = 0
}
init(objC: ObjC) {
self.object = objC
self.bits = 0
}
mutating func isUniquelyReferencedNative() -> Bool {
return _getBool(Builtin.isUnique(&object))
}
var isNative: Bool {
return _swift_usesNativeSwiftReferenceCounting_nonNull(
UnsafePointer(rawObject))
}
var isObjC: Bool {
return !isNative
}
var nativeInstance: Native {
precondition(isNative)
return Builtin.bridgeFromRawPointer(rawObject)
}
var nativeInstance_noSpareBits: Native {
precondition(isNative)
precondition(spareBits == 0)
return Builtin.bridgeFromRawPointer(rawObject)
}
mutating func isUniquelyReferenced_native_noSpareBits() -> Bool {
precondition(isNative)
precondition(spareBits == 0)
return _isUnique_native(&object)
}
var objCInstance: ObjC {
precondition(isObjC)
return Builtin.bridgeFromRawPointer(rawObject)
}
var spareBits: Int {
return Int(bits)
}
var rawObject: Builtin.RawPointer {
return Builtin.bridgeToRawPointer(object)
}
// object declared mutable to be passed to isUnique.
var object: AnyObject
let bits: UInt8
}
//===----------------------------------------------------------------------===//
//===--- Testing code -----------------------------------------------------===//
//===----------------------------------------------------------------------===//
import StdlibUnittest
var allTests = TestSuite("DiscriminatedBridgeObject")
class C {
deinit {
print("bye C!")
}
}
import Foundation
func isOSAtLeast(major: Int, _ minor: Int, patch: Int = 0) -> Bool {
let vers = (majorVersion: major, minorVersion: minor, patchVersion: patch)
// isOperatingSystemAtLeastVersion() is unavailable on some OS versions.
if #available(iOS 8.0, OSX 10.10, *) {
let procInfo: AnyObject = NSProcessInfo.processInfo()
return procInfo.isOperatingSystemAtLeastVersion(
NSOperatingSystemVersion(vers)
)
}
return false
}
func expectTagged(s: NSString, _ expected: Bool) -> NSString {
#if arch(x86_64)
let mask: UInt = 0x8000000000000001
#elseif arch(arm64)
let mask: UInt = 0x8000000000000000
#else
let mask: UInt = 0
#endif
var osSupportsTaggedStrings: Bool
#if os(iOS)
// NSTaggedPointerString is enabled starting in iOS 9.0.
osSupportsTaggedStrings = isOSAtLeast(9,0)
#elseif os(tvOS) || os(watchOS)
// NSTaggedPointerString is supported in all versions of TVOS and watchOS.
osSupportsTaggedStrings = true
#elseif os(OSX)
// NSTaggedPointerString is enabled starting in OS X 10.10.
osSupportsTaggedStrings = isOSAtLeast(10,10)
#endif
let taggedStringsSupported = osSupportsTaggedStrings && mask != 0
let tagged = unsafeBitCast(s, UInt.self) & mask != 0
if taggedStringsSupported && expected == tagged {
// okay
} else if !taggedStringsSupported && !tagged {
// okay
} else {
let un = !tagged ? "un" : ""
fatalError("Unexpectedly \(un)tagged pointer for string \"\(s)\"")
}
return s
}
var taggedNSString : NSString {
return expectTagged(NSString(format: "foo"), true)
}
var unTaggedNSString : NSString {
return expectTagged("fûtbōl" as NSString, false)
}
% for Self in '_BridgeStorage', 'BridgeObject':
allTests.test("${Self}") {
typealias B = ${Self}<C,NSString>
let oy: NSString = "oy"
expectTrue(B(objC: oy).objCInstance == oy)
for i in 0..<2 {
if true {
var b = B(native: C(), bits: i)
expectFalse(b.isObjC)
expectTrue(b.isNative)
expectTrue(b.isUniquelyReferencedNative())
if i == 0 {
expectTrue(b.isUniquelyReferenced_native_noSpareBits())
}
expectEqual(i, b.spareBits)
}
if true {
let c = C()
var b = B(native: c, bits: i)
expectFalse(b.isObjC)
expectTrue(b.isNative)
expectFalse(b.isUniquelyReferencedNative())
expectEqual(i, b.spareBits)
expectTrue(b.nativeInstance === c)
if i == 0 {
expectTrue(b.nativeInstance_noSpareBits === c)
expectFalse(b.isUniquelyReferenced_native_noSpareBits())
}
}
}
var b = B(native: C(), bits: 0)
expectTrue(b.isUniquelyReferencedNative())
// Add a reference and verify that it's still native but no longer unique
var c = b
expectFalse(b.isUniquelyReferencedNative())
_fixLifetime(c) // make sure c is not killed early
let n = C()
var bb = B(native: n)
expectEqual(0, bb.spareBits)
expectTrue(bb.nativeInstance === n)
expectTrue(bb.isNative)
expectFalse(bb.isObjC)
var d = B(objC: taggedNSString)
expectFalse(d.isUniquelyReferencedNative())
expectFalse(d.isNative)
expectTrue(d.isObjC)
d = B(objC: unTaggedNSString)
expectFalse(d.isUniquelyReferencedNative())
expectFalse(d.isNative)
expectTrue(d.isObjC)
}
% end
runAllTests()