mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Similarly to how we've always handled parameter types, we now recursively expand tuples in result types and separately determine a result convention for each result. The most important code-generation change here is that indirect results are now returned separately from each other and from any direct results. It is generally far better, when receiving an indirect result, to receive it as an independent result; the caller is much more likely to be able to directly receive the result in the address they want to initialize, rather than having to receive it in temporary memory and then copy parts of it into the target. The most important conceptual change here that clients and producers of SIL must be aware of is the new distinction between a SILFunctionType's *parameters* and its *argument list*. The former is just the formal parameters, derived purely from the parameter types of the original function; indirect results are no longer in this list. The latter includes the indirect result arguments; as always, all the indirect results strictly precede the parameters. Apply instructions and entry block arguments follow the argument list, not the parameter list. A relatively minor change is that there can now be multiple direct results, each with its own result convention. This is a minor change because I've chosen to leave return instructions as taking a single operand and apply instructions as producing a single result; when the type describes multiple results, they are implicitly bound up in a tuple. It might make sense to split these up and allow e.g. return instructions to take a list of operands; however, it's not clear what to do on the caller side, and this would be a major change that can be separated out from this already over-large patch. Unsurprisingly, the most invasive changes here are in SILGen; this requires substantial reworking of both call emission and reabstraction. It also proved important to switch several SILGen operations over to work with RValue instead of ManagedValue, since otherwise they would be forced to spuriously "implode" buffers.
536 lines
16 KiB
Swift
536 lines
16 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Customizes the result of `_reflect(x)`, where `x` is a conforming
|
|
/// type.
|
|
public protocol _Reflectable {
|
|
// The runtime has inappropriate knowledge of this protocol and how its
|
|
// witness tables are laid out. Changing this protocol requires a
|
|
// corresponding change to Reflection.cpp.
|
|
|
|
/// Returns a mirror that reflects `self`.
|
|
@warn_unused_result
|
|
func _getMirror() -> _MirrorType
|
|
}
|
|
|
|
/// A unique identifier for a class instance or metatype. This can be used by
|
|
/// reflection clients to recognize cycles in the object graph.
|
|
///
|
|
/// In Swift, only class instances and metatypes have unique identities. There
|
|
/// is no notion of identity for structs, enums, functions, or tuples.
|
|
public struct ObjectIdentifier : Hashable, Comparable {
|
|
let value: Builtin.RawPointer
|
|
|
|
/// Convert to a `UInt` that captures the full value of `self`.
|
|
///
|
|
/// Axiom: `a.uintValue == b.uintValue` iff `a == b`.
|
|
public var uintValue: UInt {
|
|
return UInt(Builtin.ptrtoint_Word(value))
|
|
}
|
|
|
|
// FIXME: Better hashing algorithm
|
|
/// The hash value.
|
|
///
|
|
/// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`.
|
|
///
|
|
/// - Note: The hash value is not guaranteed to be stable across
|
|
/// different invocations of the same program. Do not persist the
|
|
/// hash value across program runs.
|
|
public var hashValue: Int {
|
|
return Int(Builtin.ptrtoint_Word(value))
|
|
}
|
|
|
|
/// Construct an instance that uniquely identifies the class instance `x`.
|
|
public init(_ x: AnyObject) {
|
|
self.value = Builtin.bridgeToRawPointer(x)
|
|
}
|
|
|
|
/// Construct an instance that uniquely identifies the metatype `x`.
|
|
public init(_ x: Any.Type) {
|
|
self.value = unsafeBitCast(x, Builtin.RawPointer.self)
|
|
}
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func <(lhs: ObjectIdentifier, rhs: ObjectIdentifier) -> Bool {
|
|
return lhs.uintValue < rhs.uintValue
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func ==(x: ObjectIdentifier, y: ObjectIdentifier) -> Bool {
|
|
return Bool(Builtin.cmp_eq_RawPointer(x.value, y.value))
|
|
}
|
|
|
|
|
|
/// How children of this value should be presented in the IDE.
|
|
public enum _MirrorDisposition {
|
|
/// As a struct.
|
|
case Struct
|
|
/// As a class.
|
|
case Class
|
|
/// As an enum.
|
|
case Enum
|
|
/// As a tuple.
|
|
case Tuple
|
|
/// As a miscellaneous aggregate with a fixed set of children.
|
|
case Aggregate
|
|
/// As a container that is accessed by index.
|
|
case IndexContainer
|
|
/// As a container that is accessed by key.
|
|
case KeyContainer
|
|
/// As a container that represents membership of its values.
|
|
case MembershipContainer
|
|
/// As a miscellaneous container with a variable number of children.
|
|
case Container
|
|
/// An Optional which can have either zero or one children.
|
|
case Optional
|
|
/// An Objective-C object imported in Swift.
|
|
case ObjCObject
|
|
}
|
|
|
|
/// The type returned by `_reflect(x)`; supplies an API for runtime
|
|
/// reflection on `x`.
|
|
public protocol _MirrorType {
|
|
/// The instance being reflected.
|
|
var value: Any { get }
|
|
|
|
/// Identical to `value.dynamicType`.
|
|
var valueType: Any.Type { get }
|
|
|
|
/// A unique identifier for `value` if it is a class instance; `nil`
|
|
/// otherwise.
|
|
var objectIdentifier: ObjectIdentifier? { get }
|
|
|
|
/// The count of `value`'s logical children.
|
|
var count: Int { get }
|
|
|
|
/// Get a name and mirror for the `i`th logical child.
|
|
subscript(i: Int) -> (String, _MirrorType) { get }
|
|
|
|
/// A string description of `value`.
|
|
var summary: String { get }
|
|
|
|
/// A rich representation of `value` for an IDE, or `nil` if none is supplied.
|
|
var quickLookObject: PlaygroundQuickLook? { get }
|
|
|
|
/// How `value` should be presented in an IDE.
|
|
var disposition: _MirrorDisposition { get }
|
|
}
|
|
|
|
/// An entry point that can be called from C++ code to get the summary string
|
|
/// for an arbitrary object. The memory pointed to by "out" is initialized with
|
|
/// the summary string.
|
|
@warn_unused_result
|
|
@_silgen_name("swift_getSummary")
|
|
public // COMPILER_INTRINSIC
|
|
func _getSummary<T>(out: UnsafeMutablePointer<String>, x: T) {
|
|
out.initialize(String(reflecting: x))
|
|
}
|
|
|
|
/// Produce a mirror for any value. If the value's type conforms to
|
|
/// `_Reflectable`, invoke its `_getMirror()` method; otherwise, fall back
|
|
/// to an implementation in the runtime that structurally reflects values
|
|
/// of any type.
|
|
@warn_unused_result
|
|
@_silgen_name("swift_reflectAny")
|
|
public func _reflect<T>(x: T) -> _MirrorType
|
|
|
|
/// Dump an object's contents using its mirror to the specified output stream.
|
|
public func dump<T, TargetStream : OutputStreamType>(
|
|
x: T, inout _ targetStream: TargetStream,
|
|
name: String? = nil, indent: Int = 0,
|
|
maxDepth: Int = .max, maxItems: Int = .max
|
|
) -> T {
|
|
var maxItemCounter = maxItems
|
|
var visitedItems = [ObjectIdentifier : Int]()
|
|
targetStream._lock()
|
|
defer { targetStream._unlock() }
|
|
_dumpObject_unlocked(
|
|
x, name, indent, maxDepth, &maxItemCounter, &visitedItems,
|
|
&targetStream)
|
|
return x
|
|
}
|
|
|
|
/// Dump an object's contents using its mirror to standard output.
|
|
public func dump<T>(x: T, name: String? = nil, indent: Int = 0,
|
|
maxDepth: Int = .max, maxItems: Int = .max) -> T {
|
|
var stdoutStream = _Stdout()
|
|
return dump(
|
|
x, &stdoutStream, name: name, indent: indent, maxDepth: maxDepth,
|
|
maxItems: maxItems)
|
|
}
|
|
|
|
/// Dump an object's contents. User code should use dump().
|
|
internal func _dumpObject_unlocked<TargetStream : OutputStreamType>(
|
|
object: Any, _ name: String?, _ indent: Int, _ maxDepth: Int,
|
|
inout _ maxItemCounter: Int,
|
|
inout _ visitedItems: [ObjectIdentifier : Int],
|
|
inout _ targetStream: TargetStream
|
|
) {
|
|
guard maxItemCounter > 0 else { return }
|
|
maxItemCounter -= 1
|
|
|
|
for _ in 0..<indent { targetStream.write(" ") }
|
|
|
|
let mirror = Mirror(reflecting: object)
|
|
let count = mirror.children.count
|
|
let bullet = count == 0 ? "-"
|
|
: maxDepth <= 0 ? "▹" : "▿"
|
|
targetStream.write(bullet)
|
|
targetStream.write(" ")
|
|
|
|
if let nam = name {
|
|
targetStream.write(nam)
|
|
targetStream.write(": ")
|
|
}
|
|
// This takes the place of the old mirror API's 'summary' property
|
|
_dumpPrint_unlocked(object, mirror, &targetStream)
|
|
|
|
let id: ObjectIdentifier?
|
|
if let classInstance = object as? AnyObject where object.dynamicType is AnyObject.Type {
|
|
// Object is a class (but not an ObjC-bridged struct)
|
|
id = ObjectIdentifier(classInstance)
|
|
} else if let metatypeInstance = object as? Any.Type {
|
|
// Object is a metatype
|
|
id = ObjectIdentifier(metatypeInstance)
|
|
} else {
|
|
id = nil
|
|
}
|
|
if let theId = id {
|
|
if let previous = visitedItems[theId] {
|
|
targetStream.write(" #")
|
|
_print_unlocked(previous, &targetStream)
|
|
targetStream.write("\n")
|
|
return
|
|
}
|
|
let identifier = visitedItems.count
|
|
visitedItems[theId] = identifier
|
|
targetStream.write(" #")
|
|
_print_unlocked(identifier, &targetStream)
|
|
}
|
|
|
|
targetStream.write("\n")
|
|
|
|
guard maxDepth > 0 else { return }
|
|
|
|
if let superclassMirror = mirror.superclassMirror() {
|
|
_dumpSuperclass_unlocked(superclassMirror, indent + 2, maxDepth - 1, &maxItemCounter, &visitedItems, &targetStream)
|
|
}
|
|
|
|
var currentIndex = mirror.children.startIndex
|
|
for i in 0..<count {
|
|
if maxItemCounter <= 0 {
|
|
for _ in 0..<(indent+4) {
|
|
_print_unlocked(" ", &targetStream)
|
|
}
|
|
let remainder = count - i
|
|
targetStream.write("(")
|
|
_print_unlocked(remainder, &targetStream)
|
|
if i > 0 { targetStream.write(" more") }
|
|
if remainder == 1 {
|
|
targetStream.write(" child)\n")
|
|
} else {
|
|
targetStream.write(" children)\n")
|
|
}
|
|
return
|
|
}
|
|
|
|
let (name, child) = mirror.children[currentIndex]
|
|
currentIndex = currentIndex.successor()
|
|
_dumpObject_unlocked(child, name, indent + 2, maxDepth - 1,
|
|
&maxItemCounter, &visitedItems, &targetStream)
|
|
}
|
|
}
|
|
|
|
/// Dump information about an object's superclass, given a mirror reflecting
|
|
/// that superclass.
|
|
internal func _dumpSuperclass_unlocked<TargetStream : OutputStreamType>(
|
|
mirror: Mirror, _ indent: Int, _ maxDepth: Int,
|
|
inout _ maxItemCounter: Int,
|
|
inout _ visitedItems: [ObjectIdentifier : Int],
|
|
inout _ targetStream: TargetStream
|
|
) {
|
|
guard maxItemCounter > 0 else { return }
|
|
maxItemCounter -= 1
|
|
|
|
for _ in 0..<indent { targetStream.write(" ") }
|
|
|
|
let count = mirror.children.count
|
|
let bullet = count == 0 ? "-"
|
|
: maxDepth <= 0 ? "▹" : "▿"
|
|
targetStream.write(bullet)
|
|
targetStream.write(" super: ")
|
|
_debugPrint_unlocked(mirror.subjectType, &targetStream)
|
|
targetStream.write("\n")
|
|
|
|
guard maxDepth > 0 else { return }
|
|
|
|
if let superclassMirror = mirror.superclassMirror() {
|
|
_dumpSuperclass_unlocked(superclassMirror, indent + 2, maxDepth - 1,
|
|
&maxItemCounter, &visitedItems, &targetStream)
|
|
}
|
|
|
|
var currentIndex = mirror.children.startIndex
|
|
for i in 0..<count {
|
|
if maxItemCounter <= 0 {
|
|
for _ in 0..<(indent+4) {
|
|
targetStream.write(" ")
|
|
}
|
|
let remainder = count - i
|
|
targetStream.write("(")
|
|
_print_unlocked(remainder, &targetStream)
|
|
if i > 0 { targetStream.write(" more") }
|
|
if remainder == 1 {
|
|
targetStream.write(" child)\n")
|
|
} else {
|
|
targetStream.write(" children)\n")
|
|
}
|
|
return
|
|
}
|
|
|
|
let (name, child) = mirror.children[currentIndex]
|
|
currentIndex = currentIndex.successor()
|
|
_dumpObject_unlocked(child, name, indent + 2, maxDepth - 1,
|
|
&maxItemCounter, &visitedItems, &targetStream)
|
|
}
|
|
}
|
|
|
|
// -- Implementation details for the runtime's _MirrorType implementation
|
|
|
|
@_silgen_name("swift_MagicMirrorData_summary")
|
|
func _swift_MagicMirrorData_summaryImpl(
|
|
metadata: Any.Type, _ result: UnsafeMutablePointer<String>
|
|
)
|
|
|
|
public struct _MagicMirrorData {
|
|
let owner: Builtin.NativeObject
|
|
let ptr: Builtin.RawPointer
|
|
let metadata: Any.Type
|
|
|
|
var value: Any {
|
|
@_silgen_name("swift_MagicMirrorData_value")get
|
|
}
|
|
var valueType: Any.Type {
|
|
@_silgen_name("swift_MagicMirrorData_valueType")get
|
|
}
|
|
|
|
public var objcValue: Any {
|
|
@_silgen_name("swift_MagicMirrorData_objcValue")get
|
|
}
|
|
public var objcValueType: Any.Type {
|
|
@_silgen_name("swift_MagicMirrorData_objcValueType")get
|
|
}
|
|
|
|
var summary: String {
|
|
let (_, result) = _withUninitializedString {
|
|
_swift_MagicMirrorData_summaryImpl(self.metadata, $0)
|
|
}
|
|
return result
|
|
}
|
|
|
|
public func _loadValue<T>() -> T {
|
|
return Builtin.load(ptr) as T
|
|
}
|
|
}
|
|
|
|
struct _OpaqueMirror : _MirrorType {
|
|
let data: _MagicMirrorData
|
|
|
|
var value: Any { return data.value }
|
|
var valueType: Any.Type { return data.valueType }
|
|
var objectIdentifier: ObjectIdentifier? { return nil }
|
|
var count: Int { return 0 }
|
|
subscript(i: Int) -> (String, _MirrorType) {
|
|
_preconditionFailure("no children")
|
|
}
|
|
var summary: String { return data.summary }
|
|
var quickLookObject: PlaygroundQuickLook? { return nil }
|
|
var disposition: _MirrorDisposition { return .Aggregate }
|
|
}
|
|
|
|
internal struct _TupleMirror : _MirrorType {
|
|
let data: _MagicMirrorData
|
|
|
|
var value: Any { return data.value }
|
|
var valueType: Any.Type { return data.valueType }
|
|
var objectIdentifier: ObjectIdentifier? { return nil }
|
|
var count: Int {
|
|
@_silgen_name("swift_TupleMirror_count")get
|
|
}
|
|
subscript(i: Int) -> (String, _MirrorType) {
|
|
return _subscript_get(i)
|
|
}
|
|
@_silgen_name("swift_TupleMirror_subscript")
|
|
func _subscript_get<T>(i: Int) -> (T, _MirrorType)
|
|
|
|
var summary: String { return "(\(count) elements)" }
|
|
var quickLookObject: PlaygroundQuickLook? { return nil }
|
|
var disposition: _MirrorDisposition { return .Tuple }
|
|
}
|
|
|
|
struct _StructMirror : _MirrorType {
|
|
let data: _MagicMirrorData
|
|
|
|
var value: Any { return data.value }
|
|
var valueType: Any.Type { return data.valueType }
|
|
var objectIdentifier: ObjectIdentifier? { return nil }
|
|
var count: Int {
|
|
@_silgen_name("swift_StructMirror_count")get
|
|
}
|
|
subscript(i: Int) -> (String, _MirrorType) {
|
|
return _subscript_get(i)
|
|
}
|
|
@_silgen_name("swift_StructMirror_subscript")
|
|
func _subscript_get<T>(i: Int) -> (T, _MirrorType)
|
|
|
|
var summary: String {
|
|
return _typeName(valueType)
|
|
}
|
|
var quickLookObject: PlaygroundQuickLook? { return nil }
|
|
var disposition: _MirrorDisposition { return .Struct }
|
|
}
|
|
|
|
struct _EnumMirror : _MirrorType {
|
|
let data: _MagicMirrorData
|
|
|
|
var value: Any { return data.value }
|
|
var valueType: Any.Type { return data.valueType }
|
|
var objectIdentifier: ObjectIdentifier? { return nil }
|
|
var count: Int {
|
|
@_silgen_name("swift_EnumMirror_count")get
|
|
}
|
|
var caseName: UnsafePointer<CChar> {
|
|
@_silgen_name("swift_EnumMirror_caseName")get
|
|
}
|
|
subscript(i: Int) -> (String, _MirrorType) {
|
|
return _subscript_get(i)
|
|
}
|
|
@_silgen_name("swift_EnumMirror_subscript")
|
|
func _subscript_get<T>(i: Int) -> (T, _MirrorType)
|
|
|
|
var summary: String {
|
|
let maybeCaseName = String.fromCString(self.caseName)
|
|
let typeName = _typeName(valueType)
|
|
if let caseName = maybeCaseName {
|
|
return typeName + "." + caseName
|
|
}
|
|
return typeName
|
|
}
|
|
var quickLookObject: PlaygroundQuickLook? { return nil }
|
|
var disposition: _MirrorDisposition { return .Enum }
|
|
}
|
|
|
|
@warn_unused_result
|
|
@_silgen_name("swift_ClassMirror_count")
|
|
func _getClassCount(_: _MagicMirrorData) -> Int
|
|
|
|
// Like the other swift_*Mirror_subscript functions declared here and
|
|
// elsewhere, this is implemented in the runtime. The Swift CC would
|
|
// normally require the String to be returned directly and the _MirrorType
|
|
// indirectly. However, Clang isn't currently capable of doing that
|
|
// reliably because the size of String exceeds the normal direct-return
|
|
// ABI rules on most platforms. Therefore, we make this function generic,
|
|
// which has the disadvantage of passing the String type metadata as an
|
|
// extra argument, but does force the string to be returned indirectly.
|
|
@warn_unused_result
|
|
@_silgen_name("swift_ClassMirror_subscript")
|
|
func _getClassChild<T>(_: Int, _: _MagicMirrorData) -> (T, _MirrorType)
|
|
|
|
#if _runtime(_ObjC)
|
|
@warn_unused_result
|
|
@_silgen_name("swift_ClassMirror_quickLookObject")
|
|
public func _getClassPlaygroundQuickLook(
|
|
data: _MagicMirrorData
|
|
) -> PlaygroundQuickLook?
|
|
#endif
|
|
|
|
struct _ClassMirror : _MirrorType {
|
|
let data: _MagicMirrorData
|
|
|
|
var value: Any { return data.value }
|
|
var valueType: Any.Type { return data.valueType }
|
|
var objectIdentifier: ObjectIdentifier? {
|
|
return data._loadValue() as ObjectIdentifier
|
|
}
|
|
var count: Int {
|
|
return _getClassCount(data)
|
|
}
|
|
subscript(i: Int) -> (String, _MirrorType) {
|
|
return _getClassChild(i, data)
|
|
}
|
|
var summary: String {
|
|
return _typeName(valueType)
|
|
}
|
|
var quickLookObject: PlaygroundQuickLook? {
|
|
#if _runtime(_ObjC)
|
|
return _getClassPlaygroundQuickLook(data)
|
|
#else
|
|
return nil
|
|
#endif
|
|
}
|
|
var disposition: _MirrorDisposition { return .Class }
|
|
}
|
|
|
|
struct _ClassSuperMirror : _MirrorType {
|
|
let data: _MagicMirrorData
|
|
|
|
var value: Any { return data.value }
|
|
var valueType: Any.Type { return data.valueType }
|
|
|
|
// Suppress the value identifier for super mirrors.
|
|
var objectIdentifier: ObjectIdentifier? {
|
|
return nil
|
|
}
|
|
var count: Int {
|
|
return _getClassCount(data)
|
|
}
|
|
subscript(i: Int) -> (String, _MirrorType) {
|
|
return _getClassChild(i, data)
|
|
}
|
|
var summary: String {
|
|
return _typeName(data.metadata)
|
|
}
|
|
var quickLookObject: PlaygroundQuickLook? { return nil }
|
|
var disposition: _MirrorDisposition { return .Class }
|
|
}
|
|
|
|
struct _MetatypeMirror : _MirrorType {
|
|
let data: _MagicMirrorData
|
|
|
|
var value: Any { return data.value }
|
|
var valueType: Any.Type { return data.valueType }
|
|
|
|
var objectIdentifier: ObjectIdentifier? {
|
|
return data._loadValue() as ObjectIdentifier
|
|
}
|
|
|
|
var count: Int {
|
|
return 0
|
|
}
|
|
subscript(i: Int) -> (String, _MirrorType) {
|
|
_preconditionFailure("no children")
|
|
}
|
|
var summary: String {
|
|
return _typeName(data._loadValue() as Any.Type)
|
|
}
|
|
var quickLookObject: PlaygroundQuickLook? { return nil }
|
|
|
|
// Special disposition for types?
|
|
var disposition: _MirrorDisposition { return .Aggregate }
|
|
}
|
|
|
|
@available(*, unavailable, message="call the 'Mirror(reflecting:)' initializer")
|
|
public func reflect<T>(x: T) -> _MirrorType {
|
|
fatalError("unavailable function can't be called")
|
|
}
|
|
|