Skip to content

Commit 41d1549

Browse files
committed
Merge pull request #2380 from bitjammer/remote-mirror-existentials
Remote mirror existentials
2 parents 0567d5f + fb34de8 commit 41d1549

File tree

8 files changed

+385
-36
lines changed

8 files changed

+385
-36
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/Reflection/TypeLowering.h"
2525
#include "swift/Reflection/TypeRef.h"
2626
#include "swift/Reflection/TypeRefBuilder.h"
27+
#include "swift/SwiftRemoteMirror/MemoryReaderInterface.h"
2728

2829
#include <iostream>
2930
#include <vector>
@@ -119,6 +120,85 @@ class ReflectionContext
119120
return getMetadataTypeInfo(MetadataAddress.second);
120121
}
121122

123+
bool
124+
projectExistential(addr_t ExistentialAddress,
125+
const TypeRef *ExistentialTR,
126+
const TypeRef **OutInstanceTR,
127+
addr_t *OutInstanceAddress) {
128+
if (ExistentialTR == nullptr)
129+
return false;
130+
131+
auto ExistentialTI = getTypeInfo(ExistentialTR);
132+
if (ExistentialTI == nullptr)
133+
return false;
134+
135+
auto ExistentialRecordTI = dyn_cast<const RecordTypeInfo>(ExistentialTI);
136+
if (ExistentialRecordTI == nullptr)
137+
return false;
138+
139+
switch (ExistentialRecordTI->getRecordKind()) {
140+
// Class existentials have trivial layout.
141+
// The first word of the 3-word buffer has a pointer to the class instance.
142+
case RecordKind::ClassExistential:
143+
*OutInstanceTR = getBuilder().getTypeConverter().getUnknownObjectTypeRef();
144+
*OutInstanceAddress = ExistentialAddress;
145+
return true;
146+
147+
// Other existentials have two cases:
148+
// If the value fits in three words, it starts at the beginning of the
149+
// container. If it doesn't, the first word is a pointer to a heap box.
150+
case RecordKind::Existential: {
151+
auto Fields = ExistentialRecordTI->getFields();
152+
auto Metadata = std::find_if(Fields.begin(), Fields.end(),
153+
[](const FieldInfo &FI) -> bool {
154+
return FI.Name.compare("metadata") == 0;
155+
});
156+
if (Metadata == Fields.end())
157+
return false;
158+
159+
// Get the metadata pointer for the contained instance type.
160+
// This is equivalent to:
161+
// auto PointerArray = reinterpret_cast<uintptr_t*>(ExistentialAddress);
162+
// uintptr_t MetadataAddress = PointerArray[Offset];
163+
auto MetadataAddressAddress
164+
= RemoteAddress(ExistentialAddress + Metadata->Offset);
165+
166+
StoredPointer MetadataAddress = 0;
167+
if (!getReader().readInteger(MetadataAddressAddress, &MetadataAddress))
168+
return false;
169+
170+
auto InstanceTR = readTypeFromMetadata(MetadataAddress);
171+
if (!InstanceTR)
172+
return false;
173+
174+
*OutInstanceTR = InstanceTR;
175+
176+
auto InstanceTI = getTypeInfo(InstanceTR);
177+
if (!InstanceTI)
178+
return false;
179+
180+
if (InstanceTI->getSize() < ExistentialRecordTI->getSize()) {
181+
// The value fits in the existential container, so it starts at the
182+
// start of the container.
183+
*OutInstanceAddress = ExistentialAddress;
184+
} else {
185+
// Otherwise it's in a box somewhere off in the heap. The first word
186+
// of the container has the address to that box.
187+
StoredPointer BoxAddress = 0;
188+
189+
if (!getReader().readInteger(RemoteAddress(ExistentialAddress),
190+
&BoxAddress))
191+
return false;
192+
193+
*OutInstanceAddress = BoxAddress;
194+
}
195+
return true;
196+
}
197+
default:
198+
return false;
199+
}
200+
}
201+
122202
/// Return a description of the layout of a value with the given type.
123203
const TypeInfo *getTypeInfo(const TypeRef *TR) {
124204
return getBuilder().getTypeConverter().getTypeInfo(TR);

include/swift/Remote/MetadataReader.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ class MetadataReader {
579579
return BuiltType();
580580

581581
return Builder.createTupleType(elementTypes, std::move(labels),
582-
/*variadic*/ false);
582+
/*variardic*/ false);
583583
}
584584
case MetadataKind::Function: {
585585
auto Function = cast<TargetFunctionTypeMetadata<Runtime>>(Meta);
@@ -682,21 +682,28 @@ class MetadataReader {
682682
}
683683
}
684684

