Skip to content

Commit 6b70b37

Browse files
authored
Merge pull request #38713 from slavapestov/lazy-assoc-type-list-deserialization
More efficient getAssociatedTypeMembers() on serialized ProtocolDecls
2 parents d5e5253 + 4e1c2b2 commit 6b70b37

File tree

11 files changed

+176
-18
lines changed

11 files changed

+176
-18
lines changed

include/swift/AST/Decl.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ class alignas(1 << DeclAlignInBits) Decl {
511511
IsComputingSemanticMembers : 1
512512
);
513513

514-
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+8+16,
514+
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+1+1+8+16,
515515
/// Whether the \c RequiresClass bit is valid.
516516
RequiresClassValid : 1,
517517

@@ -540,6 +540,12 @@ class alignas(1 << DeclAlignInBits) Decl {
540540
/// Whether we have a lazy-loaded requirement signature.
541541
HasLazyRequirementSignature : 1,
542542

543+
/// Whether we have computed the list of associated types.
544+
HasAssociatedTypes : 1,
545+
546+
/// Whether we have a lazy-loaded list of associated types.
547+
HasLazyAssociatedTypes : 1,
548+
543549
: NumPadBits,
544550

545551
/// If this is a compiler-known protocol, this will be a KnownProtocolKind
@@ -4094,6 +4100,7 @@ class ProtocolDecl final : public NominalTypeDecl {
40944100
SourceLoc ProtocolLoc;
40954101

40964102
ArrayRef<ProtocolDecl *> InheritedProtocols;
4103+
ArrayRef<AssociatedTypeDecl *> AssociatedTypes;
40974104

40984105
struct {
40994106
/// The superclass decl and a bit to indicate whether the
@@ -4192,7 +4199,7 @@ class ProtocolDecl final : public NominalTypeDecl {
41924199
/// Retrieve the set of AssociatedTypeDecl members of this protocol; this
41934200
/// saves loading the set of members in cases where there's no possibility of
41944201
/// a protocol having nested types (ObjC protocols).
4195-
llvm::TinyPtrVector<AssociatedTypeDecl *> getAssociatedTypeMembers() const;
4202+
ArrayRef<AssociatedTypeDecl *> getAssociatedTypeMembers() const;
41964203

41974204
/// Returns a protocol requirement with the given name, or nullptr if the
41984205
/// name has multiple overloads, or no overloads at all.
@@ -4376,6 +4383,9 @@ class ProtocolDecl final : public NominalTypeDecl {
43764383
void setLazyRequirementSignature(LazyMemberLoader *lazyLoader,
43774384
uint64_t requirementSignatureData);
43784385

4386+
void setLazyAssociatedTypeMembers(LazyMemberLoader *lazyLoader,
4387+
uint64_t associatedTypesData);
4388+
43794389
private:
43804390
ArrayRef<Requirement> getCachedRequirementSignature() const;
43814391

include/swift/AST/LazyResolver.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ class LazyIterableDeclContextData : public LazyContextData {
6060
/// Context data for protocols.
6161
class LazyProtocolData : public LazyIterableDeclContextData {
6262
public:
63-
/// The context data used for loading all of the members of the iterable
64-
/// context.
63+
/// The context data used for loading a requirement signature.
6564
uint64_t requirementSignatureData = 0;
65+
/// The context data used for loading the list of associated types.
66+
uint64_t associatedTypesData = 0;
6667
};
6768

6869
/// A class that can lazily load members from a serialized format.
@@ -100,6 +101,11 @@ class alignas(void*) LazyMemberLoader {
100101
loadRequirementSignature(const ProtocolDecl *proto, uint64_t contextData,
101102
SmallVectorImpl<Requirement> &requirements) = 0;
102103

104+
/// Loads the associated types of a protocol.
105+
virtual void
106+
loadAssociatedTypes(const ProtocolDecl *proto, uint64_t contextData,
107+
SmallVectorImpl<AssociatedTypeDecl *> &assocTypes) = 0;
108+
103109
/// Returns the replaced decl for a given @_dynamicReplacement(for:) attribute.
104110
virtual ValueDecl *
105111
loadDynamicallyReplacedFunctionDecl(const DynamicReplacementAttr *DRA,

lib/AST/Decl.cpp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4787,7 +4787,9 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
47874787
Bits.ProtocolDecl.NumRequirementsInSignature = 0;
47884788
Bits.ProtocolDecl.HasMissingRequirements = false;
47894789
Bits.ProtocolDecl.KnownProtocol = 0;
4790-
setTrailingWhereClause(TrailingWhere);
4790+
Bits.ProtocolDecl.HasAssociatedTypes = 0;
4791+
Bits.ProtocolDecl.HasLazyAssociatedTypes = 0;
4792+
setTrailingWhereClause(TrailingWhere);
47914793
}
47924794

47934795
bool ProtocolDecl::isMarkerProtocol() const {
@@ -4806,26 +4808,40 @@ ArrayRef<ProtocolDecl *> ProtocolDecl::getInheritedProtocols() const {
48064808
{});
48074809
}
48084810

4809-
llvm::TinyPtrVector<AssociatedTypeDecl *>
4811+
ArrayRef<AssociatedTypeDecl *>
48104812
ProtocolDecl::getAssociatedTypeMembers() const {
4811-
llvm::TinyPtrVector<AssociatedTypeDecl *> result;
4813+
if (Bits.ProtocolDecl.HasAssociatedTypes)
4814+
return AssociatedTypes;
4815+
4816+
auto *self = const_cast<ProtocolDecl *>(this);
4817+
self->Bits.ProtocolDecl.HasAssociatedTypes = 1;
48124818

48134819
// Clang-imported protocols never have associated types.
48144820
if (hasClangNode())
4815-
return result;
4821+
return ArrayRef<AssociatedTypeDecl *>();
48164822

48174823
// Deserialized @objc protocols never have associated types.
4818-
if (!getParentSourceFile() && isObjC())
4819-
return result;
4824+
if (getParentSourceFile() == nullptr && isObjC())
4825+
return ArrayRef<AssociatedTypeDecl *>();
48204826

4821-
// Find the associated type declarations.
4822-
for (auto member : getMembers()) {
4823-
if (auto ATD = dyn_cast<AssociatedTypeDecl>(member)) {
4824-
result.push_back(ATD);
4827+
SmallVector<AssociatedTypeDecl *, 2> result;
4828+
if (Bits.ProtocolDecl.HasLazyAssociatedTypes) {
4829+
auto &ctx = getASTContext();
4830+
auto contextData = static_cast<LazyProtocolData *>(
4831+
ctx.getOrCreateLazyContextData(this, nullptr));
4832+
4833+
contextData->loader->loadAssociatedTypes(
4834+
this, contextData->associatedTypesData, result);
4835+
} else {
4836+
for (auto member : getMembers()) {
4837+
if (auto ATD = dyn_cast<AssociatedTypeDecl>(member)) {
4838+
result.push_back(ATD);
4839+
}
48254840
}
48264841
}
48274842

4828-
return result;
4843+
self->AssociatedTypes = getASTContext().AllocateCopy(result);
4844+
return AssociatedTypes;
48294845
}
48304846

48314847
ValueDecl *ProtocolDecl::getSingleRequirement(DeclName name) const {
@@ -5190,6 +5206,18 @@ ProtocolDecl::setLazyRequirementSignature(LazyMemberLoader *lazyLoader,
51905206
++Stats->getFrontendCounters().NumLazyRequirementSignatures;
51915207
}
51925208

5209+
void
5210+
ProtocolDecl::setLazyAssociatedTypeMembers(LazyMemberLoader *lazyLoader,
5211+
uint64_t associatedTypesData) {
5212+
assert(!Bits.ProtocolDecl.HasAssociatedTypes);
5213+
assert(!Bits.ProtocolDecl.HasLazyAssociatedTypes);
5214+
5215+
auto contextData = static_cast<LazyProtocolData *>(
5216+
getASTContext().getOrCreateLazyContextData(this, lazyLoader));
5217+
contextData->associatedTypesData = associatedTypesData;
5218+
Bits.ProtocolDecl.HasLazyAssociatedTypes = true;
5219+
}
5220+
51935221
ArrayRef<Requirement> ProtocolDecl::getCachedRequirementSignature() const {
51945222
assert(RequirementSignature &&
51955223
"getting requirement signature before computing it");

lib/AST/RequirementMachine/ProtocolGraph.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ struct ProtocolInfo {
3535
llvm::TinyPtrVector<const ProtocolDecl *> AllInherited;
3636

3737
/// Associated types defined in the protocol itself.
38-
llvm::TinyPtrVector<AssociatedTypeDecl *> AssociatedTypes;
38+
ArrayRef<AssociatedTypeDecl *> AssociatedTypes;
3939

4040
/// Associated types from all inherited protocols, not including duplicates or
4141
/// those defined in the protocol itself. Computed by
@@ -64,7 +64,7 @@ struct ProtocolInfo {
6464
}
6565

6666
ProtocolInfo(ArrayRef<ProtocolDecl *> inherited,
67-
llvm::TinyPtrVector<AssociatedTypeDecl *> &&types,
67+
ArrayRef<AssociatedTypeDecl *> &&types,
6868
ArrayRef<Requirement> reqs)
6969
: Inherited(inherited),
7070
AssociatedTypes(types),

lib/ClangImporter/ImporterImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,6 +1423,11 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
14231423
llvm_unreachable("unimplemented for ClangImporter");
14241424
}
14251425

1426+
void loadAssociatedTypes(const ProtocolDecl *decl, uint64_t contextData,
1427+
SmallVectorImpl<AssociatedTypeDecl *> &assocTypes) override {
1428+
llvm_unreachable("unimplemented for ClangImporter");
1429+
}
1430+
14261431
template <typename DeclTy, typename ...Targs>
14271432
DeclTy *createDeclWithClangNode(ClangNode ClangN, AccessLevel access,
14281433
Targs &&... Args) {

lib/Serialization/DeclTypeRecordNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ DECL(OPAQUE_TYPE)
123123
DECL(PATTERN_BINDING)
124124
DECL(PROTOCOL)
125125
TRAILING_INFO(DEFAULT_WITNESS_TABLE)
126+
TRAILING_INFO(ASSOCIATED_TYPE)
126127
DECL(PREFIX_OPERATOR)
127128
DECL(POSTFIX_OPERATOR)
128129
DECL(INFIX_OPERATOR)

lib/Serialization/Deserialization.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,36 @@ llvm::Error ModuleFile::readGenericRequirementsChecked(
886886
return llvm::Error::success();
887887
}
888888

889+
void ModuleFile::readAssociatedTypes(
890+
SmallVectorImpl<AssociatedTypeDecl *> &assocTypes,
891+
llvm::BitstreamCursor &Cursor) {
892+
using namespace decls_block;
893+
894+
BCOffsetRAII lastRecordOffset(Cursor);
895+
SmallVector<uint64_t, 8> scratch;
896+
StringRef blobData;
897+
898+
while (true) {
899+
lastRecordOffset.reset();
900+
901+
llvm::BitstreamEntry entry =
902+
fatalIfUnexpected(Cursor.advance(AF_DontPopBlockAtEnd));
903+
if (entry.Kind != llvm::BitstreamEntry::Record)
904+
break;
905+
906+
scratch.clear();
907+
unsigned recordID = fatalIfUnexpected(
908+
Cursor.readRecord(entry.ID, scratch, &blobData));
909+
if (recordID != ASSOCIATED_TYPE)
910+
break;
911+
912+
DeclID declID;
913+
AssociatedTypeLayout::readRecord(scratch, declID);
914+
915+
assocTypes.push_back(cast<AssociatedTypeDecl>(getDecl(declID)));
916+
}
917+
}
918+
889919
/// Advances past any records that might be part of a requirement signature.
890920
static llvm::Error skipGenericRequirements(llvm::BitstreamCursor &Cursor) {
891921
using namespace decls_block;
@@ -919,6 +949,38 @@ static llvm::Error skipGenericRequirements(llvm::BitstreamCursor &Cursor) {
919949
return llvm::Error::success();
920950
}
921951

952+
/// Advances past any lazy associated type member records.
953+
static llvm::Error skipAssociatedTypeMembers(llvm::BitstreamCursor &Cursor) {
954+
using namespace decls_block;
955+
956+
BCOffsetRAII lastRecordOffset(Cursor);
957+
958+
while (true) {
959+
Expected<llvm::BitstreamEntry> maybeEntry =
960+
Cursor.advance(AF_DontPopBlockAtEnd);
961+
if (!maybeEntry)
962+
return maybeEntry.takeError();
963+
llvm::BitstreamEntry entry = maybeEntry.get();
964+
if (entry.Kind != llvm::BitstreamEntry::Record)
965+
break;
966+
967+
Expected<unsigned> maybeRecordID = Cursor.skipRecord(entry.ID);
968+
if (!maybeRecordID)
969+
return maybeRecordID.takeError();
970+
switch (maybeRecordID.get()) {
971+
case ASSOCIATED_TYPE:
972+
break;
973+
974+
default:
975+
// This record is not an associated type.
976+
return llvm::Error::success();
977+
}
978+
979+
lastRecordOffset.reset();
980+
}
981+
return llvm::Error::success();
982+
}
983+
922984
GenericSignature ModuleFile::getGenericSignature(
923985
serialization::GenericSignatureID ID) {
924986
auto signature = getGenericSignatureChecked(ID);
@@ -3552,6 +3614,11 @@ class DeclDeserializer {
35523614
if (llvm::Error Err = skipGenericRequirements(MF.DeclTypeCursor))
35533615
MF.fatal(std::move(Err));
35543616

3617+
proto->setLazyAssociatedTypeMembers(&MF,
3618+
MF.DeclTypeCursor.GetCurrentBitNo());
3619+
if (llvm::Error Err = skipAssociatedTypeMembers(MF.DeclTypeCursor))
3620+
MF.fatal(std::move(Err));
3621+
35553622
proto->setMemberLoader(&MF, MF.DeclTypeCursor.GetCurrentBitNo());
35563623

35573624
return proto;
@@ -6558,6 +6625,14 @@ void ModuleFile::loadRequirementSignature(const ProtocolDecl *decl,
65586625
readGenericRequirements(reqs, DeclTypeCursor);
65596626
}
65606627

6628+
void ModuleFile::loadAssociatedTypes(const ProtocolDecl *decl,
6629+
uint64_t contextData,
6630+
SmallVectorImpl<AssociatedTypeDecl *> &assocTypes) {
6631+
BCOffsetRAII restoreOffset(DeclTypeCursor);
6632+
fatalIfNotSuccess(DeclTypeCursor.JumpToBit(contextData));
6633+
readAssociatedTypes(assocTypes, DeclTypeCursor);
6634+
}
6635+
65616636
static Optional<ForeignErrorConvention::Kind>
65626637
decodeRawStableForeignErrorConventionKind(uint8_t kind) {
65636638
switch (kind) {

lib/Serialization/ModuleFile.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ class ModuleFile
389389
readGenericRequirementsChecked(SmallVectorImpl<Requirement> &requirements,
390390
llvm::BitstreamCursor &Cursor);
391391

392+
/// Read a list of associated type declarations in a protocol.
393+
void readAssociatedTypes(SmallVectorImpl<AssociatedTypeDecl *> &assocTypes,
394+
llvm::BitstreamCursor &Cursor);
395+
392396
/// Populates the protocol's default witness table.
393397
///
394398
/// Returns true if there is an error.
@@ -709,6 +713,10 @@ class ModuleFile
709713
loadRequirementSignature(const ProtocolDecl *proto, uint64_t contextData,
710714
SmallVectorImpl<Requirement> &requirements) override;
711715

716+
void
717+
loadAssociatedTypes(const ProtocolDecl *proto, uint64_t contextData,
718+
SmallVectorImpl<AssociatedTypeDecl *> &assocTypes) override;
719+
712720
Optional<StringRef> getGroupNameById(unsigned Id) const;
713721
Optional<StringRef> getSourceFileNameById(unsigned Id) const;
714722
Optional<StringRef> getGroupNameForDecl(const Decl *D) const;

lib/Serialization/ModuleFormat.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 620; // use @available(renamed:) for async alternative warning
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 621; // protocol associated type list
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///
@@ -1612,6 +1612,11 @@ namespace decls_block {
16121612
BCVBR<8> // alignment
16131613
>;
16141614

1615+
using AssociatedTypeLayout = BCRecordLayout<
1616+
ASSOCIATED_TYPE,
1617+
DeclIDField // associated type decl
1618+
>;
1619+
16151620
/// Specifies the private discriminator string for a private declaration. This
16161621
/// identifies the declaration's original source file in some opaque way.
16171622
using PrivateDiscriminatorLayout = BCRecordLayout<

lib/Serialization/Serialization.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,19 @@ void Serializer::writeGenericRequirements(ArrayRef<Requirement> requirements,
13461346
}
13471347
}
13481348

1349+
void Serializer::writeAssociatedTypes(ArrayRef<AssociatedTypeDecl *> assocTypes,
1350+
const std::array<unsigned, 256> &abbrCodes) {
1351+
using namespace decls_block;
1352+
1353+
auto assocTypeAbbrCode = abbrCodes[AssociatedTypeLayout::Code];
1354+
1355+
for (auto *assocType : assocTypes) {
1356+
AssociatedTypeLayout::emitRecord(
1357+
Out, ScratchRecord, assocTypeAbbrCode,
1358+
addDeclRef(assocType));
1359+
}
1360+
}
1361+
13491362
void Serializer::writeASTBlockEntity(GenericSignature sig) {
13501363
using namespace decls_block;
13511364

@@ -3536,6 +3549,8 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
35363549
writeGenericParams(proto->getGenericParams());
35373550
S.writeGenericRequirements(
35383551
proto->getRequirementSignature(), S.DeclTypeAbbrCodes);
3552+
S.writeAssociatedTypes(
3553+
proto->getAssociatedTypeMembers(), S.DeclTypeAbbrCodes);
35393554
writeMembers(id, proto->getAllMembers(), true);
35403555
writeDefaultWitnessTable(proto);
35413556
}
@@ -4761,6 +4776,7 @@ void Serializer::writeAllDeclsAndTypes() {
47614776
registerDeclTypeAbbr<OpaqueTypeLayout>();
47624777
registerDeclTypeAbbr<PatternBindingLayout>();
47634778
registerDeclTypeAbbr<ProtocolLayout>();
4779+
registerDeclTypeAbbr<AssociatedTypeLayout>();
47644780
registerDeclTypeAbbr<DefaultWitnessTableLayout>();
47654781
registerDeclTypeAbbr<PrefixOperatorLayout>();
47664782
registerDeclTypeAbbr<PostfixOperatorLayout>();

0 commit comments

Comments
 (0)