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
|
//===----------------- OSLogNSObjectType.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
//
//===----------------------------------------------------------------------===//
// This file defines extensions for interpolating NSObject into an OSLogMessage.
// It defines `appendInterpolation` function for NSObject type. It also defines
// extensions for generating an os_log format string for NSObjects (using the
// format specifier %@) and for serializing NSObject into the argument buffer
// passed to os_log ABIs.
//
// The `appendInterpolation` function defined in this file accept privacy
// options along with the interpolated expression as shown below:
//
// "\(x, privacy: .public\)"
import ObjectiveC
extension OSLogInterpolation {
/// Defines interpolation for expressions of type NSObject.
///
/// Do not call this function directly. It will be called automatically when interpolating
/// a value of type `NSObject` in the string interpolations passed to the log APIs.
///
/// - Parameters:
/// - argumentObject: The interpolated expression of type NSObject, which is autoclosured.
/// - privacy: A privacy qualifier which is either private or public. It is auto-inferred by default.
@_semantics("constant_evaluable")
@inlinable
@_optimize(none)
@_semantics("oslog.requires_constant_arguments")
public mutating func appendInterpolation(
_ argumentObject: @autoclosure @escaping () -> NSObject,
privacy: OSLogPrivacy = .auto
) {
guard argumentCount < maxOSLogArgumentCount else { return }
formatString += getNSObjectFormatSpecifier(privacy)
// If the privacy has a mask, append the mask argument, which is a constant payload.
if privacy.hasMask {
appendMaskArgument(privacy)
}
addNSObjectHeaders(privacy)
arguments.append(argumentObject)
argumentCount += 1
objectArgumentCount += 1
}
/// Update preamble and append argument headers based on the parameters of
/// the interpolation.
@_semantics("constant_evaluable")
@inlinable
@_optimize(none)
internal mutating func addNSObjectHeaders(_ privacy: OSLogPrivacy) {
// Append argument header.
let header = getArgumentHeader(privacy: privacy, type: .object)
arguments.append(header)
// Append number of bytes needed to serialize the argument.
let byteCount = pointerSizeInBytes()
arguments.append(UInt8(byteCount))
// Increment total byte size by the number of bytes needed for this
// argument, which is the sum of the byte size of the argument and
// two bytes needed for the headers.
totalBytesForSerializingArguments += byteCount + 2
preamble = getUpdatedPreamble(privacy: privacy, isScalar: false)
}
/// Construct an os_log format specifier from the given parameters.
/// This function must be constant evaluable and all its arguments
/// must be known at compile time.
@inlinable
@_semantics("constant_evaluable")
@_effects(readonly)
@_optimize(none)
internal func getNSObjectFormatSpecifier(_ privacy: OSLogPrivacy) -> String {
var specifier = "%"
if let privacySpecifier = privacy.privacySpecifier {
specifier += "{"
specifier += privacySpecifier
specifier += "}"
}
specifier += "@"
return specifier
}
}
extension OSLogArguments {
/// Append an (autoclosured) interpolated expression of type NSObject, passed to
/// `OSLogMessage.appendInterpolation`, to the array of closures tracked
/// by this instance.
@_semantics("constant_evaluable")
@inlinable
@_optimize(none)
internal mutating func append(_ value: @escaping () -> NSObject) {
argumentClosures.append({ (position, objectArguments, _) in
serialize(value(), at: &position, storingObjectsIn: &objectArguments)
})
}
}
/// Serialize an NSObject pointer at the buffer location pointed by
/// `bufferPosition`.
@_alwaysEmitIntoClient
@inline(__always)
internal func serialize(
_ object: NSObject,
at bufferPosition: inout ByteBufferPointer,
storingObjectsIn objectArguments: inout ObjectStorage<NSObject>
) {
let byteCount = pointerSizeInBytes();
let dest =
UnsafeMutableRawBufferPointer(start: bufferPosition, count: byteCount)
// Get the address of this NSObject as an UnsafeRawPointer.
let objectAddress = Unmanaged.passUnretained(object).toOpaque()
// Copy the address into the destination buffer. Note that the input NSObject
// is kept alive until the os_log ABI call completes by storing in the
// objectArguments.
withUnsafeBytes(of: objectAddress) { dest.copyMemory(from: $0) }
bufferPosition += byteCount
// This object could be newly created by the auto-closure. Therefore, make
// sure it is alive until the log call completes.
initializeAndAdvance(&objectArguments, to: object)
}
|