Add extraction protocol conformance descriptor extraction, as read from an object file image, to TypeRefBuilder.

This commit is contained in:
Artem Chikin
2022-01-19 19:49:46 -08:00
parent f3d784fd0f
commit e934fe201a
13 changed files with 465 additions and 103 deletions

View File

@@ -79,6 +79,16 @@ struct RuntimeTarget<4> {
using StoredSize = uint32_t;
using StoredPointerDifference = int32_t;
static constexpr size_t PointerSize = 4;
#if SWIFT_OBJC_INTEROP
static constexpr bool ObjCInterop = true;
template <typename T>
using TargetAnyClassMetadata = TargetAnyClassMetadataObjCInterop<T>;
#else
static constexpr bool ObjCInterop = false;
template <typename T>
using TargetAnyClassMetadata = TargetAnyClassMetadata<T>;
#endif
};
template <>
@@ -91,6 +101,16 @@ struct RuntimeTarget<8> {
using StoredSize = uint64_t;
using StoredPointerDifference = int64_t;
static constexpr size_t PointerSize = 8;
#if SWIFT_OBJC_INTEROP
static constexpr bool ObjCInterop = true;
template <typename T>
using TargetAnyClassMetadata = TargetAnyClassMetadataObjCInterop<T>;
#else
static constexpr bool ObjCInterop = false;
template <typename T>
using TargetAnyClassMetadata = TargetAnyClassMetadata<T>;
#endif
};
namespace reflection {
@@ -540,6 +560,14 @@ namespace {
using TypeContextDescriptor = TargetTypeContextDescriptor<InProcess>;
template<unsigned PointerSize>
using ExternalTypeContextDescriptor
#if SWIFT_OBJC_INTEROP
= TargetTypeContextDescriptor<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
#else
= TargetTypeContextDescriptor<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
#endif
// FIXME: https://bugs.swift.org/browse/SR-1155
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winvalid-offsetof"
@@ -2107,6 +2135,14 @@ using ProtocolRequirement = TargetProtocolRequirement<InProcess>;
template<typename Runtime> struct TargetProtocolDescriptor;
using ProtocolDescriptor = TargetProtocolDescriptor<InProcess>;
template<unsigned PointerSize>
using ExternalProtocolDescriptor
#if SWIFT_OBJC_INTEROP
= TargetProtocolDescriptor<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
#else
= TargetProtocolDescriptor<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
#endif
/// A witness table for a protocol.
///
/// With the exception of the initial protocol conformance descriptor,
@@ -2722,6 +2758,16 @@ public:
return TypeRef.getTypeDescriptor(getTypeKind());
}
constexpr inline auto
getTypeDescriptorOffset() const -> typename Runtime::StoredSize {
return offsetof(typename std::remove_reference<decltype(*this)>::type, TypeRef);
}
constexpr inline auto
getProtocolDescriptorOffset() const -> typename Runtime::StoredSize {
return offsetof(typename std::remove_reference<decltype(*this)>::type, Protocol);
}
TargetContextDescriptor<Runtime> * __ptrauth_swift_type_descriptor *
_getTypeDescriptorLocation() const {
if (getTypeKind() != TypeReferenceKind::IndirectTypeDescriptor)
@@ -2840,9 +2886,21 @@ using TargetProtocolConformanceRecord =
using ProtocolConformanceRecord = TargetProtocolConformanceRecord<InProcess>;
template<unsigned PointerSize>
using ExternalProtocolConformanceDescriptor
= TargetProtocolConformanceDescriptor<External<RuntimeTarget<8>>>;
using ExternalProtocolConformanceRecord = TargetProtocolConformanceRecord<External<RuntimeTarget<8>>>;
#if SWIFT_OBJC_INTEROP
= TargetProtocolConformanceDescriptor<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
#else
= TargetProtocolConformanceDescriptor<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
#endif
template<unsigned PointerSize>
using ExternalProtocolConformanceRecord
#if SWIFT_OBJC_INTEROP
= TargetProtocolConformanceRecord<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
#else
= TargetProtocolConformanceRecord<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
#endif
template<typename Runtime>
struct TargetGenericContext;
@@ -2893,6 +2951,13 @@ private:
};
using ContextDescriptor = TargetContextDescriptor<InProcess>;
template<unsigned PointerSize>
using ExternalContextDescriptor
#if SWIFT_OBJC_INTEROP
= TargetContextDescriptor<External<WithObjCInterop<RuntimeTarget<PointerSize>>>>;
#else
= TargetContextDescriptor<External<NoObjCInterop<RuntimeTarget<PointerSize>>>>;
#endif
inline bool isCImportedModuleName(llvm::StringRef name) {
// This does not include MANGLING_MODULE_CLANG_IMPORTER because that's
@@ -3417,6 +3482,11 @@ public:
NumRequirements};
}
constexpr inline auto
getNameOffset() const -> typename Runtime::StoredSize {
return offsetof(typename std::remove_reference<decltype(*this)>::type, Name);
}
/// Retrieve the requirement base descriptor address.
ConstTargetPointer<Runtime, TargetProtocolRequirement<Runtime>>
getRequirementBaseDescriptor() const {
@@ -4081,6 +4151,11 @@ public:
/// type's metadata. The returned value is measured in sizeof(StoredPointer).
int32_t getGenericArgumentOffset() const;
constexpr inline auto
getNameOffset() const -> typename Runtime::StoredSize {
return offsetof(typename std::remove_reference<decltype(*this)>::type, Name);
}
/// Return the start of the generic arguments array in the nominal
/// type's metadata. The returned value is measured in sizeof(StoredPointer).
const TargetMetadata<Runtime> * const *getGenericArguments(

View File

@@ -12,7 +12,7 @@
namespace swift {
/// Represents the seven reflection sections used by Swift
/// Represents the eight reflection sections used by Swift
enum ReflectionSectionKind : uint8_t {
fieldmd,
assocty,
@@ -20,7 +20,8 @@ enum ReflectionSectionKind : uint8_t {
capture,
typeref,
reflstr,
conform
conform,
protocs
};
/// Abstract base class responsible for providing the correct reflection section
@@ -50,6 +51,8 @@ public:
return "__swift5_reflstr";
case conform:
return "__swift5_proto";
case protocs:
return "__swift5_protos";
}
llvm_unreachable("Section type not found.");
}
@@ -73,7 +76,9 @@ public:
case reflstr:
return "swift5_reflstr";
case conform:
return "swift5_proto";
return "swift5_protocol_conformances";
case protocs:
return "swift5_protocols";
}
llvm_unreachable("Section type not found.");
}
@@ -97,7 +102,9 @@ public:
case reflstr:
return ".sw5rfst";
case conform:
return ".sw5cnfrm"; // TODO: Figure out the real name
return ".sw5prtc$B";
case protocs:
return ".sw5prt$B";
}
llvm_unreachable("Section not found.");
}

