Skip to content

Implement reflection support for Symbolic Extended Existential types. #82389

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
37 changes: 37 additions & 0 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,43 @@ void decodeRequirement(
}
}

/// Extract the protocol and requirement nodes from a shape symbol.
static inline std::pair<NodePointer, NodePointer>
decodeShape(NodePointer Node) {
if (!Node || Node->getKind() != Node::Kind::Global ||
Node->getNumChildren() != 1)
return {nullptr, nullptr};
Node = Node->getChild(0);
if (Node && (Node->getKind() == Node::Kind::Uniquable) &&
Node->getNumChildren() == 1)
Node = Node->getChild(0);
if (!Node || Node->getKind() != Node::Kind::ExtendedExistentialTypeShape ||
Node->getNumChildren() != 2)
return {nullptr, nullptr};
Node = Node->getChild(1);
if (!Node || Node->getKind() != Node::Kind::Type ||
Node->getNumChildren() != 1)
return {nullptr, nullptr};
Node = Node->getChild(0);
if (!Node || Node->getKind() != Node::Kind::ConstrainedExistential ||
Node->getNumChildren() != 2)
return {nullptr, nullptr};
NodePointer Requirements = Node->getChild(1);
if (!Requirements || Requirements->getKind() !=
Node::Kind::ConstrainedExistentialRequirementList)
return {nullptr, nullptr};

Node = Node->getChild(0);
if (!Node || Node->getKind() != Node::Kind::Type ||
Node->getNumChildren() != 1)
return {nullptr, nullptr};
NodePointer Protocol = Node;
if (!Protocol)
return {nullptr, nullptr};

return {Protocol, Requirements};
}

