mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
169 lines
6.2 KiB
Swift
169 lines
6.2 KiB
Swift
//===----------------- 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)
|
|
}
|
|
}
|
|
}
|