-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathOSLogTestHelper.swift
168 lines (149 loc) · 6.16 KB
/
OSLogTestHelper.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
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
//===----------------- OSLogTestHelper.swift ----------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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
//
//===----------------------------------------------------------------------===//
import ObjectiveC
// This file contains test helpers for testing the compiler diagnostics and optimizations
// of the new swift APIs for os log that accept string interpolations.
// Some functions defined in this file are marked @_optimize(none) to prevent inlining
// of string internals (such as String._StringGuts) which will interfere with
// constant evaluation and folding. Note that these functions will be inlined,
// constant evaluated, folded and optimized in the context of a caller. TODO:
// @_optimize(none) can be removed if (non-mandatory) inlining optimizations can be moved
// after serialization.
/// A function that acts like a check for whether logging is enabled in `_osLogTestHelper`.
@inline(never)
@usableFromInline
internal func isLoggingEnabled() -> Bool { true }
/// A closure that does nothing. Meant to be used as the default assertion of
/// `_osLogTestHelper`.
public let _noopClosure = { (x : String, y : UnsafeBufferPointer<UInt8>) in return }
/// A test helper that constructs a byte buffer and a format string from an
/// instance of `OSLogMessage` using the same logic as the new os log APIs,
/// and applies a given `assertion` to the constructed format string and
/// byte buffer. This function should be used only in tests.
/// - Parameters:
/// - message: An instance of `OSLogMessage` created from string interpolation
/// - assertion: A closure that takes a format string and a pointer to a
/// byte buffer and asserts a condition.
@_semantics("oslog.requires_constant_arguments")
@_transparent
@_optimize(none)
public // @testable
func _osLogTestHelper(
_ message: OSLogMessage,
assertion: (String, UnsafeBufferPointer<UInt8>) -> Void = _noopClosure
) {
// Compute static constants first so that they can be folded by
// OSLogOptimization pass.
let formatString = message.interpolation.formatString
let preamble = message.interpolation.preamble
let argumentCount = message.interpolation.argumentCount
let bufferSize = message.bufferSize
let objectCount = message.interpolation.objectArgumentCount
let stringCount = message.interpolation.stringArgumentCount
let uint32bufferSize = UInt32(bufferSize)
let argumentClosures = message.interpolation.arguments.argumentClosures
let formatStringPointer = _getGlobalStringTablePointer(formatString)
// Code that will execute at runtime.
if (!isLoggingEnabled()) {
return
}
let bufferMemory = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
// Buffer for storing NSObjects and strings to keep them alive until the
// _os_log_impl_test call completes.
let objectArguments = createStorage(capacity: objectCount, type: NSObject.self)
let stringArgumentOwners = createStorage(capacity: stringCount, type: Any.self)
var currentBufferPosition = bufferMemory
var objectArgumentsPosition = objectArguments
var stringArgumentOwnersPosition = stringArgumentOwners
serialize(preamble, at: ¤tBufferPosition)
serialize(argumentCount, at: ¤tBufferPosition)
argumentClosures.forEach {
$0(¤tBufferPosition,
&objectArgumentsPosition,
&stringArgumentOwnersPosition)
}
_os_log_impl_test(
assertion,
formatString,
formatStringPointer,
bufferMemory,
uint32bufferSize)
// The following operation extends the lifetime of objectArguments and
// stringArgumentOwners till this point. This is necessary because the
// assertion is passed internal pointers to the objects/strings stored
// in these arrays, as in the actual os log implementation.
destroyStorage(objectArguments, count: objectCount)
destroyStorage(stringArgumentOwners, count: stringCount)
bufferMemory.deallocate()
}
/// A function that pretends to be _os_log_impl.
@inline(never)
@usableFromInline
internal func _os_log_impl_test(
_ assertion: (String, UnsafeBufferPointer<UInt8>) -> Void,
_ formatString: String,
_ formatStringPointer: UnsafePointer<CChar>,
_ bufferMemory: UnsafeMutablePointer<UInt8>,
_ bufferSize: UInt32
) {
assertion(
formatString,
UnsafeBufferPointer(
start: UnsafePointer(bufferMemory),
count: Int(bufferSize)))
}
/// A function that pretends to be os_signpost(.animationBegin, ...). The purpose
/// of this function is to test whether the OSLogOptimization pass works properly
/// on the special case of animation begin signposts.
@_transparent
public func _osSignpostAnimationBeginTestHelper(
_ format: AnimationFormatString.MyLogMessage,
_ arguments: CVarArg...
) {
_animationBeginSignpostHelper(formatStringPointer: format.formatStringPointer,
arguments: arguments)
}
@usableFromInline
internal func _animationBeginSignpostHelper(
formatStringPointer: UnsafePointer<CChar>,
arguments: [CVarArg]
) {}
// A namespace for utilities specific to os_signpost animation tests.
public enum AnimationFormatString {
@inlinable
@_optimize(none)
@_semantics("constant_evaluable")
internal static func constructOSLogInterpolation(
_ formatString: String
) -> OSLogInterpolation {
var s = OSLogInterpolation(literalCapacity: 1, interpolationCount: 0)
s.formatString += formatString
s.formatString += " isAnimation=YES"
return s
}
@frozen
@_semantics("oslog.message.type")
public struct MyLogMessage : ExpressibleByStringLiteral {
@usableFromInline
var formatStringPointer: UnsafePointer<CChar>
@_transparent
public init(stringLiteral value: String) {
let message =
OSLogTestHelper.OSLogMessage(
stringInterpolation:
constructOSLogInterpolation(
value))
let formatString = message.interpolation.formatString
formatStringPointer = _getGlobalStringTablePointer(formatString)
}
}
}