#define MAKE_NODE_TYPE_ERROR(Node, Fmt, ...) \
TYPE_LOOKUP_ERROR_FMT("TypeDecoder.h:%u: Node kind %u \"%.*s\" - " Fmt, \
__LINE__, (unsigned)Node->getKind(), \
Expand Down
235 changes: 120 additions & 115 deletions include/swift/Remote/MetadataReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -509,8 +509,8 @@ class MetadataReader {
// The symbolic reference points at a non-unique extended
// existential type shape.
return dem.createNode(
Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference,
resolved.getResolvedAddress().getAddressData());
Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference,
resolved.getResolvedAddress().getAddressData());
}
case Demangle::SymbolicReferenceKind::ObjectiveCProtocol: {
// 'resolved' points to a struct of two relative addresses.
Expand Down Expand Up @@ -886,6 +886,74 @@ class MetadataReader {
return resolver.swiftProtocol(Demangled);
}

BuiltType readTypeFromShape(
RemoteAbsolutePointer shapeAddress,
std::function<std::optional<std::vector<BuiltType>>(unsigned)> getArgs) {
StoredPointer addr = shapeAddress.getResolvedAddress().getAddressData();
ShapeRef Shape = readShape(addr);
if (!Shape)
return BuiltType();

assert(Shape->hasGeneralizationSignature());
auto builtArgs = getArgs(Shape->getGenSigArgumentLayoutSizeInWords());

// Pull out the existential type from the mangled type name.
Demangler dem;
auto mangledExistentialAddr =
resolveRelativeField(Shape, Shape->ExistentialType);
auto node = readMangledName(RemoteAddress(mangledExistentialAddr),
MangledNameKind::Type, dem);
if (!node)
return BuiltType();

BuiltType builtProto = decodeMangledType(node).getType();
if (!builtProto)
return BuiltType();

if (builtArgs) {
// Build up a substitution map for the generalized signature.
BuiltGenericSignature sig =
decodeRuntimeGenericSignature(Shape,
Shape->getGeneralizationSignature())
.getType();
if (!sig)
return BuiltType();

BuiltSubstitutionMap subst =
Builder.createSubstitutionMap(sig, *builtArgs);
if (subst.empty())
return BuiltType();

builtProto = Builder.subst(builtProto, subst);
if (!builtProto)
return BuiltType();
}

// Read the type expression to build up any remaining layers of
// existential metatype.
if (Shape->Flags.hasTypeExpression()) {
Demangler dem;

// Read the mangled name.
auto mangledContextName = Shape->getTypeExpression();
auto mangledNameAddress =
resolveRelativeField(Shape, mangledContextName->name);
auto node = readMangledName(RemoteAddress(mangledNameAddress),
MangledNameKind::Type, dem);
if (!node)
return BuiltType();

while (node->getKind() == Demangle::Node::Kind::Type &&
node->getNumChildren() &&
node->getChild(0)->getKind() == Demangle::Node::Kind::Metatype &&
node->getChild(0)->getNumChildren()) {
builtProto = Builder.createExistentialMetatypeType(builtProto);
node = node->getChild(0)->getChild(0);
}
}
return builtProto;
}

/// Given a remote pointer to metadata, attempt to turn it into a type.
BuiltType
readTypeFromMetadata(StoredPointer MetadataAddress,
Expand Down Expand Up @@ -1081,79 +1149,25 @@ class MetadataReader {
}
case MetadataKind::ExtendedExistential: {
auto Exist = cast<TargetExtendedExistentialTypeMetadata<Runtime>>(Meta);

// Read the shape for this existential.
StoredPointer shapeAddress = stripSignedPointer(Exist->Shape);
ShapeRef Shape = readShape(shapeAddress);
if (!Shape)
return BuiltType();

const unsigned shapeArgumentCount
= Shape->getGenSigArgumentLayoutSizeInWords();
// Pull out the arguments to the generalization signature.
assert(Shape->hasGeneralizationSignature());
std::vector<BuiltType> builtArgs;
for (unsigned i = 0; i < shapeArgumentCount; ++i) {
auto remoteArg = Exist->getGeneralizationArguments()[i];
auto builtArg = readTypeFromMetadata(remoteArg, false, recursion_limit);
if (!builtArg)
return BuiltType();
builtArgs.push_back(builtArg);
}

// Pull out the existential type from the mangled type name.
Demangler dem;
auto mangledExistentialAddr =
resolveRelativeField(Shape, Shape->ExistentialType);
auto node = readMangledName(RemoteAddress(mangledExistentialAddr),
MangledNameKind::Type, dem);
if (!node)
return BuiltType();

BuiltType builtProto = decodeMangledType(node).getType();
if (!builtProto)
return BuiltType();

// Build up a substitution map for the generalized signature.
BuiltGenericSignature sig =
decodeRuntimeGenericSignature(Shape,
Shape->getGeneralizationSignature())
.getType();
if (!sig)
return BuiltType();

BuiltSubstitutionMap subst =
Builder.createSubstitutionMap(sig, builtArgs);
if (subst.empty())
return BuiltType();

builtProto = Builder.subst(builtProto, subst);
if (!builtProto)
return BuiltType();

// Read the type expression to build up any remaining layers of
// existential metatype.
if (Shape->Flags.hasTypeExpression()) {
Demangler dem;

// Read the mangled name.
auto mangledContextName = Shape->getTypeExpression();
auto mangledNameAddress =
resolveRelativeField(Shape, mangledContextName->name);
auto node = readMangledName(RemoteAddress(mangledNameAddress),
MangledNameKind::Type, dem);
if (!node)
return BuiltType();

while (node->getKind() == Demangle::Node::Kind::Type &&
node->getNumChildren() &&
node->getChild(0)->getKind() == Demangle::Node::Kind::Metatype &&
node->getChild(0)->getNumChildren()) {
builtProto = Builder.createExistentialMetatypeType(builtProto);
node = node->getChild(0)->getChild(0);
}
}

auto builtProto = readTypeFromShape(
RemoteAddress(shapeAddress),
[&](unsigned shapeArgumentCount)
-> std::optional<std::vector<BuiltType>> {
// Pull out the arguments to the generalization signature.
std::vector<BuiltType> builtArgs;
for (unsigned i = 0; i < shapeArgumentCount; ++i) {
auto remoteArg = Exist->getGeneralizationArguments()[i];
auto builtArg =
readTypeFromMetadata(remoteArg, false, recursion_limit);
if (!builtArg)
return std::nullopt;
builtArgs.push_back(builtArg);
}
return builtArgs;
});
TypeCache[TypeCacheKey] = builtProto;
return builtProto;
}
Expand Down Expand Up @@ -1366,69 +1380,60 @@ class MetadataReader {
if (address.getOffset() == 0)
return ParentContextDescriptorRef(address.getSymbol());
}

return ParentContextDescriptorRef(
readContextDescriptor(address.getResolvedAddress().getAddressData()));
readContextDescriptor(address.getResolvedAddress().getAddressData()));
}

