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:
David Farler
2016-05-03 02:54:30 -07:00
parent bfc94f4290
commit 5f5ce39a1d
8 changed files with 303 additions and 28 deletions

View File

@@ -24,6 +24,7 @@
#include "swift/Reflection/TypeLowering.h"
#include "swift/Reflection/TypeRef.h"
#include "swift/Reflection/TypeRefBuilder.h"
#include "swift/SwiftRemoteMirror/MemoryReaderInterface.h"
#include <iostream>
#include <vector>
@@ -119,6 +120,85 @@ public:
return getMetadataTypeInfo(MetadataAddress.second);
}
bool
projectExistential(addr_t ExistentialAddress,
const TypeRef *ExistentialTR,
const TypeRef **OutInstanceTR,
addr_t *OutInstanceAddress) {
if (ExistentialTR == nullptr)
return false;
auto ExistentialTI = getTypeInfo(ExistentialTR);
if (ExistentialTI == nullptr)
return false;
auto ExistentialRecordTI = dyn_cast<const RecordTypeInfo>(ExistentialTI);
if (ExistentialRecordTI == nullptr)
return false;
switch (ExistentialRecordTI->getRecordKind()) {
// Class existentials have trivial layout.
// The first word of the 3-word buffer has a pointer to the class instance.
case RecordKind::ClassExistential:
*OutInstanceTR = getBuilder().getTypeConverter().getUnknownObjectTypeRef();
*OutInstanceAddress = ExistentialAddress;
return true;
// Other existentials have two cases:
// If the value fits in three words, it starts at the beginning of the
// container. If it doesn't, the first word is a pointer to a heap box.
case RecordKind::Existential: {
auto Fields = ExistentialRecordTI->getFields();
auto Metadata = std::find_if(Fields.begin(), Fields.end(),
[](const FieldInfo &FI) -> bool {
return FI.Name.compare("metadata") == 0;
});
if (Metadata == Fields.end())
return false;
// Get the metadata pointer for the contained instance type.
// This is equivalent to:
// auto PointerArray = reinterpret_cast<uintptr_t*>(ExistentialAddress);
// uintptr_t MetadataAddress = PointerArray[Offset];
auto MetadataAddressAddress
= RemoteAddress(ExistentialAddress + Metadata->Offset);
StoredPointer MetadataAddress = 0;
if (!getReader().readInteger(MetadataAddressAddress, &MetadataAddress))
return false;
auto InstanceTR = readTypeFromMetadata(MetadataAddress);
if (!InstanceTR)
return false;
*OutInstanceTR = InstanceTR;
auto InstanceTI = getTypeInfo(InstanceTR);
if (!InstanceTI)
return false;
if (InstanceTI->getSize() < ExistentialRecordTI->getSize()) {
// The value fits in the existential container, so it starts at the
// start of the container.
*OutInstanceAddress = ExistentialAddress;
} else {
// Otherwise it's in a box somewhere off in the heap. The first word
// of the container has the address to that box.
StoredPointer BoxAddress = 0;
if (!getReader().readInteger(RemoteAddress(ExistentialAddress),
&BoxAddress))
return false;
*OutInstanceAddress = BoxAddress;
}
return true;
}
default:
return false;
}
}
/// Return a description of the layout of a value with the given type.
const TypeInfo *getTypeInfo(const TypeRef *TR) {
return getBuilder().getTypeConverter().getTypeInfo(TR);