View File

@@ -442,6 +442,17 @@ public:
return reinterpret_cast<PointerTy>(absolute);
}
/// Apply the offset to a parameter, instead of `this`.
PointerTy getRelative(void *base) const & {
// Check for null.
if (Nullable && RelativeOffset == 0)
return nullptr;
// The value is addressed relative to `base`.
uintptr_t absolute = detail::applyRelativeOffset(base, RelativeOffset);
return reinterpret_cast<PointerTy>(absolute);
}
/// A zero relative offset encodes a null reference.
bool isNull() const & {
return RelativeOffset == 0;
@@ -476,6 +487,10 @@ public:
return this->get();
}
const typename super::ValueTy* getRelative(void *base) const & {
return this->super::getRelative(base);
}
using super::isNull;
};

View File

@@ -221,6 +221,22 @@ public:
SectionsBuf + (I * sizeof(typename T::Section)));
if (strncmp(S->sectname, Name.data(), strlen(Name.data())) != 0)
continue;
// The above check verifies that `Name` is a prefix to the examined
// section name, to allow for matching of sections with a suffix
// like `_TEXT`, etc.
// "__swift5_proto" section name is a substring of "__swift5_protos",
// Ensure we don't return the latter when looking for the former.
SwiftObjectFileFormatMachO ObjectFileFormat;
if (Name.data() ==
ObjectFileFormat.getSectionName(ReflectionSectionKind::conform)) {
auto protocolsSectionName =
ObjectFileFormat.getSectionName(ReflectionSectionKind::protocs);
if (strncmp(S->sectname, protocolsSectionName.data(),
strlen(protocolsSectionName.data())) == 0)
continue;
}
auto RemoteSecStart = S->addr + Slide;
auto LocalSectBuf =
this->getReader().readBytes(RemoteAddress(RemoteSecStart), S->size);

View File