685+
BuiltType readTypeFromMangledName(const char *MangledTypeName,
686+
size_t Length) {
687+
auto Demangled = Demangle::demangleSymbolAsNode(MangledTypeName, Length);
688+
return decodeMangledType(Demangled);
689+
}
690+
685691
/// Read the isa pointer of a class or closure context instance and apply
686692
/// the isa mask.
687693
std::pair<bool, StoredPointer> readMetadataFromInstance(
688694
StoredPointer ObjectAddress) {
695+
StoredPointer isaMaskValue = ~0;
689696
auto isaMask = readIsaMask();
690-
if (!isaMask.first)
691-
return {false, 0};
697+
if (isaMask.first)
698+
isaMaskValue = isaMask.second;
692699

693700
StoredPointer MetadataAddress;
694701
if (!Reader->readBytes(RemoteAddress(ObjectAddress),
695702
(uint8_t*)&MetadataAddress,
696703
sizeof(StoredPointer)))
697704
return {false, 0};
698705

699-
return {true, MetadataAddress & isaMask.second};
706+
return {true, MetadataAddress & isaMaskValue};
700707
}
701708

702709
/// Given the address of a nominal type descriptor, attempt to resolve

include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ swift_typeref_t
7474
swift_reflection_typeRefForInstance(SwiftReflectionContextRef ContextRef,
7575
uintptr_t Object);
7676

