Skip to content

Add interface for lookup of externally stored field descriptors #69752

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions include/swift/RemoteInspection/DescriptorFinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#ifndef SWIFT_REFLECTION_DESCRIPTOR_FINDER_H
#define SWIFT_REFLECTION_DESCRIPTOR_FINDER_H

#include "swift/Demangling/Demangle.h"
#include "swift/RemoteInspection/Records.h"
#include "llvm/ADT/StringRef.h"

namespace swift {
Expand All @@ -39,13 +41,69 @@ struct BuiltinTypeDescriptorBase {
virtual llvm::StringRef getMangledTypeName() = 0;
};

/// An abstract interface for a field record.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is a FieldRecord versus a FieldDescriptor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A field descriptor describes a nominal type, it has an array of field records, which describes that type's fields.

struct FieldRecordBase {
const bool IsIndirectCase;
const bool IsVar;
const bool HasMangledTypeName;

FieldRecordBase(bool IsIndirectCase, bool IsVar,
bool HasMangledTypeName)
: IsIndirectCase(IsIndirectCase), IsVar(IsVar),
HasMangledTypeName(HasMangledTypeName) {}

virtual ~FieldRecordBase(){};

virtual llvm::StringRef getFieldName() = 0;
virtual Demangle::Node *getDemangledTypeName() = 0;
};

/// An abstract interface for a field descriptor.
struct FieldDescriptorBase {
const FieldDescriptorKind Kind;
const bool HasSuperClass;

FieldDescriptorBase(FieldDescriptorKind Kind, bool HasSuperClass)
: Kind(Kind), HasSuperClass(HasSuperClass) {}

bool isEnum() const {
return (Kind == FieldDescriptorKind::Enum ||
Kind == FieldDescriptorKind::MultiPayloadEnum);
}

bool isClass() const {
return (Kind == FieldDescriptorKind::Class ||
Kind == FieldDescriptorKind::ObjCClass);
}

bool isProtocol() const {
return (Kind == FieldDescriptorKind::Protocol ||
Kind == FieldDescriptorKind::ClassProtocol ||
Kind == FieldDescriptorKind::ObjCProtocol);
}

bool isStruct() const {
return Kind == FieldDescriptorKind::Struct;
}

virtual ~FieldDescriptorBase(){};

virtual Demangle::Node *demangleSuperclass() = 0;
virtual std::vector<std::unique_ptr<FieldRecordBase>>
getFieldRecords() = 0;
};

/// Interface for finding type descriptors. Implementors may provide descriptors
/// that live inside or outside reflection metadata.
struct DescriptorFinder {
virtual ~DescriptorFinder(){};

virtual std::unique_ptr<BuiltinTypeDescriptorBase>
getBuiltinTypeDescriptor(const TypeRef *TR) = 0;


virtual std::unique_ptr<FieldDescriptorBase>
getFieldDescriptor(const TypeRef *TR) = 0;
};

} // namespace reflection
Expand Down
14 changes: 8 additions & 6 deletions include/swift/RemoteInspection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,8 @@ class TypeRefBuilder {
return ReflectionInfos;
}

/// Load unsubstituted field types for a nominal type.
RemoteRef<FieldDescriptor> getFieldTypeInfo(const TypeRef *TR);
std::unique_ptr<FieldDescriptorBase>
getFieldDescriptor(const TypeRef *TR) override;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where did the comment go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the whole function, including comment, to a private section.


