Skip to content

Commit 5758cdc

Browse files
committed
[ABI] Eliminate the special structure for generic parameter references.
TargetGenericParamRef is a specialized structure used to describe the subject of a generic requirement, e.g., the “T.Assoc” in “T.Assoc: P”. Replace it with a mangled name, for several reasons: 1) Mangled type names are also fairly concise, can often be shared, and are a well-tested path 2) Mangled type names can express any type, which might be useful in the future 3) This structure doesn’t accommodate specifically stating where the conformances come from (to extract associated type witnesses). Neither can mangled names, but we’d like to do that work in only one place. This change exposed an existing bug where we improperly calculated the generic parameter counts for extensions of nested generic types. Fix that bug here (which broke an execution test).
1 parent 4d041a3 commit 5758cdc

File tree

12 files changed

+97
-306
lines changed

12 files changed

+97
-306
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ Globals
113113
global ::= context 'MXE' // extension descriptor
114114
global ::= context 'MXX' // anonymous context descriptor
115115
global ::= context identifier 'MXY' // anonymous context descriptor
116-
global ::= type assoc-type-list 'MXA' // generic parameter ref
116+
global ::= type assoc-type-list 'MXA' // generic parameter ref (HISTORICAL)
117117
global ::= protocol 'Mp' // protocol descriptor
118118

119119
global ::= nominal-type 'Mo' // class metadata immediate member base offset

include/swift/ABI/Metadata.h