77+
/// Returns a typeref from a mangled type name string.
78+
swift_typeref_t
79+
swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef,
80+
const char *MangledName,
81+
uint64_t Length);
82+
7783
/// Returns a structure describing the layout of a value of a typeref.
7884
/// For classes, this returns the reference value itself.
7985
swift_typeinfo_t
@@ -141,7 +147,7 @@ swift_reflection_genericArgumentOfTypeRef(swift_typeref_t OpaqueTypeRef,
141147
/// Returns true if InstanceTypeRef and StartOfInstanceData contain valid
142148
/// valid values.
143149
int swift_reflection_projectExistential(SwiftReflectionContextRef ContextRef,
144-
addr_t InstanceAddress,
150+
addr_t ExistentialAddress,
145151
swift_typeref_t ExistentialTypeRef,
146152
swift_typeref_t *OutInstanceTypeRef,
147153
addr_t *OutStartOfInstanceData);

stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@
2121
import MachO
2222
import Darwin
2323

24+
let RequestInstanceKind = "k"
2425
let RequestInstanceAddress = "i"
2526
let RequestReflectionInfos = "r"
2627
let RequestReadBytes = "b";
2728
let RequestSymbolAddress = "s"
2829
let RequestStringLength = "l"
29-
let RequestExit = "e"
30+
let RequestDone = "d"
3031
let RequestPointerSize = "p"
3132

3233
internal func debugLog(_ message: String) {
@@ -36,6 +37,13 @@ internal func debugLog(_ message: String) {
3637
#endif
3738
}
3839

40+
public enum InstanceKind : UInt8 {
41+
case None
42+
case Object
43+
case Existential
44+
case Closure
45+
}
46+
3947
/// Represents a section in a loaded image in this process.
4048
internal struct Section {
4149
/// The absolute start address of the section's data in this address space.
@@ -255,11 +263,17 @@ internal func sendPointerSize() {
255263
/// - Get the pointer size of this process, which affects assumptions about the
256264
/// the layout of runtime structures with pointer-sized fields.
257265
/// - Read raw bytes out of this process's address space.
258-
public func reflect(_ instance: AnyObject) {
266+
///
267+
/// The parent sends a Done message to indicate that it's done
268+
/// looking at this instance. It will continue to ask for instances,
269+
/// so call doneReflecting() when you don't have any more instances.
270+
internal func reflect(instanceAddress: UInt, kind: InstanceKind) {
259271
while let command = readLine(strippingNewline: true) {
260272
switch command {
273+
case String(validatingUTF8: RequestInstanceKind)!:
274+
sendValue(kind.rawValue)
261275
case String(validatingUTF8: RequestInstanceAddress)!:
262-
sendAddress(of: instance)
276+
sendValue(instanceAddress)
263277
case String(validatingUTF8: RequestReflectionInfos)!:
264278
sendReflectionInfos()
265279
case String(validatingUTF8: RequestReadBytes)!:
@@ -270,14 +284,40 @@ public func reflect(_ instance: AnyObject) {
270284
sendStringLength()
271285
case String(validatingUTF8: RequestPointerSize)!:
272286
sendPointerSize();
273-
case String(validatingUTF8: RequestExit)!:
274-
exit(EXIT_SUCCESS)
287+
case String(validatingUTF8: RequestDone)!:
288+
return;
275289
default:
276-
fatalError("Unknown request received!")
290+
fatalError("Unknown request received: '\(Array(command.utf8))'!")
277291
}
278292
}
279293
}
280294

295+
/// Reflect a class instance.
296+
public func reflect(object: AnyObject) {
297+
let address = unsafeAddress(of: object)
298+
let addressValue = unsafeBitCast(address, to: UInt.self)
299+
reflect(instanceAddress: addressValue, kind: .Object)
300+
}
301+
302+
/// Reflect any type at all by boxing it into an existential container (an `Any`)
303+
///
304+
/// This function serves to exercise the projectExistential function of the
305+
/// SwiftRemoteMirror API.
306+
public func reflect<T>(any: T) {
307+
let any: Any = any
308+
let anyPointer = UnsafeMutablePointer<Any>(allocatingCapacity: sizeof(Any.self))
309+
anyPointer.initialize(with: any)
310+
let anyPointerValue = unsafeBitCast(anyPointer, to: UInt.self)
311+
reflect(instanceAddress: anyPointerValue, kind: .Existential)
312+
anyPointer.deallocateCapacity(sizeof(Any.self))
313+
}
314+
315+
/// Call this function to indicate to the parent that there are
316+
/// no more instances to look at.
317+
public func doneReflecting() {
318+
sendValue(InstanceKind.None.rawValue)
319+
}
320+
281321
/* Example usage
282322

283323
public protocol P {

stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ swift_reflection_typeRefForInstance(SwiftReflectionContextRef ContextRef,
8484
return reinterpret_cast<swift_typeref_t>(TR);
8585
}
8686

87+
swift_typeref_t
88+
swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef,
89+
const char *MangledTypeName,
90+
uint64_t Length) {
91+
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
92+
auto TR = Context->readTypeFromMangledName(MangledTypeName, Length);
93+
return reinterpret_cast<swift_typeref_t>(TR);
94+
}
95+
8796
swift_typeref_t
8897
swift_reflection_genericArgumentOfTypeRef(swift_typeref_t OpaqueTypeRef,
8998
unsigned Index) {
@@ -237,12 +246,14 @@ swift_reflection_childOfInstance(SwiftReflectionContextRef ContextRef,
237246
}
238247

239248
int swift_reflection_projectExistential(SwiftReflectionContextRef ContextRef,
240-
addr_t InstanceAddress,
249+
addr_t ExistentialAddress,
241250
swift_typeref_t ExistentialTypeRef,
242251
swift_typeref_t *InstanceTypeRef,
243252
addr_t *StartOfInstanceData) {
244-
// TODO
245-
return false;
253+
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
254+
auto ExistentialTR = reinterpret_cast<const TypeRef *>(ExistentialTypeRef);
255+
return Context->projectExistential(ExistentialAddress, ExistentialTR,
256+
reinterpret_cast<const TypeRef **>(InstanceTypeRef), StartOfInstanceData);
246257
}
247258

248259
void swift_reflection_dumpTypeRef(swift_typeref_t OpaqueTypeRef) {

tools/swift-reflection-test/messages.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
static const char *REQUEST_INSTANCE_KIND = "k\n";
1314
static const char *REQUEST_INSTANCE_ADDRESS = "i\n";
1415
static const char *REQUEST_REFLECTION_INFO = "r\n";
1516
static const char *REQUEST_READ_BYTES = "b\n";
1617
static const char *REQUEST_SYMBOL_ADDRESS = "s\n";
1718
static const char *REQUEST_STRING_LENGTH = "l\n";
1819
static const char *REQUEST_POINTER_SIZE = "p\n";
19-
static const char *REQUEST_EXIT = "e\n";
20+
static const char *REQUEST_DONE = "d\n";
21+
22+
typedef enum InstanceKind {
23+
None,
24+
Object,
25+
Existential,
26+
Closure
27+
} InstanceKind;

0 commit comments

Comments
 (0)