@@ -192,23 +192,8 @@ public:
+ CR->NumMetadataSources * sizeof(MetadataSourceRecord);
}
};
class ConformanceRecordIterator
: public ReflectionSectionIteratorBase<ConformanceRecordIterator,
ExternalProtocolConformanceRecord> {
public:
ConformanceRecordIterator(RemoteRef<void> Cur, uint64_t Size)
: ReflectionSectionIteratorBase(Cur, Size)
{}
static uint64_t getCurrentRecordSize(RemoteRef<ExternalProtocolConformanceRecord> CD){
return sizeof(ExternalProtocolConformanceRecord);
}
};
using CaptureSection = ReflectionSection<CaptureDescriptorIterator>;
using GenericSection = ReflectionSection<const void *>;
using ConformanceSection = ReflectionSection<ConformanceRecordIterator>;
struct ReflectionInfo {
FieldSection Field;
@@ -217,7 +202,7 @@ struct ReflectionInfo {
CaptureSection Capture;
GenericSection TypeReference;
GenericSection ReflectionString;
ConformanceSection Conformance;
GenericSection Conformance;
};
struct ClosureContextInfo {
@@ -252,6 +237,17 @@ struct FieldTypeInfo {
}
};
/// Info about a protocol conformance read out from an Image
struct ProtocolConformanceInfo {
std::string typeName;
std::string protocolName;
// TODO:
// const TypeRef *type;
// std::string mangledTypeName;
// std::string mangledProtocolName;
};
/// An implementation of MetadataReader's BuilderType concept for
/// building TypeRefs, and parsing field metadata from any images
/// it has been made aware of.
@@ -686,14 +682,23 @@ public:
}
private:
using RefDemangler = std::function<Demangle::Node * (RemoteRef<char>, bool)>;
using UnderlyingTypeReader = std::function<const TypeRef* (uint64_t, unsigned)>;
using ByteReader = std::function<remote::MemoryReader::ReadBytesResult (remote::RemoteAddress, unsigned)>;
using StringReader = std::function<bool (remote::RemoteAddress, std::string &)>;
using PointerReader = std::function<llvm::Optional<remote::RemoteAbsolutePointer> (remote::RemoteAddress, unsigned)>;
// These fields are captured from the MetadataReader template passed into the
// TypeRefBuilder struct, to isolate its template-ness from the rest of
// TypeRefBuilder.
unsigned PointerSize;
std::function<Demangle::Node * (RemoteRef<char>, bool)>
TypeRefDemangler;
std::function<const TypeRef* (uint64_t, unsigned)>
OpaqueUnderlyingTypeReader;
RefDemangler TypeRefDemangler;
UnderlyingTypeReader OpaqueUnderlyingTypeReader;
// Opaque fields captured from the MetadataReader's MemoryReader
ByteReader OpaqueByteReader;
StringReader OpaqueStringReader;
PointerReader OpaquePointerReader;
public:
template<typename Runtime>
@@ -710,6 +715,15 @@ public:
[&reader](uint64_t descriptorAddr, unsigned ordinal) -> const TypeRef* {
return reader.readUnderlyingTypeForOpaqueTypeDescriptor(
descriptorAddr, ordinal).getType();
}),
OpaqueByteReader([&reader](remote::RemoteAddress address, unsigned size) -> remote::MemoryReader::ReadBytesResult {
return reader.Reader->readBytes(address, size);
}),
OpaqueStringReader([&reader](remote::RemoteAddress address, std::string &dest) -> bool {
return reader.Reader->readString(address, dest);
}),
OpaquePointerReader([&reader](remote::RemoteAddress address, unsigned size) -> llvm::Optional<remote::RemoteAbsolutePointer> {
return reader.Reader->readPointer(address, size);
})
{}
@@ -749,16 +763,290 @@ public:
/// Dumping typerefs, field declarations, associated types
///
void dumpTypeRef(RemoteRef<char> MangledName,
std::ostream &stream, bool printTypeName = false);
void dumpTypeRef(RemoteRef<char> MangledName, std::ostream &stream,
bool printTypeName = false);
void dumpFieldSection(std::ostream &stream);
void dumpAssociatedTypeSection(std::ostream &stream);
void dumpBuiltinTypeSection(std::ostream &stream);
void dumpCaptureSection(std::ostream &stream);
void dumpConformanceSection(std::ostream &stream);
void dumpAllSections(std::ostream &stream);
///
/// Extraction of protocol conformances
///
private:
/// Reader of protocol descriptors from Images
template <unsigned PointerSize>
struct ProtocolConformanceDescriptorReader {
std::string Error;
ByteReader OpaqueByteReader;
StringReader OpaqueStringReader;
PointerReader OpaquePointerReader;
ProtocolConformanceDescriptorReader(ByteReader byteReader,
StringReader stringReader,
PointerReader pointerReader)
: Error(""), OpaqueByteReader(byteReader),
OpaqueStringReader(stringReader), OpaquePointerReader(pointerReader) {
}
std::string getConformingTypeName(
const char *conformanceDescriptorAddress,
const ExternalProtocolConformanceDescriptor<PointerSize>
&conformanceDescriptor) {
std::string typeName;
// Compute the address of the type descriptor as follows:
// - Compute the address of the TypeRef field in the protocol
// descriptor
// - Read the TypeRef field to compute the offset to the type
// descriptor
// - Address of the type descriptor is found at the (2) offset from the
// conformance descriptor address
auto contextDescriptorFieldAddress = detail::applyRelativeOffset(
conformanceDescriptorAddress,
(int32_t)conformanceDescriptor.getTypeDescriptorOffset());
auto contextDescriptorOffsetBytes =
OpaqueByteReader(remote::RemoteAddress(contextDescriptorFieldAddress),
sizeof(uint32_t));
if (!contextDescriptorOffsetBytes.get()) {
Error = "Failed to read type descriptor field in conformance descriptor.";
return typeName;
}
auto contextDescriptorOffset =
(const uint32_t *)contextDescriptorOffsetBytes.get();
// Read the type descriptor itself using the address computed above
auto contextDescriptorAddress = detail::applyRelativeOffset(
(const char *)contextDescriptorFieldAddress,
(int32_t)*contextDescriptorOffset);
auto contextDescriptorBytes =
OpaqueByteReader(remote::RemoteAddress(contextDescriptorAddress),
sizeof(ExternalContextDescriptor<PointerSize>));
if (!contextDescriptorBytes.get()) {
Error = "Failed to read context descriptor.";
return typeName;
}
const ExternalContextDescriptor<PointerSize> *contextDescriptor =
(const ExternalContextDescriptor<PointerSize> *)
contextDescriptorBytes.get();
auto typeDescriptor =
dyn_cast<ExternalTypeContextDescriptor<PointerSize>>(
contextDescriptor);
if (!typeDescriptor) {
Error = "Unexpected type of context descriptor.";
return typeName;
}
// Compute the address of the type descriptor's name field and read the
// offset
auto typeNameOffsetAddress =
detail::applyRelativeOffset((const char *)contextDescriptorAddress,
(int32_t)typeDescriptor->getNameOffset());
auto typeNameOfsetBytes = OpaqueByteReader(
remote::RemoteAddress(typeNameOffsetAddress), sizeof(uint32_t));
if (!typeNameOfsetBytes.get()) {
Error = "Failed to read type name offset in a type descriptor.";
return typeName;
}
auto typeNameOffset = (const uint32_t *)typeNameOfsetBytes.get();
// Using the offset above, compute the address of the name field itsel
// and read it.
auto typeNameAddress = detail::applyRelativeOffset(
(const char *)typeNameOffsetAddress, (int32_t)*typeNameOffset);
OpaqueStringReader(remote::RemoteAddress(typeNameAddress), typeName);
return typeName;
}
std::string getConformanceProtocol(
const char *conformanceDescriptorAddress,
const ExternalProtocolConformanceDescriptor<PointerSize>
&conformanceDescriptor) {
std::string protocolName = "";
auto protocolDescriptorFieldAddress = detail::applyRelativeOffset(
conformanceDescriptorAddress,
(int32_t)conformanceDescriptor.getProtocolDescriptorOffset());
auto protocolDescriptorOffsetBytes = OpaqueByteReader(
remote::RemoteAddress(protocolDescriptorFieldAddress),
sizeof(uint32_t));
if (!protocolDescriptorOffsetBytes.get()) {
Error = "Error reading protocol descriptor field in conformance descriptor.";
return protocolName;
}
auto protocolDescriptorOffset =
(const uint32_t *)protocolDescriptorOffsetBytes.get();
auto protocolDescriptorTarget = detail::applyRelativeOffset(
(const char *)protocolDescriptorFieldAddress,
(int32_t)*protocolDescriptorOffset);
// If indirect, attempt to get symbol name from external bindings
if ((uint64_t)protocolDescriptorTarget & 0x1) {
auto adjustedProtocolDescriptorTarget =
(const void *)((uint64_t)protocolDescriptorTarget & ~(0x1));
if (auto symbol = OpaquePointerReader(
remote::RemoteAddress(adjustedProtocolDescriptorTarget), 8)) {
Demangle::Context Ctx;
auto demangledRoot =
Ctx.demangleSymbolAsNode(symbol->getSymbol().str());
assert(demangledRoot->getKind() == Node::Kind::Global);
assert(demangledRoot->getChild(0)->getKind() ==
Node::Kind::ProtocolDescriptor);
protocolName = nodeToString(demangledRoot->getChild(0)->getChild(0));
} else {
Error = "Error reading external protocol address.";
return protocolName;
}
// If direct, read the protocol descriptor and get symbol name
} else {
auto protocolDescriptorBytes =
OpaqueByteReader(remote::RemoteAddress(protocolDescriptorTarget),
sizeof(ExternalProtocolDescriptor<PointerSize>));
if (!protocolDescriptorBytes.get()) {
Error = "Error reading protocol descriptor.";
return protocolName;
}
const ExternalProtocolDescriptor<PointerSize> *protocolDescriptor =
(const ExternalProtocolDescriptor<PointerSize> *)
protocolDescriptorBytes.get();
// Compute the address of the protocol descriptor's name field and read
// the offset
auto protocolNameOffsetAddress = detail::applyRelativeOffset(
(const char *)protocolDescriptorTarget,
(int32_t)protocolDescriptor->getNameOffset());
auto protocolNameOfsetBytes = OpaqueByteReader(
remote::RemoteAddress(protocolNameOffsetAddress), sizeof(uint32_t));
if (!protocolNameOfsetBytes.get()) {
Error = "Failed to read type name offset in a protocol descriptor.";
return protocolName;
}
auto protocolNameOffset =
(const uint32_t *)protocolNameOfsetBytes.get();
// Using the offset above, compute the address of the name field itsel
// and read it.
auto protocolNameAddress =
detail::applyRelativeOffset((const char *)protocolNameOffsetAddress,
(int32_t)*protocolNameOffset);
OpaqueStringReader(remote::RemoteAddress(protocolNameAddress),
protocolName);
}
return protocolName;
}
/// Given the address of a conformance descriptor, attempt to read it.
ProtocolConformanceInfo
readConformanceDescriptor(RemoteRef<void> conformanceRecordRef) {
const ExternalProtocolConformanceRecord<PointerSize> *CD =
(const ExternalProtocolConformanceRecord<PointerSize> *)
conformanceRecordRef.getLocalBuffer();
// Read the Protocol Conformance Descriptor by getting its address from
// the conformance record.
auto conformanceDescriptorAddress = (const char *)CD->getRelative(
(void *)conformanceRecordRef.getAddressData());
auto descriptorBytes = OpaqueByteReader(
remote::RemoteAddress(conformanceDescriptorAddress),
sizeof(ExternalProtocolConformanceDescriptor<PointerSize>));
if (!descriptorBytes.get()) {
Error = "Failed to read protocol conformance descriptor.";
return ProtocolConformanceInfo();
}
const ExternalProtocolConformanceDescriptor<PointerSize>
*conformanceDescriptorPtr =
(const ExternalProtocolConformanceDescriptor<PointerSize> *)
descriptorBytes.get();
auto conformingTypeName = getConformingTypeName(
conformanceDescriptorAddress, *conformanceDescriptorPtr);
auto conformanceProtocol = getConformanceProtocol(
conformanceDescriptorAddress, *conformanceDescriptorPtr);
return ProtocolConformanceInfo{conformingTypeName,
conformanceProtocol};
}
bool hasError() {
return !Error.empty();
}
};
public:
template <unsigned PointerSize>
void dumpConformanceSection(std::ostream &stream) {
// Collect all conformances and aggregate them per-conforming-type.
std::unordered_map<std::string, std::vector<std::string>> typeConformances;
ProtocolConformanceDescriptorReader<PointerSize> conformanceReader(
OpaqueByteReader, OpaqueStringReader, OpaquePointerReader);
for (const auto &section : ReflectionInfos) {
auto ConformanceBegin = section.Conformance.startAddress();
auto ConformanceEnd = section.Conformance.endAddress();
for (auto conformanceAddr = ConformanceBegin;
conformanceAddr != ConformanceEnd;
conformanceAddr = conformanceAddr.atByteOffset(4)) {
auto conformanceInfo =
conformanceReader.readConformanceDescriptor(conformanceAddr);
if (conformanceReader.hasError()) {
stream << "Error reading conformance descriptor: "
<< conformanceReader.Error << "\n";
continue;
}
if (typeConformances.count(conformanceInfo.typeName) != 0) {
typeConformances[conformanceInfo.typeName].push_back(
conformanceInfo.protocolName);
} else {
typeConformances.emplace(
conformanceInfo.typeName,
std::vector<std::string>{conformanceInfo.protocolName});
}
}
}
for (auto &pair : typeConformances) {
stream << pair.first << " : ";
bool first = true;
for (auto &protocol : pair.second) {
if (!first) {
stream << ", ";
}
first = false;
stream << protocol;
}
stream << "\n";
}
}
template <unsigned PointerSize>
void dumpAllSections(std::ostream &stream) {
stream << "FIELDS:\n";
stream << "=======\n";
dumpFieldSection(stream);
stream << "\n";
stream << "ASSOCIATED TYPES:\n";
stream << "=================\n";
dumpAssociatedTypeSection(stream);
stream << "\n";
stream << "BUILTIN TYPES:\n";
stream << "==============\n";
dumpBuiltinTypeSection(stream);
stream << "\n";
stream << "CAPTURE DESCRIPTORS:\n";
stream << "====================\n";
dumpCaptureSection(stream);
stream << "\n";
stream << "CONFORMANCES:\n";
stream << "=============\n";
dumpConformanceSection<PointerSize>(stream);
stream << "\n";
}
};
} // end namespace reflection
} // end namespace swift

