Skip to content

Commit d52dad3

Browse files
authored
[IRGen] Extract getConformance from ProtocolInfo (#18681)
We were using this just as a convenient way to share an existing DenseMap, but it's not really related; we don't need to compute witness table layout just to generate a conformance reference. I started working on this because the "Cub" source compat project was hitting issues here, but now I can't reproduce it. Still, this is a reasonable cleanup.
1 parent 67c9358 commit d52dad3

File tree

4 files changed

+44
-51
lines changed

4 files changed

+44
-51
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -980,19 +980,6 @@ bool irgen::isDependentConformance(const NormalProtocolConformance *conformance)
980980
conformance, [](unsigned, CanType, ProtocolDecl *) { return true; });
981981
}
982982

983-
/// Detail about how an object conforms to a protocol.
984-
class irgen::ConformanceInfo {
985-
friend ProtocolInfo;
986-
public:
987-
virtual ~ConformanceInfo() {}
988-
virtual llvm::Value *getTable(IRGenFunction &IGF,
989-
llvm::Value **conformingMetadataCache) const = 0;
990-
/// Try to get this table as a constant pointer. This might just
991-
/// not be supportable at all.
992-
virtual llvm::Constant *tryGetConstantTable(IRGenModule &IGM,
993-
CanType conformingType) const = 0;
994-
};
995-
996983
static llvm::Value *
997984
emitConditionalConformancesBuffer(IRGenFunction &IGF,
998985
const ProtocolConformance *conformance) {
@@ -1268,13 +1255,10 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF,
12681255

12691256
// TODO: Use the witness entry instead of falling through here.
12701257

1271-
// Look for a protocol type info.
1272-
const ProtocolInfo &basePI = IGM.getProtocolInfo(baseProto);
1258+
// Look for conformance info.
12731259
auto *astConf = ConformanceInContext.getInheritedConformance(baseProto);
12741260
assert(astConf->getType()->isEqual(ConcreteType));
1275-
1276-
const ConformanceInfo &conf =
1277-
basePI.getConformance(IGM, baseProto, astConf);
1261+
const ConformanceInfo &conf = IGM.getConformanceInfo(baseProto, astConf);
12781262

12791263
// If we can emit the base witness table as a constant, do so.
12801264
llvm::Constant *baseWitness = conf.tryGetConstantTable(IGM, ConcreteType);
@@ -1649,10 +1633,8 @@ getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement,
16491633
if (associatedConformance.isConcrete()) {
16501634
assert(associatedType->isEqual(associatedConformance.getConcrete()->getType()));
16511635

1652-
const ProtocolInfo &protocolI = IGM.getProtocolInfo(associatedProtocol);
1653-
conformanceI =
1654-
&protocolI.getConformance(IGM, associatedProtocol,
1655-
associatedConformance.getConcrete());
1636+
conformanceI = &IGM.getConformanceInfo(associatedProtocol,
1637+
associatedConformance.getConcrete());
16561638

16571639
// If we can emit a constant table, do so.
16581640
// In principle, any time we can do this, we should try to re-use this
@@ -2131,53 +2113,54 @@ ProtocolInfo *ProtocolInfo::create(ArrayRef<WitnessTableEntry> table) {
21312113
return new(buffer) ProtocolInfo(table);
21322114
}
21332115

2134-
ProtocolInfo::~ProtocolInfo() {
2135-
for (auto &conf : Conformances) {
2136-
delete conf.second;
2137-
}
2138-
}
2116+
// Provide a unique home for the ConformanceInfo vtable.
2117+
void ConformanceInfo::anchor() {}
21392118

21402119
/// Find the conformance information for a protocol.
21412120
const ConformanceInfo &
2142-
ProtocolInfo::getConformance(IRGenModule &IGM, ProtocolDecl *protocol,
2143-
const ProtocolConformance *conformance) const {
2121+
IRGenModule::getConformanceInfo(const ProtocolDecl *protocol,
2122+
const ProtocolConformance *conformance) {
21442123
assert(conformance->getProtocol() == protocol &&
21452124
"conformance is for wrong protocol");
21462125

21472126
auto checkCache =
2148-
[&](const ProtocolConformance *conf) -> Optional<ConformanceInfo *> {
2127+
[this](const ProtocolConformance *conf) -> const ConformanceInfo * {
21492128
// Check whether we've already cached this.
21502129
auto it = Conformances.find(conf);
21512130
if (it != Conformances.end())
2152-
return it->second;
2131+
return it->second.get();
21532132

2154-
return None;
2133+
return nullptr;
21552134
};
21562135

21572136
if (auto found = checkCache(conformance))
2158-
return **found;
2137+
return *found;
21592138

21602139
// Drill down to the root normal
21612140
auto normalConformance = conformance->getRootNormalConformance();
21622141

2163-
ConformanceInfo *info;
2142+
const ConformanceInfo *info;
21642143
// If the conformance is dependent in any way, we need to unique it.
21652144
// TODO: maybe this should apply whenever it's out of the module?
21662145
// TODO: actually enable this
2146+
// FIXME: Both implementations of ConformanceInfo are trivially-destructible,
2147+
// so in theory we could allocate them on a BumpPtrAllocator. But there's not
2148+
// a good one for us to use. (The ASTContext's outlives the IRGenModule in
2149+
// batch mode.)
21672150
if (isDependentConformance(normalConformance) ||
21682151
// Foreign types need to go through the accessor to unique the witness
21692152
// table.
21702153
normalConformance->isSynthesizedNonUnique()) {
21712154
info = new AccessorConformanceInfo(conformance);
2172-
Conformances.insert({conformance, info});
2155+
Conformances.try_emplace(conformance, info);
21732156
} else {
21742157
// Otherwise, we can use a direct-referencing conformance, which can get
21752158
// away with the non-specialized conformance.
21762159
if (auto found = checkCache(normalConformance))
2177-
return **found;
2160+
return *found;
21782161

21792162
info = new DirectConformanceInfo(normalConformance);
2180-
Conformances.insert({normalConformance, info});
2163+
Conformances.try_emplace(normalConformance, info);
21812164
}
21822165

21832166
return *info;
@@ -2835,9 +2818,7 @@ llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF,
28352818
LocalTypeDataKind::forConcreteProtocolWitnessTable(concreteConformance));
28362819
if (wtable) return wtable;
28372820

2838-
auto &protoI = IGF.IGM.getProtocolInfo(proto);
2839-
auto &conformanceI =
2840-
protoI.getConformance(IGF.IGM, proto, concreteConformance);
2821+
auto &conformanceI = IGF.IGM.getConformanceInfo(proto, concreteConformance);
28412822
wtable = conformanceI.getTable(IGF, srcMetadataCache);
28422823

28432824
IGF.setScopedLocalTypeData(

lib/IRGen/IRGenModule.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "GenType.h"
5252
#include "IRGenModule.h"
5353
#include "IRGenDebugInfo.h"
54+
#include "ProtocolInfo.h"
5455
#include "StructLayout.h"
5556

5657
#include <initializer_list>

lib/IRGen/IRGenModule.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ namespace irgen {
109109
class Address;
110110
class ClangTypeConverter;
111111
class ClassMetadataLayout;
112+
class ConformanceInfo;
112113
class DebugTypeInfo;
113114
class EnumImplStrategy;
114115
class EnumMetadataLayout;
@@ -703,6 +704,12 @@ class IRGenModule {
703704
//--- Types -----------------------------------------------------------------
704705
public:
705706
const ProtocolInfo &getProtocolInfo(ProtocolDecl *D);
707+
708+
// Not strictly a type operation, but similar.
709+
const ConformanceInfo &
710+
getConformanceInfo(const ProtocolDecl *protocol,
711+
const ProtocolConformance *conformance);
712+
706713
SILType getLoweredType(AbstractionPattern orig, Type subst);
707714
SILType getLoweredType(Type subst);
708715
const TypeInfo &getTypeInfoForUnlowered(AbstractionPattern orig,
@@ -774,6 +781,9 @@ class IRGenModule {
774781
llvm::DenseMap<Decl*, MetadataLayout*> MetadataLayouts;
775782
void destroyMetadataLayoutMap();
776783

784+
llvm::DenseMap<const ProtocolConformance *,
785+
std::unique_ptr<const ConformanceInfo>> Conformances;
786+
777787
friend class GenericContextScope;
778788
friend class CompletelyFragileScope;
779789

lib/IRGen/ProtocolInfo.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ namespace swift {
3232
class ProtocolConformance;
3333

3434
namespace irgen {
35-
class ConformanceInfo; // private to GenProto.cpp
3635
class IRGenModule;
3736
class TypeInfo;
3837

@@ -161,11 +160,6 @@ class ProtocolInfo final :
161160
/// The number of table entries in this protocol layout.
162161
unsigned NumTableEntries;
163162

164-
/// A table of all the conformances we've needed so far for this
165-
/// protocol. We expect this to be quite small for most protocols.
166-
mutable llvm::SmallDenseMap<const ProtocolConformance*, ConformanceInfo*, 2>
167-
Conformances;
168-
169163
ProtocolInfo(ArrayRef<WitnessTableEntry> table)
170164
: NumTableEntries(table.size()) {
171165
std::uninitialized_copy(table.begin(), table.end(),
@@ -175,10 +169,6 @@ class ProtocolInfo final :
175169
static ProtocolInfo *create(ArrayRef<WitnessTableEntry> table);
176170

177171
public:
178-
const ConformanceInfo &getConformance(IRGenModule &IGM,
179-
ProtocolDecl *protocol,
180-
const ProtocolConformance *conf) const;
181-
182172
/// The number of witness slots in a conformance to this protocol;
183173
/// in other words, the size of the table in words.
184174
unsigned getNumWitnesses() const {
@@ -256,8 +246,19 @@ class ProtocolInfo final :
256246
}
257247
llvm_unreachable("didn't find entry for associated conformance");
258248
}
249+
};
259250

260-
~ProtocolInfo();
251+
/// Detail about how an object conforms to a protocol.
252+
class ConformanceInfo {
253+
virtual void anchor();
254+
public:
255+
virtual ~ConformanceInfo() = default;
256+
virtual llvm::Value *getTable(IRGenFunction &IGF,
257+
llvm::Value **conformingMetadataCache) const = 0;
258+
/// Try to get this table as a constant pointer. This might just
259+
/// not be supportable at all.
260+
virtual llvm::Constant *tryGetConstantTable(IRGenModule &IGM,
261+
CanType conformingType) const = 0;
261262
};
262263

263264
} // end namespace irgen

0 commit comments

Comments
 (0)