Skip to content

Commit 2356b07

Browse files
committed
[Test] Add two lexical lifetime verification tests.
Verify that lexical-lifetimes and copy-propagation interact correctly to keep objects named by variables alive in a couple interesting cases: unsafe pointers, synchronization point calls.
1 parent 1ed3ce3 commit 2356b07

File tree

1 file changed

+108
-6
lines changed

1 file changed

+108
-6
lines changed

validation-test/SILOptimizer/lexical-lifetimes.swift

Lines changed: 108 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,64 @@ class D {
2121
}
2222
}
2323

24+
class DataWrapper {
25+
26+
var pointer: UnsafeMutableRawBufferPointer
27+
28+
init(count: Int) {
29+
pointer = UnsafeMutableRawBufferPointer.allocate(byteCount: count, alignment: MemoryLayout<Int>.alignment)
30+
}
31+
32+
var bytes: UnsafeMutableRawBufferPointer { return pointer }
33+
34+
deinit {
35+
pointer.deallocate()
36+
}
37+
}
38+
39+
var fileHandleMap: [Int32 : String] = [:]
40+
41+
func openTheFile(_ path: String) -> Int32 {
42+
let fd: Int32 = 42
43+
assert(fileHandleMap[fd] == nil)
44+
fileHandleMap[fd] = path
45+
return fd
46+
}
47+
48+
func closeTheFile(_ fd: Int32) {
49+
fileHandleMap.removeValue(forKey: fd)
50+
}
51+
52+
func writeToTheFile(_ fd: Int32) {
53+
assert(fileHandleMap[fd] != nil)
54+
}
55+
56+
class FileHandleWrapper {
57+
58+
var handle: Int32? = nil
59+
60+
func open(path: String) {
61+
let fd = openTheFile(path)
62+
if fd >= 0 {
63+
handle = fd
64+
}
65+
}
66+
67+
func close() {
68+
if let fd = handle {
69+
closeTheFile(fd)
70+
handle = nil
71+
}
72+
}
73+
74+
deinit {
75+
if let fd = handle {
76+
closeTheFile(fd)
77+
}
78+
}
79+
}
80+
81+
2482
// =============================================================================
2583
// = Declarations }} =
2684
// =============================================================================
@@ -29,27 +87,71 @@ class D {
2987
// = Tests {{ =
3088
// =============================================================================
3189

32-
func test_localLetKeepsObjectAliveBeyondCallToClassWithWeakReference() {
90+
func test_localLet_keepsObjectAliveBeyondCallToClassWithWeakReference() {
3391
let d = D()
3492
let c = C(d)
35-
// CHECK: cWillFoo{{.*}} test_localLetKeepsObjectAliveBeyondCallToClassWithWeakReference
93+
// CHECK: cWillFoo{{.*}} test_localLet_keepsObjectAliveBeyondCallToClassWithWeakReference
3694
c.foo(#function)
3795
}
3896

39-
func test_localVarKeepsObjectAliveBeyondCallToClassWithWeakReference() {
97+
func test_localVar_keepsObjectAliveBeyondCallToClassWithWeakReference() {
4098
var d = D()
4199
let c = C(d)
42-
// CHECK: cWillFoo{{.*}} test_localVarKeepsObjectAliveBeyondCallToClassWithWeakReference
100+
// CHECK: cWillFoo{{.*}} test_localVar_keepsObjectAliveBeyondCallToClassWithWeakReference
43101
c.foo(#function)
44102
}
45103

104+
func test_localLet_keepsObjectAliveBeyondCallToClassWithPointer_doit(_ input: [UInt8]) {
105+
let data = DataWrapper(count: input.count)
106+
data.bytes.copyBytes(from: input)
107+
}
108+
func test_localLet_keepsObjectAliveBeyondCallToClassWithPointer() {
109+
test_localLet_keepsObjectAliveBeyondCallToClassWithPointer_doit([1,2,3,4,50])
110+
}
111+
112+
func test_localVar_keepsObjectAliveBeyondCallToClassWithPointer_doit(_ input: [UInt8]) {
113+
let data = DataWrapper(count: input.count)
114+
data.bytes.copyBytes(from: input)
115+
}
116+
func test_localVar_keepsObjectAliveBeyondCallToClassWithPointer() {
117+
test_localVar_keepsObjectAliveBeyondCallToClassWithPointer_doit([1,2,3,4,50])
118+
}
119+
120+
func test_localLet_keepsObjectAliveBeyondCallToSynchronizationPointFunction_doit(_ path: String) {
121+
var file = FileHandleWrapper()
122+
file.open(path: path)
123+
// Retrieving 'fd' is the last use of 'file'
124+
guard let fd = file.handle else { return }
125+
// 'fd' has now been closed. The subsequent write will fail.
126+
writeToTheFile(fd)
127+
}
128+
func test_localLet_keepsObjectAliveBeyondCallToSynchronizationPointFunction() {
129+
test_localLet_keepsObjectAliveBeyondCallToSynchronizationPointFunction_doit("blue")
130+
}
131+
132+
func test_localVar_keepsObjectAliveBeyondCallToSynchronizationPointFunction_doit(_ path: String) {
133+
var file = FileHandleWrapper()
134+
file.open(path: path)
135+
// Retrieving 'fd' is the last use of 'file'
136+
guard let fd = file.handle else { return }
137+
// 'fd' has now been closed. The subsequent write will fail.
138+
writeToTheFile(fd)
139+
}
140+
func test_localVar_keepsObjectAliveBeyondCallToSynchronizationPointFunction() {
141+
test_localVar_keepsObjectAliveBeyondCallToSynchronizationPointFunction_doit("blue")
142+
}
143+
46144
// =============================================================================
47145
// = Tests }} =
48146
// =============================================================================
49147

50148
func run() {
51-
test_localLetKeepsObjectAliveBeyondCallToClassWithWeakReference()
52-
test_localVarKeepsObjectAliveBeyondCallToClassWithWeakReference()
149+
test_localLet_keepsObjectAliveBeyondCallToClassWithWeakReference()
150+
test_localVar_keepsObjectAliveBeyondCallToClassWithWeakReference()
151+
test_localLet_keepsObjectAliveBeyondCallToClassWithPointer()
152+
test_localVar_keepsObjectAliveBeyondCallToClassWithPointer()
153+
test_localLet_keepsObjectAliveBeyondCallToSynchronizationPointFunction()
154+
test_localVar_keepsObjectAliveBeyondCallToSynchronizationPointFunction()
53155
}
54156

55157
run()

0 commit comments

Comments
 (0)