View File

@@ -126,6 +126,7 @@ struct ReflectionContextHolder {
ReflectionContextOwner Owner;
reflection::TypeRefBuilder &Builder;
ObjectMemoryReader &Reader;
uint8_t PointerSize;
};
template <typename T>

View File

@@ -1,5 +1,3 @@
add_swift_host_library(swiftStaticMirror STATIC
ObjectFileContext.cpp)

View File

@@ -496,7 +496,7 @@ ObjectMemoryReader::resolvePointer(reflection::RemoteAddress Addr,
template <typename Runtime>
ReflectionContextHolder makeReflectionContextForMetadataReader(
std::shared_ptr<ObjectMemoryReader> reader) {
std::shared_ptr<ObjectMemoryReader> reader, uint8_t pointerSize) {
using ReflectionContext = reflection::ReflectionContext<Runtime>;
auto context = new ReflectionContext(reader);
auto &builder = context->getBuilder();
@@ -505,11 +505,7 @@ ReflectionContextHolder makeReflectionContextForMetadataReader(
}
return {ReflectionContextOwner(
context, [](void *x) { delete (ReflectionContext *)x; }),
builder, *reader};
}
uint8_t queryPointerSize(const std::vector<const ObjectFile *> &objectFiles) {
builder, *reader, pointerSize};
}
ReflectionContextHolder makeReflectionContextForObjectFiles(
@@ -521,6 +517,7 @@ ReflectionContextHolder makeReflectionContextForObjectFiles(
&pointerSize);
switch (pointerSize) {
case 4:
return makeReflectionContextForMetadataReader<
// FIXME: This could be configurable.
#if SWIFT_OBJC_INTEROP
@@ -528,7 +525,7 @@ ReflectionContextHolder makeReflectionContextForObjectFiles(
#else
External<NoObjCInterop<RuntimeTarget<4>>>
#endif
>(std::move(Reader));
>(std::move(Reader), pointerSize);
case 8:
return makeReflectionContextForMetadataReader<
// FIXME: This could be configurable.
@@ -537,7 +534,7 @@ ReflectionContextHolder makeReflectionContextForObjectFiles(
#else
External<NoObjCInterop<RuntimeTarget<8>>>
#endif
>(std::move(Reader));
>(std::move(Reader), pointerSize);
default:
fputs("unsupported word size in object file\n", stderr);
abort();

View File

@@ -18,7 +18,6 @@
#if SWIFT_ENABLE_REFLECTION
#include "swift/Reflection/TypeRefBuilder.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Reflection/Records.h"
#include "swift/Reflection/TypeLowering.h"
@@ -29,6 +28,7 @@
using namespace swift;
using namespace reflection;
using ReadBytesResult = swift::remote::MemoryReader::ReadBytesResult;
TypeRefBuilder::BuiltType
TypeRefBuilder::decodeMangledType(Node *node, bool forRequirement) {
@@ -496,61 +496,4 @@ void TypeRefBuilder::dumpCaptureSection(std::ostream &stream) {
}
}
/// Given the address of a conformance descriptor, attempt to read it.
static void readConformanceDescriptor(const ExternalProtocolConformanceRecord &record) {
// Read the flags to figure out how much space we should read.
// ContextDescriptorFlags flags;
// if (!Reader->readBytes(RemoteAddress(address), (uint8_t*)&flags,
// sizeof(flags)))
// return nullptr;
}
void TypeRefBuilder::dumpConformanceSection(std::ostream &stream) {
for (const auto &section : ReflectionInfos) {
for (const auto conformanceRecord : section.Conformance) {
stream << "dummy\n";
readConformanceDescriptor(conformanceRecord->get());
// switch (auto kind = conformance->getTypeKind()) {
// case TypeReferenceKind::DirectObjCClassName:
// stream << "DirectObjCClassName\n";
// break;
//
// case TypeReferenceKind::IndirectObjCClass:
// stream << "IndirectObjCClass\n";
// break;
//
// case TypeReferenceKind::DirectTypeDescriptor:
// case TypeReferenceKind::IndirectTypeDescriptor:
// stream << "TypeDescriptor\n";
// break;
// }
}
}
}
void TypeRefBuilder::dumpAllSections(std::ostream &stream) {
stream << "FIELDS:\n";
stream << "=======\n";
dumpFieldSection(stream);
stream << "\n";
stream << "ASSOCIATED TYPES:\n";
stream << "=================\n";
dumpAssociatedTypeSection(stream);
stream << "\n";
stream << "BUILTIN TYPES:\n";
stream << "==============\n";
dumpBuiltinTypeSection(stream);
stream << "\n";
stream << "CAPTURE DESCRIPTORS:\n";
stream << "====================\n";
dumpCaptureSection(stream);
stream << "\n";
stream << "CONFORMANCES:\n";
stream << "=============\n";
dumpConformanceSection(stream);
stream << "\n";
}
#endif

View File

@@ -217,7 +217,7 @@ swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
sectionFromInfo<const void *>(Info, Info.type_references),
sectionFromInfo<const void *>(Info, Info.reflection_strings),
// TODO: Conformance section
ConformanceSection(RemoteRef<void>(), 0)};
ReflectionSection<const void *>(nullptr, 0)};
Context->addReflectionInfo(ContextInfo);
}
@@ -238,7 +238,7 @@ void swift_reflection_addReflectionMappingInfo(
reflectionSectionFromLocalAndRemote<const void *>(Info.type_references),
reflectionSectionFromLocalAndRemote<const void *>(Info.reflection_strings),
// TODO: Conformance section
ConformanceSection(RemoteRef<void>(), 0)};
ReflectionSection<const void *>(nullptr, 0)};
Context->addReflectionInfo(ContextInfo);
}

View File

@@ -0,0 +1,4 @@
public protocol MyProto {}
struct StructA : MyProto, Hashable {
var x: Int
}

View File

@@ -0,0 +1,8 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -Xfrontend -enable-anonymous-context-mangled-names %S/Inputs/ConcreteTypes.swift %S/Inputs/Conformances.swift -parse-as-library -emit-module -emit-library -module-name TypesToReflect -o %t/Conformances
// RUN: %target-swift-reflection-dump -binary-filename %t/Conformances | %FileCheck %s
// CHECK: CONFORMANCES:
// CHECK: =============
// CHECK: StructA : MyProto, Swift.Hashable, Swift.Equatable

View File

@@ -115,7 +115,17 @@ static int doDumpReflectionSections(ArrayRef<std::string> BinaryFilenames,
switch (Action) {
case ActionType::DumpReflectionSections:
// Dump everything
builder.dumpAllSections(stream);
switch (context.PointerSize) {
case 4:
builder.dumpAllSections<4>(stream);
break;
case 8:
builder.dumpAllSections<8>(stream);
break;
default:
fputs("unsupported word size in object file\n", stderr);
abort();
}
break;
case ActionType::DumpTypeLowering: {
for (std::string Line; std::getline(std::cin, Line);) {