Lines changed: 7 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -2502,137 +2502,13 @@ struct TargetGenericContextDescriptorHeader {
25022502
using GenericContextDescriptorHeader =
25032503
TargetGenericContextDescriptorHeader<InProcess>;
25042504

2505-
/// A reference to a generic parameter that is the subject of a requirement.
2506-
/// This can refer either directly to a generic parameter or to a path to an
2507-
/// associated type.
2508-
template<typename Runtime>
2509-
class TargetGenericParamRef {
2510-
union {
2511-
/// The word of storage, whose low bit indicates whether there is an
2512-
/// associated type path stored out-of-line and whose upper bits describe
2513-
/// the generic parameter at root of the path.
2514-
uint32_t Word;
2515-
2516-
/// This is the associated type path stored out-of-line. The \c bool
2517-
/// is used for masking purposes and is otherwise unused; instead, check
2518-
/// the low bit of \c Word.
2519-
RelativeDirectPointerIntPair<const void, bool> AssociatedTypePath;
2520-
};
2521-
2522-
public:
2523-
/// Index of the parameter being referenced. 0 is the first generic parameter
2524-
/// of the root of the context hierarchy, and subsequent parameters are
2525-
/// numbered breadth-first from there.
2526-
unsigned getRootParamIndex() const {
2527-
// If there is no path, retrieve the index directly.
2528-
if ((Word & 0x01) == 0) return Word >> 1;
2529-
2530-
// Otherwise, the index is at the start of the associated type path.
2531-
return *reinterpret_cast<const unsigned *>(AssociatedTypePath.getPointer());
2532-
}
2533-
2534-
/// A reference to an associated type along the reference path.
2535-
struct AssociatedTypeRef {
2536-
/// The protocol the associated type belongs to.
2537-
RelativeIndirectablePointer<TargetProtocolDescriptor<Runtime>,
2538-
/*nullable*/ false> Protocol;
2539-
/// A reference to the associated type descriptor within the protocol.
2540-
RelativeIndirectablePointer<TargetProtocolRequirement<Runtime>,
2541-
/*nullable*/ false> Requirement;
2542-
};
2543-
2544-
/// A forward iterator that walks through the associated type path, which is
2545-
/// a zero-terminated array of AssociatedTypeRefs.
2546-
class AssociatedTypeIterator {
2547-
const void *addr;
2548-
2549-
explicit AssociatedTypeIterator(const void *startAddr) : addr(startAddr) {}
2550-
2551-
bool isEnd() const {
2552-
if (addr == nullptr)
2553-
return true;
2554-
unsigned word;
2555-
memcpy(&word, addr, sizeof(unsigned));
2556-
if (word == 0)
2557-
return true;
2558-
return false;
2559-
}
2560-
2561-
template <class> friend class TargetGenericParamRef;
2562-
2563-
public:
2564-
AssociatedTypeIterator() : addr(nullptr) {}
2565-
2566-
using iterator_category = std::forward_iterator_tag;
2567-
using value_type = AssociatedTypeRef;
2568-
using difference_type = std::ptrdiff_t;
2569-
using pointer = const AssociatedTypeRef *;
2570-
using reference = const AssociatedTypeRef &;
2571-
2572-
bool operator==(AssociatedTypeIterator i) const {
2573-
// Iterators are same if they both point at the same place, or are both
2574-
// at the end (either by being initialized as an end iterator with a
2575-
// null address, or by being advanced to the null terminator of an
2576-
// associated type list).
2577-
if (addr == i.addr)
2578-
return true;
2579-
2580-
if (isEnd() && i.isEnd())
2581-
return true;
2582-
2583-
return false;
2584-
}
2585-
2586-
bool operator!=(AssociatedTypeIterator i) const {
2587-
return !(*this == i);
2588-
}
2589-
2590-
reference operator*() const {
2591-
return *reinterpret_cast<pointer>(addr);
2592-
}
2593-
pointer operator->() const {
2594-
return reinterpret_cast<pointer>(addr);
2595-
}
2596-
2597-
AssociatedTypeIterator &operator++() {
2598-
addr = reinterpret_cast<const char*>(addr) + sizeof(AssociatedTypeRef);
2599-
return *this;
2600-
}
2601-
2602-
AssociatedTypeIterator operator++(int) {
2603-
auto copy = *this;
2604-
++*this;
2605-
return copy;
2606-
}
2607-
};
2608-
2609-
/// Iterators for going through the associated type path from the root param.
2610-
AssociatedTypeIterator begin() const {
2611-
if (Word & 0x01) {
2612-
// The associated types start after the first word, which holds the
2613-
// root param index.
2614-
return AssociatedTypeIterator(
2615-
reinterpret_cast<const char*>(AssociatedTypePath.getPointer()) +
2616-
sizeof(unsigned));
2617-
} else {
2618-
// This is a direct param reference, so there are no associated types.
2619-
return end();
2620-
}
2621-
}
2622-
2623-
AssociatedTypeIterator end() const {
2624-
return AssociatedTypeIterator{};
2625-
}
2626-
};
2627-
2628-
using GenericParamRef = TargetGenericParamRef<InProcess>;
2629-
26302505
template<typename Runtime>
26312506
class TargetGenericRequirementDescriptor {
26322507
public:
26332508
GenericRequirementFlags Flags;
2634-
/// The generic parameter or associated type that's constrained.
2635-
TargetGenericParamRef<Runtime> Param;
2509+
2510+
/// The type that's constrained, described as a mangled name.
2511+
RelativeDirectPointer<const char, /*nullable*/ false> Param;
26362512

26372513
private:
26382514
union {
@@ -2668,9 +2544,10 @@ class TargetGenericRequirementDescriptor {
26682544
return getFlags().getKind();
26692545
}
26702546

2671-
/// Retrieve the generic parameter that is the subject of this requirement.
2672-
const TargetGenericParamRef<Runtime> &getParam() const {
2673-
return Param;
2547+
/// Retrieve the generic parameter that is the subject of this requirement,
2548+
/// as a mangled type name.
2549+
StringRef getParam() const {
2550+
return swift::Demangle::makeSymbolicMangledNameStringRef(Param.get());
26742551
}
26752552

26762553
/// Retrieve the protocol for a Protocol requirement.

lib/IRGen/GenDecl.cpp

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -871,61 +871,6 @@ IRGenModule::getConstantReferenceForProtocolDescriptor(ProtocolDecl *proto) {
871871
LinkEntity::forProtocolDescriptor(proto));
872872
}
873873

874-
llvm::Constant *IRGenModule::getAddrOfAssociatedTypeGenericParamRef(
875-
GenericSignature *sig,
876-
CanDependentMemberType dmt) {
877-
llvm::SmallVector<AssociatedTypeDecl *, 4> assocTypePath;
878-
879-
// Get the base ordinal.
880-
auto baseDMT = dmt;
881-
CanType base;
882-
do {
883-
base = baseDMT.getBase();
884-
assocTypePath.push_back(baseDMT->getAssocType());
885-
baseDMT = dyn_cast<DependentMemberType>(base);
886-
} while (baseDMT);
887-
auto ordinal = sig->getGenericParamOrdinal(cast<GenericTypeParamType>(base));
888-
889-
// Generate a symbol name for the descriptor. This is a private symbol, so
890-
// isn't ABI, but is useful for ODR coalescing within the same binary.
891-
IRGenMangler Mangler;
892-
auto symbolName = Mangler
893-
.mangleAssociatedTypeGenericParamRef(ordinal, dmt);
894-
895-
// Use an existing definition if we have one.
896-
if (auto existingVar = Module.getGlobalVariable(symbolName))
897-
return existingVar;
898-
899-
// Otherwise, build the reference path.
900-
ConstantInitBuilder builder(*this);
901-
auto B = builder.beginStruct();
902-
B.addInt32(ordinal);
903-
904-
for (auto *assocType : reversed(assocTypePath)) {
905-
auto proto = getConstantReferenceForProtocolDescriptor(
906-
assocType->getProtocol());
907-
B.addRelativeAddress(proto);
908-
909-
// Add a reference to the associated type descriptor.
910-
auto assocTypeDescriptor =
911-
getAddrOfLLVMVariableOrGOTEquivalent(
912-
LinkEntity::forAssociatedTypeDescriptor(assocType));
913-
B.addRelativeAddress(assocTypeDescriptor);
914-
}
915-
916-
// Null terminator.
917-
B.addInt32(0);
918-
919-
auto var = B.finishAndCreateGlobal(symbolName, Alignment(4),
920-
/*constant*/ true);
921-
ApplyIRLinkage({llvm::GlobalValue::LinkOnceODRLinkage,
922-
llvm::GlobalValue::HiddenVisibility,
923-
llvm::GlobalValue::DefaultStorageClass})
924-
.to(var);
925-
setTrueConstGlobal(var);
926-
return var;
927-
}
928-
929874
void IRGenModule::addLazyConformances(DeclContext *dc) {
930875
for (const ProtocolConformance *conf :
931876
dc->getLocalConformances(ConformanceLookupKind::All,

lib/IRGen/GenMeta.cpp

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4103,31 +4103,6 @@ void IRGenModule::emitProtocolDecl(ProtocolDecl *protocol) {
41034103
// Generic requirements.
41044104
//===----------------------------------------------------------------------===//
41054105

4106-
/// Add a generic parameter reference to the given constant struct builder.
4107-
static void addGenericParamRef(IRGenModule &IGM, ConstantStructBuilder &B,
4108-
GenericSignature *sig, CanType type) {
4109-
// type should be either a generic parameter or dependent member type
4110-
// thereof.
4111-
4112-
if (auto genericParam = dyn_cast<GenericTypeParamType>(type)) {
4113-
// We can encode the ordinal of a direct type parameter reference
4114-
// inline.
4115-
auto ordinal = sig->getGenericParamOrdinal(genericParam);
4116-
B.addInt32(ordinal << 1);
4117-
return;
4118-
}
4119-
4120-
if (auto dmt = dyn_cast<DependentMemberType>(type)) {
4121-
// We have to encode the associated type path out-of-line.
4122-
auto assocTypeRecord = IGM.getAddrOfAssociatedTypeGenericParamRef(sig, dmt);
4123-
4124-
B.addTaggedRelativeOffset(IGM.Int32Ty, assocTypeRecord, 1);
4125-
return;
4126-
}
4127-
4128-
llvm_unreachable("not a generic parameter");
4129-
}
4130-
41314106
/// Add a generic requirement to the given constant struct builder.
41324107
static void addGenericRequirement(IRGenModule &IGM, ConstantStructBuilder &B,
41334108
GenericRequirementsMetadata &metadata,
@@ -4141,7 +4116,9 @@ static void addGenericRequirement(IRGenModule &IGM, ConstantStructBuilder &B,
41414116
++metadata.NumGenericExtraArguments;
41424117

41434118
B.addInt(IGM.Int32Ty, flags.getIntValue());
4144-
addGenericParamRef(IGM, B, sig, paramType->getCanonicalType());
4119+
auto typeName =
4120+
IGM.getTypeRef(paramType->getCanonicalType(), MangledTypeRefRole::Metadata);
4121+
B.addRelativeAddress(typeName);
41454122
addReference();
41464123
}
41474124

lib/IRGen/IRGenMangler.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -282,17 +282,6 @@ class IRGenMangler : public Mangle::ASTMangler {
282282
return finalize();
283283
}
284284

285-
std::string mangleAssociatedTypeGenericParamRef(unsigned baseOrdinal,
286-
CanType member) {
287-
beginMangling();
288-
bool isFirstAssociatedTypeIdentifier = true;
289-
appendType(GenericTypeParamType::get(0, baseOrdinal,
290-
member->getASTContext()));
291-
appendAssociatedTypePath(member, isFirstAssociatedTypeIdentifier);
292-
appendOperator("MXA");
293-
return finalize();
294-
}
295-
296285
void appendAssociatedTypePath(CanType associatedType, bool &isFirst) {
297286
if (auto memberType = dyn_cast<DependentMemberType>(associatedType)) {
298287
appendAssociatedTypePath(memberType.getBase(), isFirst);

lib/IRGen/IRGenModule.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -880,8 +880,6 @@ class IRGenModule {
880880
ForDefinition_t forDefinition);
881881
llvm::Constant *getAddrOfKeyPathPattern(KeyPathPattern *pattern,
882882
SILLocation diagLoc);
883-
llvm::Constant *getAddrOfAssociatedTypeGenericParamRef(GenericSignature *sig,
884-
CanDependentMemberType dmt);
885883
ConstantReference getConstantReferenceForProtocolDescriptor(ProtocolDecl *proto);
886884

887885
ConstantIntegerLiteral getConstantIntegerLiteral(APInt value);

0 commit comments

Comments
 (0)