Skip to content

[5.7] Implement symbolic demangling for extended existential metadata #59845

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
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
9 changes: 9 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ The following symbolic reference kinds are currently implemented:
metadata-access-function ::= '\x09' .{4} // Reference points directly to metadata access function that can be invoked to produce referenced object
#endif

#if SWIFT_RUNTIME_VERISON >= 5.7
symbolic-extended-existential-type-shape ::= '\x0A' .{4} // Reference points directly to an ExtendedExistentialTypeShape
symbolic-extended-existential-type-shape ::= '\x0B' .{4} // Reference points directly to a NonUniqueExtendedExistentialTypeShape
#endif

A mangled name may also include ``\xFF`` bytes, which are only used for
alignment padding. They do not affect what the mangled name references and can
be skipped over and ignored.
Expand Down Expand Up @@ -653,6 +658,10 @@ Types
type ::= type assoc-type-list 'QX' // associated type relative to base `type`
#endif

#if SWIFT_RUNTIME_VERSION >= 5.7
type ::= symbolic-extended-existential-type-shape type* retroactive-conformance* 'Xj'
#endif

protocol-list ::= protocol '_' protocol*
protocol-list ::= empty-list

Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ class ASTBuilder {
Type createConstrainedExistentialType(Type base,
ArrayRef<BuiltRequirement> constraints);

Type createSymbolicExtendedExistentialType(NodePointer shapeNode,
ArrayRef<Type> genArgs);

Type createExistentialMetatypeType(Type instance,
Optional<Demangle::ImplMetatypeRepresentation> repr=None);

Expand Down
55 changes: 51 additions & 4 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "swift/Basic/Mangler.h"
#include "swift/AST/Types.h"
#include "swift/AST/Decl.h"
#include "swift/Basic/TaggedUnion.h"

namespace clang {
class NamedDecl;
Expand Down Expand Up @@ -79,8 +80,50 @@ class ASTMangler : public Mangler {
bool RespectOriginallyDefinedIn = true;

public:
using SymbolicReferent = llvm::PointerUnion<const NominalTypeDecl *,
const OpaqueTypeDecl *>;
class SymbolicReferent {
public:
enum Kind {
NominalType,
OpaqueType,
ExtendedExistentialTypeShape,
};
private:
// TODO: make a TaggedUnion variant that works with an explicit
// kind instead of requiring this redundant kind storage.
TaggedUnion<const NominalTypeDecl *,
const OpaqueTypeDecl *,
Type>
storage;
Kind kind;

SymbolicReferent(Kind kind, Type type) : storage(type), kind(kind) {}
public:
SymbolicReferent(const NominalTypeDecl *decl)
: storage(decl), kind(NominalType) {}
SymbolicReferent(const OpaqueTypeDecl *decl)
: storage(decl), kind(OpaqueType) {}
static SymbolicReferent forExtendedExistentialTypeShape(Type type) {
return SymbolicReferent(ExtendedExistentialTypeShape, type);
}

Kind getKind() const { return kind; }

bool isNominalType() const { return kind == NominalType; }
const NominalTypeDecl *getNominalType() const {
assert(kind == NominalType);
return storage.get<const NominalTypeDecl *>();
}

const OpaqueTypeDecl *getOpaqueType() const {
assert(kind == OpaqueType);
return storage.get<const OpaqueTypeDecl *>();
}

Type getType() const {
assert(kind == ExtendedExistentialTypeShape);
return storage.get<Type>();
}
};
protected:

/// If set, the mangler calls this function to determine whether to symbolic
Expand All @@ -90,8 +133,8 @@ class ASTMangler : public Mangler {

bool canSymbolicReference(SymbolicReferent referent) {
// Marker protocols cannot ever be symbolically referenced.
if (auto nominal = referent.dyn_cast<const NominalTypeDecl *>()) {
if (auto proto = dyn_cast<ProtocolDecl>(nominal)) {
if (referent.isNominalType()) {
if (auto proto = dyn_cast<ProtocolDecl>(referent.getNominalType())) {
if (proto->isMarkerProtocol())
return false;
}
Expand Down Expand Up @@ -521,6 +564,10 @@ class ASTMangler : public Mangler {
GenericSignature sig);
void appendOpParamForLayoutConstraint(LayoutConstraint Layout);

void appendSymbolicExtendedExistentialType(SymbolicReferent shapeReferent,
Type type,
GenericSignature sig,
const ValueDecl *forDecl);
void appendSymbolicReference(SymbolicReferent referent);

void appendOpaqueDeclName(const OpaqueTypeDecl *opaqueDecl);
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -6529,6 +6529,8 @@ inline bool TypeBase::isClassExistentialType() {
return pt->requiresClass();
if (auto pct = dyn_cast<ProtocolCompositionType>(T))
return pct->requiresClass();
if (auto ppt = dyn_cast<ParameterizedProtocolType>(T))
return ppt->requiresClass();
if (auto existential = dyn_cast<ExistentialType>(T))
return existential->requiresClass();
return false;
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ NODE(BackDeploymentThunk)
NODE(BackDeploymentFallback)
NODE(ExtendedExistentialTypeShape)
NODE(Uniquable)
NODE(UniqueExtendedExistentialTypeShapeSymbolicReference)
NODE(NonUniqueExtendedExistentialTypeShapeSymbolicReference)
NODE(SymbolicExtendedExistentialType)

#undef CONTEXT_NODE
#undef NODE
6 changes: 6 additions & 0 deletions include/swift/Demangling/Demangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,10 @@ enum class SymbolicReferenceKind : uint8_t {
/// A symbolic reference to an accessor function, which can be executed in
/// the process to get a pointer to the referenced entity.
AccessorFunctionReference,
/// A symbolic reference to a unique extended existential type shape.
UniqueExtendedExistentialTypeShape,
/// A symbolic reference to a non-unique extended existential type shape.
NonUniqueExtendedExistentialTypeShape,
};

using SymbolicReferenceResolver_t = NodePointer (SymbolicReferenceKind,
Expand Down Expand Up @@ -516,6 +520,7 @@ class Demangler : public NodeFactory {
const Vector<NodePointer> &TypeLists,
size_t TypeListIdx);
NodePointer popAnyProtocolConformanceList();
NodePointer popRetroactiveConformances();
NodePointer demangleRetroactiveConformance();
NodePointer demangleInitializer();
NodePointer demangleImplParamConvention(Node::Kind ConvKind);
Expand All @@ -530,6 +535,7 @@ class Demangler : public NodeFactory {
NodePointer demangleAssociatedTypeSimple(NodePointer GenericParamIdx);
NodePointer demangleAssociatedTypeCompound(NodePointer GenericParamIdx);
NodePointer demangleExtendedExistentialShape(char kind);
NodePointer demangleSymbolicExtendedExistentialType();

NodePointer popAssocTypeName();
NodePointer popAssocTypePath();
Expand Down
42 changes: 30 additions & 12 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -547,18 +547,8 @@ class TypeDecoder {
Node->getNumChildren());

llvm::SmallVector<BuiltType, 8> args;

const auto &genericArgs = Node->getChild(1);
if (genericArgs->getKind() != NodeKind::TypeList)
return MAKE_NODE_TYPE_ERROR0(genericArgs, "is not TypeList");

for (auto genericArg : *genericArgs) {
auto paramType = decodeMangledType(genericArg, depth + 1,
/*forRequirement=*/false);
if (paramType.isError())
return paramType;
args.push_back(paramType.getType());
}
if (auto error = decodeGenericArgs(Node->getChild(1), depth+1, args))
return *error;

auto ChildNode = Node->getChild(0);
if (ChildNode->getKind() == NodeKind::Type &&
Expand Down Expand Up @@ -665,6 +655,18 @@ class TypeDecoder {
"had a different kind when re-checked");
}
}
case NodeKind::SymbolicExtendedExistentialType: {
if (Node->getNumChildren() < 2)
return MAKE_NODE_TYPE_ERROR0(Node, "not enough children");

auto shapeNode = Node->getChild(0);
llvm::SmallVector<BuiltType, 8> args;
if (auto error = decodeGenericArgs(Node->getChild(1), depth + 1, args))
return *error;

return Builder.createSymbolicExtendedExistentialType(shapeNode, args);
}

case NodeKind::ProtocolList:
case NodeKind::ProtocolListWithAnyObject:
case NodeKind::ProtocolListWithClass: {
Expand Down Expand Up @@ -1380,6 +1382,22 @@ return {}; // Not Implemented!
return false;
}

llvm::Optional<TypeLookupError>
decodeGenericArgs(Demangle::NodePointer node, unsigned depth,
llvm::SmallVectorImpl<BuiltType> &args) {
if (node->getKind() != NodeKind::TypeList)
return MAKE_NODE_TYPE_ERROR0(node, "is not TypeList");

for (auto genericArg : *node) {
auto paramType = decodeMangledType(genericArg, depth,
/*forRequirement=*/false);
if (paramType.isError())
return *paramType.getError();
args.push_back(paramType.getType());
}
return llvm::None;
}

llvm::Optional<TypeLookupError>
decodeMangledTypeDecl(Demangle::NodePointer node, unsigned depth,
BuiltTypeDecl &typeDecl, BuiltType &parent,
Expand Down
7 changes: 7 additions & 0 deletions include/swift/Reflection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,13 @@ class TypeRefBuilder {
return ConstrainedExistentialTypeRef::create(*this, baseProto, constraints);
}

const TypeRef *
createSymbolicExtendedExistentialType(NodePointer shapeNode,
llvm::ArrayRef<const TypeRef *> args) {
// Can't handle this here.
return nullptr;
}

const ExistentialMetatypeTypeRef *createExistentialMetatypeType(
const TypeRef *instance,
llvm::Optional<Demangle::ImplMetatypeRepresentation> repr = None) {
Expand Down
39 changes: 35 additions & 4 deletions include/swift/Remote/MetadataReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,20 @@ class MetadataReader {
// execute code in the target process to resolve it from here.
return nullptr;
}
case Demangle::SymbolicReferenceKind::UniqueExtendedExistentialTypeShape: {
// The symbolic reference points at a unique extended
// existential type shape.
return dem.createNode(
Node::Kind::UniqueExtendedExistentialTypeShapeSymbolicReference,
resolved.getResolvedAddress().getAddressData());
}
case Demangle::SymbolicReferenceKind::NonUniqueExtendedExistentialTypeShape: {
// The symbolic reference points at a non-unique extended
// existential type shape.
return dem.createNode(
Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference,
resolved.getResolvedAddress().getAddressData());
}
}

return nullptr;
Expand Down Expand Up @@ -1974,8 +1988,25 @@ class MetadataReader {
}
case MetadataKind::ExistentialMetatype:
return _readMetadata<TargetExistentialMetatypeMetadata>(address);
case MetadataKind::ExtendedExistential:
return _readMetadata<TargetExtendedExistentialTypeMetadata>(address);
case MetadataKind::ExtendedExistential: {
// We need to read the shape in order to figure out how large
// the generalization arguments are.
StoredPointer shapeAddress = address + sizeof(StoredPointer);
StoredSignedPointer signedShapePtr;
if (!Reader->readInteger(RemoteAddress(shapeAddress), &signedShapePtr))
return nullptr;
auto shapePtr = stripSignedPointer(signedShapePtr);

auto shape = readShape(shapePtr);
if (!shape)
return nullptr;

auto totalSize =
sizeof(TargetExtendedExistentialTypeMetadata<Runtime>)
+ shape->getGeneralizationSignature().getArgumentLayoutSizeInWords()
* sizeof(StoredPointer);
return _readMetadata(address, totalSize);
}
case MetadataKind::ForeignClass:
return _readMetadata<TargetForeignClassMetadata>(address);
case MetadataKind::Function: {
Expand All @@ -1996,12 +2027,12 @@ class MetadataReader {
totalSize += flags.getNumParameters() * sizeof(uint32_t);

if (flags.isDifferentiable())
totalSize = roundUpToAlignment(totalSize, sizeof(void *)) +
totalSize = roundUpToAlignment(totalSize, sizeof(StoredPointer)) +
sizeof(TargetFunctionMetadataDifferentiabilityKind<
typename Runtime::StoredSize>);

return _readMetadata(address,
roundUpToAlignment(totalSize, sizeof(void *)));
roundUpToAlignment(totalSize, sizeof(StoredPointer)));
}
case MetadataKind::HeapGenericLocalVariable:
return _readMetadata<TargetGenericBoxHeapMetadata>(address);
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,11 @@ Type ASTBuilder::createConstrainedExistentialType(
return ExistentialType::get(constrainedBase);
}

Type ASTBuilder::createSymbolicExtendedExistentialType(NodePointer shapeNode,
ArrayRef<Type> genArgs) {
return Type();
}

Type ASTBuilder::createMetatypeType(Type instance,
Optional<Demangle::ImplMetatypeRepresentation> repr) {
if (!repr)
Expand Down
50 changes: 49 additions & 1 deletion lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,18 @@ void ASTMangler::appendType(Type type, GenericSignature sig,

case TypeKind::ExistentialMetatype: {
ExistentialMetatypeType *EMT = cast<ExistentialMetatypeType>(tybase);

// ExtendedExistentialTypeShapes consider existential metatypes to
// be part of the existential, so if we're symbolically referencing
// shapes, we need to handle that at this level.
if (EMT->hasParameterizedExistential()) {
auto referent = SymbolicReferent::forExtendedExistentialTypeShape(EMT);
if (canSymbolicReference(referent)) {
appendSymbolicExtendedExistentialType(referent, EMT, sig, forDecl);
return;
}
}

if (EMT->getInstanceType()->isExistentialType() &&
EMT->hasParameterizedExistential())
appendConstrainedExistential(EMT->getInstanceType(), sig, forDecl);
Expand Down Expand Up @@ -1293,7 +1305,13 @@ void ASTMangler::appendType(Type type, GenericSignature sig,

case TypeKind::Existential: {
auto *ET = cast<ExistentialType>(tybase);
if (tybase->hasParameterizedExistential()) {
if (ET->hasParameterizedExistential()) {
auto referent = SymbolicReferent::forExtendedExistentialTypeShape(ET);
if (canSymbolicReference(referent)) {
appendSymbolicExtendedExistentialType(referent, ET, sig, forDecl);
return;
}

return appendConstrainedExistential(ET->getConstraintType(), sig,
forDecl);
}
Expand Down Expand Up @@ -1751,6 +1769,36 @@ void ASTMangler::appendRetroactiveConformances(Type type, GenericSignature sig)
appendRetroactiveConformances(subMap, sig, module);
}

void ASTMangler::appendSymbolicExtendedExistentialType(
SymbolicReferent shapeReferent,
Type type,
GenericSignature sig,
const ValueDecl *forDecl) {
assert(shapeReferent.getKind() ==
SymbolicReferent::ExtendedExistentialTypeShape);
assert(canSymbolicReference(shapeReferent));
assert(type->isAnyExistentialType());

// type ::= symbolic-extended-existential-type-shape
// type* retroactive-conformance* 'Xj'

appendSymbolicReference(shapeReferent);

auto genInfo = ExistentialTypeGeneralization::get(type);
if (genInfo.Generalization) {
for (auto argType : genInfo.Generalization.getReplacementTypes())
appendType(argType, sig, forDecl);

// What module should be used here? The existential isn't anchored
// to any given module; we should just treat conformances as
// retroactive if they're "objectively" retroactive.
appendRetroactiveConformances(genInfo.Generalization, sig,
/*from module*/ nullptr);
}

appendOperator("Xj");
}

static char getParamConvention(ParameterConvention conv) {
// @in and @out are mangled the same because they're put in
// different places.
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ExistentialGeneralization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ class Generalizer : public CanTypeVisitor<Generalizer, Type> {

ExistentialTypeGeneralization
ExistentialTypeGeneralization::get(Type rawType) {
assert(rawType->isExistentialType());
assert(rawType->isAnyExistentialType());
assert(!rawType->hasTypeParameter());

// Canonicalize. We need to generalize the canonical shape of the
Expand Down
Loading