-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathcustom_rr_abi.swift
86 lines (69 loc) · 2.82 KB
/
custom_rr_abi.swift
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
// RUN: %target-run-simple-swift(-import-objc-header %S/Inputs/custom_rr_abi_utilities.h)
// REQUIRES: CPU=arm64 || CPU=arm64e
// REQUIRES: executable_test
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime
import StdlibUnittest
// A class that can provider a retainable pointer and determine whether it's
// been retained or released. This creates a helper object that will be retained
// or released. We don't attempt to clean up the helper so it leaks if not released,
// but this is only used for this one test so that's OK.
class RetainReleaseChecker {
var pointerValue: UnsafeMutableRawPointer
private class Helper {}
private weak var weakRef: Helper?
private let originalRetainCount: UInt
init() {
do {
// Make a helper object, retain it so it stays alive, and put it into
// pointerValue and weakRef.
let helper = Helper()
pointerValue = Unmanaged.passRetained(helper).toOpaque()
weakRef = helper
}
// Record the original retain count before anything happens. Then we can
// detect changes without needing to know exactly what the count is supposed
// to be.
originalRetainCount = _getRetainCount(weakRef!)
}
// If helper was retained, then weakRef will still point to it, and the retain
// count will have increased.
var retained: Bool {
weakRef != nil && _getRetainCount(weakRef!) > originalRetainCount
}
// weakRef is the only reference we had to the helper, aside from the retain we put
// on it to create pointerValue. If helper was released, then it will be destroyed
// and weakRef will be nil.
var released: Bool {
weakRef == nil
}
}
var CustomRRABITestSuite = TestSuite("CustomRRABI")
CustomRRABITestSuite.test("retain") {
foreachRRFunction { function, cname, register, isRetain in
let name = String(cString: cname!)
let fullname = "\(name)_x\(register)"
// Create a set of RR checker objects.
var checkers = (0..<NUM_REGS).map{ _ in RetainReleaseChecker() }
// Fill out a registers array with the pointers from the RR checkers.
var regs: [UnsafeMutableRawPointer?] = checkers.map{ $0.pointerValue }
// Call the RR function.
function!(®s)
// Make sure all the checkers report what they're supposed to. All registers
// aside from `register` should be untouched, and `register` should have been
// either retained or released.
for (i, checker) in checkers.enumerated() {
if i == register {
if isRetain != 0 {
expectTrue(checker.retained, "\(fullname) must retain x\(i)")
} else {
expectTrue(checker.released, "\(fullname) must release x\(i)")
}
} else {
expectFalse(checker.retained, "\(fullname) must not retain x\(i)")
expectFalse(checker.released, "\(fullname) must not retain x\(i)")
}
}
}
}
runAllTests()