std::unique_ptr<BuiltinTypeDescriptorBase>
getBuiltinTypeDescriptor(const TypeRef *TR) override;
Expand Down Expand Up @@ -512,6 +512,9 @@ class TypeRefBuilder {
/// Get the primitive type lowering for a builtin type.
RemoteRef<BuiltinTypeDescriptor> getBuiltinTypeInfo(const TypeRef *TR);

/// Load unsubstituted field types for a nominal type.
RemoteRef<FieldDescriptor> getFieldTypeInfo(const TypeRef *TR);

void populateFieldTypeInfoCacheWithReflectionAtIndex(size_t Index);

llvm::Optional<RemoteRef<FieldDescriptor>>
Expand Down Expand Up @@ -1532,12 +1535,11 @@ class TypeRefBuilder {
}
const TypeRef *lookupSuperclass(const TypeRef *TR);

RemoteRef<FieldDescriptor> getFieldTypeInfo(const TypeRef *TR) {
return RDF.getFieldTypeInfo(TR);
}
std::unique_ptr<FieldDescriptorBase>
getFieldDescriptor(const TypeRef *TR);

/// Get the parsed and substituted field types for a nominal type.
bool getFieldTypeRefs(const TypeRef *TR, RemoteRef<FieldDescriptor> FD,
bool getFieldTypeRefs(const TypeRef *TR, FieldDescriptorBase &FD,
remote::TypeInfoProvider *ExternalTypeInfo,
std::vector<FieldTypeInfo> &Fields);

Expand Down
17 changes: 9 additions & 8 deletions stdlib/public/RemoteInspection/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ class ExistentialTypeInfoBuilder {
continue;
}

auto FD = TC.getBuilder().getFieldTypeInfo(P);
auto FD = TC.getBuilder().getFieldDescriptor(P);
if (FD == nullptr) {
DEBUG_LOG(fprintf(stderr, "No field descriptor: "); P->dump())
Invalid = true;
Expand Down Expand Up @@ -1424,7 +1424,7 @@ class ExistentialTypeInfoBuilder {
return;
}

const auto &FD = TC.getBuilder().getFieldTypeInfo(T);
const auto &FD = TC.getBuilder().getFieldDescriptor(T);
if (FD == nullptr) {
DEBUG_LOG(fprintf(stderr, "No field descriptor: "); T->dump())
Invalid = true;
Expand Down Expand Up @@ -2093,7 +2093,7 @@ class EnumTypeInfoBuilder {
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
BitwiseTakable(true), Invalid(false) {}

const TypeInfo *build(const TypeRef *TR, RemoteRef<FieldDescriptor> FD,
const TypeInfo *build(const TypeRef *TR, FieldDescriptorBase &FD,
remote::TypeInfoProvider *ExternalTypeInfo) {
// Count various categories of cases:
unsigned NonPayloadCases = 0; // `case a`
Expand Down Expand Up @@ -2415,7 +2415,7 @@ class LowerType
return nullptr;
};

auto FD = TC.getBuilder().getFieldTypeInfo(TR);
auto FD = TC.getBuilder().getFieldDescriptor(TR);
if (FD == nullptr || FD->isStruct()) {
// Maybe this type is opaque -- look for a builtin
// descriptor to see if we at least know its size
Expand Down Expand Up @@ -2454,7 +2454,8 @@ class LowerType
RecordTypeInfoBuilder builder(TC, RecordKind::Struct);

std::vector<FieldTypeInfo> Fields;
if (!TC.getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields))
if (!TC.getBuilder().getFieldTypeRefs(TR, *FD.get(), ExternalTypeInfo,
Fields))
return nullptr;

for (auto Field : Fields)
Expand All @@ -2464,7 +2465,7 @@ class LowerType
case FieldDescriptorKind::Enum:
case FieldDescriptorKind::MultiPayloadEnum: {
EnumTypeInfoBuilder builder(TC);
return builder.build(TR, FD, ExternalTypeInfo);
return builder.build(TR, *FD.get(), ExternalTypeInfo);
}
case FieldDescriptorKind::ObjCClass:
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
Expand Down Expand Up @@ -2706,7 +2707,7 @@ TypeConverter::getTypeInfo(const TypeRef *TR,
const RecordTypeInfo *TypeConverter::getClassInstanceTypeInfo(
const TypeRef *TR, unsigned start,
remote::TypeInfoProvider *ExternalTypeInfo) {
auto FD = getBuilder().getFieldTypeInfo(TR);
auto FD = getBuilder().getFieldDescriptor(TR);
if (FD == nullptr) {
DEBUG_LOG(fprintf(stderr, "No field descriptor: "); TR->dump());
return nullptr;
Expand All @@ -2720,7 +2721,7 @@ const RecordTypeInfo *TypeConverter::getClassInstanceTypeInfo(
RecordTypeInfoBuilder builder(*this, RecordKind::ClassInstance);

std::vector<FieldTypeInfo> Fields;
if (!getBuilder().getFieldTypeRefs(TR, FD, ExternalTypeInfo, Fields))
if (!getBuilder().getFieldTypeRefs(TR, *FD.get(), ExternalTypeInfo, Fields))
return nullptr;

// Start layout from the given instance start offset. This should
Expand Down
95 changes: 80 additions & 15 deletions stdlib/public/RemoteInspection/TypeRefBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,15 @@ TypeRefBuilder::ReflectionTypeDescriptorFinder::lookupTypeWitness(
}

const TypeRef *TypeRefBuilder::lookupSuperclass(const TypeRef *TR) {
const auto &FD = getFieldTypeInfo(TR);
const auto &FD = getFieldDescriptor(TR);
if (FD == nullptr)
return nullptr;

if (!FD->hasSuperclass())
if (!FD->HasSuperClass)
return nullptr;

ScopedNodeFactoryCheckpoint checkpoint(this);
auto Demangled = demangleTypeRef(readTypeRef(FD, FD->Superclass));
auto Demangled = FD->demangleSuperclass();
auto Unsubstituted = decodeMangledType(Demangled);
if (!Unsubstituted)
return nullptr;
Expand Down Expand Up @@ -375,34 +375,97 @@ TypeRefBuilder::ReflectionTypeDescriptorFinder::getFieldTypeInfo(
return nullptr;
}

namespace {
// A field record implementation that wraps a reflection field record.
class FieldRecordImpl : public FieldRecordBase {
RemoteRef<const FieldRecord> Field;
TypeRefBuilder &Builder;

public:
FieldRecordImpl(RemoteRef<const FieldRecord> FR, TypeRefBuilder &Builder)
: FieldRecordBase(FR->isIndirectCase(), FR->isVar(),
FR->hasMangledTypeName()),
Field(FR), Builder(Builder) {}

~FieldRecordImpl() override {}

StringRef getFieldName() override {
return Builder.getTypeRefString(
Builder.readTypeRef(Field, Field->FieldName));
}

NodePointer getDemangledTypeName() override {
return Builder.demangleTypeRef(
Builder.readTypeRef(Field, Field->MangledTypeName));
}
};

/// A field descriptor implementation that wraps a reflection field
/// descriptor.
class FieldDescriptorImpl : public FieldDescriptorBase {
RemoteRef<FieldDescriptor> FD;
TypeRefBuilder &Builder;

public:
FieldDescriptorImpl(RemoteRef<FieldDescriptor> FD, TypeRefBuilder &Builder)
: FieldDescriptorBase(FD->Kind, FD->hasSuperclass()), FD(FD),
Builder(Builder) {}

~FieldDescriptorImpl() override {}

NodePointer demangleSuperclass() override {
return Builder.demangleTypeRef(Builder.readTypeRef(FD, FD->Superclass));
}

std::vector<std::unique_ptr<FieldRecordBase>> getFieldRecords() override {
std::vector<std::unique_ptr<FieldRecordBase>> FieldRecords;
for (auto &FieldRef : *FD.getLocalBuffer()) {
FieldRecords.emplace_back(
std::make_unique<FieldRecordImpl>(FD.getField(FieldRef), Builder));
}
return FieldRecords;
}
};
} // namespace

std::unique_ptr<FieldDescriptorBase>
TypeRefBuilder::ReflectionTypeDescriptorFinder::getFieldDescriptor(
const TypeRef *TR) {
if (auto FDI = getFieldTypeInfo(TR))
return std::make_unique<FieldDescriptorImpl>(FDI, Builder);
return nullptr;
}

std::unique_ptr<FieldDescriptorBase>
TypeRefBuilder::getFieldDescriptor(const TypeRef *TR) {
for (auto DF : getDescriptorFinders())
if (auto descriptor = DF->getFieldDescriptor(TR))
return descriptor;
return nullptr;
}

bool TypeRefBuilder::getFieldTypeRefs(
const TypeRef *TR, RemoteRef<FieldDescriptor> FD,
const TypeRef *TR, FieldDescriptorBase &FD,
remote::TypeInfoProvider *ExternalTypeInfo,
std::vector<FieldTypeInfo> &Fields) {
if (FD == nullptr)
return false;

auto Subs = TR->getSubstMap();
if (!Subs)
return false;

int FieldValue = -1;
for (auto &FieldRef : *FD.getLocalBuffer()) {
auto Field = FD.getField(FieldRef);

auto FieldName = getTypeRefString(readTypeRef(Field, Field->FieldName));
for (auto &Field : FD.getFieldRecords()) {
auto FieldName = Field->getFieldName();
FieldValue += 1;

// Empty cases of enums do not have a type
if (FD->isEnum() && !Field->hasMangledTypeName()) {
if (FD.isEnum() && !Field->HasMangledTypeName) {
Fields.push_back(
FieldTypeInfo::forEmptyCase(FieldName.str(), FieldValue));
continue;
}

ScopedNodeFactoryCheckpoint checkpoint(this);
auto Demangled =
demangleTypeRef(readTypeRef(Field, Field->MangledTypeName));
auto Demangled = Field->getDemangledTypeName();
auto Unsubstituted = decodeMangledType(Demangled);
if (!Unsubstituted)
return false;
Expand All @@ -412,7 +475,7 @@ bool TypeRefBuilder::getFieldTypeRefs(
// `case a([T?])` is generic, but `case a([Int?])` is not.
bool IsGeneric = false;
auto Substituted = Unsubstituted->subst(*this, *Subs, IsGeneric);
bool IsIndirect = FD->isEnum() && Field->isIndirectCase();
bool IsIndirect = FD.isEnum() && Field->IsIndirectCase;

auto FieldTI = FieldTypeInfo(FieldName.str(), FieldValue, Substituted,
IsIndirect, IsGeneric);
Expand Down Expand Up @@ -471,6 +534,7 @@ TypeRefBuilder::ReflectionTypeDescriptorFinder::getBuiltinTypeInfo(
return nullptr;
}

namespace {
/// A builtin type descriptor implementation that wraps a reflection builtin
/// type descriptor.
class BuiltinTypeDescriptorImpl : public BuiltinTypeDescriptorBase {
Expand All @@ -491,6 +555,7 @@ class BuiltinTypeDescriptorImpl : public BuiltinTypeDescriptorBase {
return Builder.getTypeRefString(Builder.readTypeRef(BTD, BTD->TypeName));
};
};
} // namespace

std::unique_ptr<BuiltinTypeDescriptorBase>
TypeRefBuilder::ReflectionTypeDescriptorFinder::getBuiltinTypeDescriptor(
Expand Down