18
18
19
19
@available ( macOS 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
20
20
public struct Logger {
21
+ @usableFromInline
21
22
internal let logObject : OSLog
22
23
23
24
/// Create a custom OS log object.
@@ -30,8 +31,16 @@ public struct Logger {
30
31
logObject = OSLog . default
31
32
}
32
33
34
+ // Functions defined below are marked @_optimize(none) to prevent inlining
35
+ // of string internals (such as String._StringGuts) which will interfere with
36
+ // constant evaluation and folding. Note that these functions will be inlined,
37
+ // constant evaluated/folded and optimized in the context of a caller.
38
+
33
39
/// Log a string interpolation at a given level. The level is `default` if
34
40
/// it is not specified.
41
+ @inlinable
42
+ @_semantics ( " oslog.log " )
43
+ @_optimize ( none)
35
44
public func log( level: OSLogType = . default, _ message: OSLogMessage ) {
36
45
osLog ( logObject, level, message)
37
46
}
@@ -44,28 +53,46 @@ public struct Logger {
44
53
/// extract the format string, serialize the arguments to a byte buffer,
45
54
/// and pass them to the OS logging system.
46
55
@available ( macOS 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
56
+ @usableFromInline
57
+ @_transparent
58
+ @_optimize ( none)
47
59
internal func osLog(
48
60
_ logObject: OSLog ,
49
61
_ logLevel: OSLogType ,
50
62
_ message: OSLogMessage
51
63
) {
52
- guard logObject. isEnabled ( type: logLevel) else { return }
53
-
64
+ // Compute static constants first so that they can be folded by
65
+ // OSLogOptimization pass.
66
+ let formatString = message. interpolation. formatString
67
+ let preamble = message. interpolation. preamble
68
+ let argumentCount = message. interpolation. argumentCount
54
69
let bufferSize = message. bufferSize
55
- let bufferMemory = UnsafeMutablePointer< UInt8> . allocate( capacity: bufferSize)
56
- var builder = OSLogByteBufferBuilder ( bufferMemory)
57
70
58
- message. serializeArguments ( into: & builder)
71
+ // Code that will execute at runtime.
72
+ let arguments = message. interpolation. arguments
73
+ formatString. withCString { cFormatString in
74
+
75
+ guard logObject. isEnabled ( type: logLevel) else { return }
76
+
77
+ // Ideally, we could stack allocate the buffer as it is local to this
78
+ // function and also its size is a compile-time constant.
79
+ let bufferMemory =
80
+ UnsafeMutablePointer< UInt8> . allocate( capacity: bufferSize)
81
+ var builder = OSLogByteBufferBuilder ( bufferMemory)
82
+
83
+ builder. serialize ( preamble)
84
+ builder. serialize ( argumentCount)
85
+ arguments. serialize ( into: & builder)
59
86
60
- message. formatString. withCString { cFormatString in
61
87
___os_log_impl ( UnsafeMutableRawPointer ( mutating: #dsohandle) ,
62
88
logObject,
63
89
logLevel,
64
90
cFormatString,
65
91
bufferMemory,
66
92
UInt32 ( bufferSize) )
93
+
94
+ bufferMemory. deallocate ( )
67
95
}
68
- bufferMemory. deallocate ( )
69
96
}
70
97
71
98
/// A test helper that constructs a byte buffer and a format string from an
@@ -76,18 +103,31 @@ internal func osLog(
76
103
/// - message: An instance of `OSLogMessage` created from string interpolation
77
104
/// - assertion: A closure that takes a format string and a pointer to a
78
105
/// byte buffer and asserts a condition.
106
+ @inlinable
107
+ @_semantics ( " oslog.log.test_helper " )
108
+ @_optimize ( none)
79
109
public // @testable
80
110
func _checkFormatStringAndBuffer(
81
111
_ message: OSLogMessage ,
82
112
with assertion: ( String , UnsafeBufferPointer < UInt8 > ) -> Void
83
113
) {
114
+ // Compute static constants first so that they can be folded by
115
+ // OSLogOptimization pass.
116
+ let formatString = message. interpolation. formatString
117
+ let preamble = message. interpolation. preamble
118
+ let argumentCount = message. interpolation. argumentCount
84
119
let bufferSize = message. bufferSize
120
+
121
+ // Code that will execute at runtime.
85
122
let bufferMemory = UnsafeMutablePointer< UInt8> . allocate( capacity: bufferSize)
86
123
var builder = OSLogByteBufferBuilder ( bufferMemory)
87
- message. serializeArguments ( into: & builder)
124
+
125
+ builder. serialize ( preamble)
126
+ builder. serialize ( argumentCount)
127
+ message. interpolation. arguments. serialize ( into: & builder)
88
128
89
129
assertion (
90
- message . formatString,
130
+ formatString,
91
131
UnsafeBufferPointer ( start: UnsafePointer ( bufferMemory) , count: bufferSize) )
92
132
93
133
bufferMemory. deallocate ( )
0 commit comments