mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
SwiftRemoteMirror: Wire up existential projection API
Implement the ReflectionContext's implementation of: swift_reflection_projectExistential. First, we get the type info of the existential typeref - it should be a record type info. If it's a class existential, it has trivial layout: the first word is a pointer to the class instance. Otherwise, if the value fits in the 3-word buffer of the existential container, it trivially is also at the start of the container. Otherwise, the value is off in a heap box somewhere, but the first word of the container is a pointer to that box.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
import MachO
|
||||
import Darwin
|
||||
|
||||
let RequestInstanceKind = "k"
|
||||
let RequestInstanceAddress = "i"
|
||||
let RequestReflectionInfos = "r"
|
||||
let RequestReadBytes = "b";
|
||||
@@ -36,6 +37,13 @@ internal func debugLog(_ message: String) {
|
||||
#endif
|
||||
}
|
||||
|
||||
public enum InstanceKind : UInt8 {
|
||||
case None
|
||||
case Object
|
||||
case Existential
|
||||
case Closure
|
||||
}
|
||||
|
||||
/// Represents a section in a loaded image in this process.
|
||||
internal struct Section {
|
||||
/// The absolute start address of the section's data in this address space.
|
||||
@@ -259,11 +267,13 @@ internal func sendPointerSize() {
|
||||
/// The parent sends a Done message to indicate that it's done
|
||||
/// looking at this instance. It will continue to ask for instances,
|
||||
/// so call doneReflecting() when you don't have any more instances.
|
||||
public func reflect(_ instance: AnyObject) {
|
||||
internal func reflect(instanceAddress: UInt, kind: InstanceKind) {
|
||||
while let command = readLine(strippingNewline: true) {
|
||||
switch command {
|
||||
case String(validatingUTF8: RequestInstanceKind)!:
|
||||
sendValue(kind.rawValue)
|
||||
case String(validatingUTF8: RequestInstanceAddress)!:
|
||||
sendAddress(of: instance)
|
||||
sendValue(instanceAddress)
|
||||
case String(validatingUTF8: RequestReflectionInfos)!:
|
||||
sendReflectionInfos()
|
||||
case String(validatingUTF8: RequestReadBytes)!:
|
||||
@@ -277,15 +287,35 @@ public func reflect(_ instance: AnyObject) {
|
||||
case String(validatingUTF8: RequestDone)!:
|
||||
return;
|
||||
default:
|
||||
fatalError("Unknown request received!")
|
||||
fatalError("Unknown request received: '\(Array(command.utf8))'!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reflect a class instance.
|
||||
public func reflect(object: AnyObject) {
|
||||
let address = unsafeAddress(of: object)
|
||||
let addressValue = unsafeBitCast(address, to: UInt.self)
|
||||
reflect(instanceAddress: addressValue, kind: .Object)
|
||||
}
|
||||
|
||||
/// Reflect any type at all by boxing it into an existential container (an `Any`)
|
||||
///
|
||||
/// This function serves to exercise the projectExistential function of the
|
||||
/// SwiftRemoteMirror API.
|
||||
public func reflect<T>(any: T) {
|
||||
let any: Any = any
|
||||
let anyPointer = UnsafeMutablePointer<Any>(allocatingCapacity: sizeof(Any.self))
|
||||
anyPointer.initialize(with: any)
|
||||
let anyPointerValue = unsafeBitCast(anyPointer, to: UInt.self)
|
||||
reflect(instanceAddress: anyPointerValue, kind: .Existential)
|
||||
anyPointer.deallocateCapacity(sizeof(Any.self))
|
||||
}
|
||||
|
||||
/// Call this function to indicate to the parent that there are
|
||||
/// no more instances to look at.
|
||||
public func doneReflecting() {
|
||||
sendValue(UInt(0))
|
||||
sendValue(InstanceKind.None.rawValue)
|
||||
}
|
||||
|
||||
/* Example usage
|
||||
|
||||
Reference in New Issue
Block a user