ShapeRef
readShape(StoredPointer address) {
ShapeRef readShape(StoredPointer address) {
if (address == 0)
return nullptr;

using ShapeHeader = TargetExtendedExistentialTypeShape<Runtime>;
auto cached = ShapeCache.find(address);
if (cached != ShapeCache.end())
return ShapeRef(address,
reinterpret_cast<const TargetExtendedExistentialTypeShape<Runtime> *>(
cached->second.get()));

ExtendedExistentialTypeShapeFlags flags;
if (!Reader->readBytes(RemoteAddress(address), (uint8_t*)&flags,
sizeof(flags)))
return nullptr;
return ShapeRef(
address, reinterpret_cast<const ShapeHeader *>(cached->second.get()));

// Read the size of the requirement signature.
uint64_t reqSigGenericSize = 0;
uint64_t genericHeaderSize = sizeof(GenericContextDescriptorHeader);
uint64_t descriptorSize;
{
GenericContextDescriptorHeader header;
auto headerAddr = address + sizeof(flags);

if (!Reader->readBytes(RemoteAddress(headerAddr),
(uint8_t*)&header, sizeof(header)))
auto readResult =
Reader->readBytes(RemoteAddress(address), sizeof(ShapeHeader));
if (!readResult)
return nullptr;

reqSigGenericSize = reqSigGenericSize
+ (header.NumParams + 3u & ~3u)
+ header.NumRequirements
* sizeof(TargetGenericRequirementDescriptor<Runtime>);
}
uint64_t typeExprSize = flags.hasTypeExpression() ? sizeof(StoredPointer) : 0;
uint64_t suggestedVWSize = flags.hasSuggestedValueWitnesses() ? sizeof(StoredPointer) : 0;

uint64_t size = sizeof(ExtendedExistentialTypeShapeFlags) +
sizeof(TargetRelativeDirectPointer<Runtime, const char,
/*nullable*/ false>) +
genericHeaderSize + typeExprSize + suggestedVWSize +
reqSigGenericSize;
if (size > MaxMetadataSize)
auto shapeHeader =
reinterpret_cast<const ShapeHeader *>(readResult.get());

// Read the size of the requirement signature.
uint64_t reqSigGenericSize = 0;
auto flags = shapeHeader->Flags;
auto &reqSigHeader = shapeHeader->ReqSigHeader;
reqSigGenericSize =
reqSigGenericSize + (reqSigHeader.NumParams + 3u & ~3u) +
reqSigHeader.NumRequirements *
sizeof(TargetGenericRequirementDescriptor<Runtime>);
uint64_t typeExprSize =
flags.hasTypeExpression() ? sizeof(StoredPointer) : 0;
uint64_t suggestedVWSize =
flags.hasSuggestedValueWitnesses() ? sizeof(StoredPointer) : 0;

descriptorSize = sizeof(shapeHeader) + typeExprSize + suggestedVWSize +
reqSigGenericSize;
}
if (descriptorSize > MaxMetadataSize)
return nullptr;
auto readResult = Reader->readBytes(RemoteAddress(address), size);
auto readResult = Reader->readBytes(RemoteAddress(address), descriptorSize);
if (!readResult)
return nullptr;

auto descriptor =
reinterpret_cast<const TargetExtendedExistentialTypeShape<Runtime> *>(
readResult.get());
auto descriptor = reinterpret_cast<const ShapeHeader *>(readResult.get());

ShapeCache.insert(
std::make_pair(address, std::move(readResult)));
ShapeCache.insert(std::make_pair(address, std::move(readResult)));
return ShapeRef(address, descriptor);
}

/// Given the address of a context descriptor, attempt to read it.
ContextDescriptorRef
readContextDescriptor(StoredPointer address) {
ContextDescriptorRef readContextDescriptor(StoredPointer address) {
if (address == 0)
return nullptr;

Expand Down
58 changes: 58 additions & 0 deletions include/swift/RemoteInspection/TypeRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,64 @@ class ConstrainedExistentialTypeRef final : public TypeRef {
}
};

class SymbolicExtendedExistentialTypeRef final : public TypeRef {
const ProtocolCompositionTypeRef *Protocol;
std::vector<TypeRefRequirement> Requirements;
std::vector<const TypeRef *> Arguments;
ExtendedExistentialTypeShapeFlags Flags;

static TypeRefID Profile(const ProtocolCompositionTypeRef *Protocol,
llvm::ArrayRef<TypeRefRequirement> Requirements,
llvm::ArrayRef<const TypeRef *> Arguments,
ExtendedExistentialTypeShapeFlags Flags) {
TypeRefID ID;
ID.addPointer(Protocol);
for (auto reqt : Requirements) {
ID.addPointer(reqt.getFirstType());
if (reqt.getKind() != RequirementKind::Layout)
ID.addPointer(reqt.getSecondType());
else
ID.addInteger(
unsigned(0)); // FIXME: Layout constraints aren't implemented yet
ID.addInteger(unsigned(reqt.getKind()));
}

for (auto &Arg : Arguments)
ID.addPointer(Arg);
return ID;
}

public:
SymbolicExtendedExistentialTypeRef(
const ProtocolCompositionTypeRef *Protocol,
llvm::ArrayRef<TypeRefRequirement> Requirements,
llvm::ArrayRef<const TypeRef *> Args,
ExtendedExistentialTypeShapeFlags Flags)
: TypeRef(TypeRefKind::SymbolicExtendedExistential), Protocol(Protocol),
Requirements(Requirements), Arguments(Args), Flags(Flags) {}

template <typename Allocator>
static const SymbolicExtendedExistentialTypeRef *
create(Allocator &A, const ProtocolCompositionTypeRef *Protocol,
llvm::ArrayRef<TypeRefRequirement> Requirements,
llvm::ArrayRef<const TypeRef *> Args,
ExtendedExistentialTypeShapeFlags Flags) {
FIND_OR_CREATE_TYPEREF(A, SymbolicExtendedExistentialTypeRef, Protocol,
Requirements, Args, Flags);
}

const ProtocolCompositionTypeRef *getProtocol() const { return Protocol; }
llvm::ArrayRef<TypeRefRequirement> getRequirements() const {
return Requirements;
}
llvm::ArrayRef<const TypeRef *> getArguments() const { return Arguments; }
ExtendedExistentialTypeShapeFlags getFlags() const { return Flags; }

static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::SymbolicExtendedExistential;
}
};

class MetatypeTypeRef final : public TypeRef {
const TypeRef *InstanceType;
bool WasAbstract;
Expand Down
Loading