Skip to content

Commit 4e1c2b2

Browse files
committed
Serialization: Serialize the list of associated types in a protocol
This allows ProtocolDecl::getAssociatedTypeMembers() on a serialized ProtocolDecl to avoid deserializing the full member list.
1 parent c44b49e commit 4e1c2b2

File tree

10 files changed

+149
-7
lines changed

10 files changed

+149
-7
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4383,6 +4383,9 @@ class ProtocolDecl final : public NominalTypeDecl {
43834383
void setLazyRequirementSignature(LazyMemberLoader *lazyLoader,
43844384
uint64_t requirementSignatureData);
43854385

4386+
void setLazyAssociatedTypeMembers(LazyMemberLoader *lazyLoader,
4387+
uint64_t associatedTypesData);
4388+
43864389
private:
43874390
ArrayRef<Requirement> getCachedRequirementSignature() const;
43884391

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: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4825,11 +4825,18 @@ ProtocolDecl::getAssociatedTypeMembers() const {
48254825
return ArrayRef<AssociatedTypeDecl *>();
48264826

48274827
SmallVector<AssociatedTypeDecl *, 2> result;
4828+
if (Bits.ProtocolDecl.HasLazyAssociatedTypes) {
4829+
auto &ctx = getASTContext();
4830+
auto contextData = static_cast<LazyProtocolData *>(
4831+
ctx.getOrCreateLazyContextData(this, nullptr));
48284832

4829-
// Find the associated type declarations.
4830-
for (auto member : getMembers()) {
4831-
if (auto ATD = dyn_cast<AssociatedTypeDecl>(member)) {
4832-
result.push_back(ATD);
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+
}
48334840
}
48344841
}
48354842

@@ -5199,6 +5206,18 @@ ProtocolDecl::setLazyRequirementSignature(LazyMemberLoader *lazyLoader,
51995206
++Stats->getFrontendCounters().NumLazyRequirementSignatures;
52005207
}
52015208

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+
52025221
ArrayRef<Requirement> ProtocolDecl::getCachedRequirementSignature() const {
52035222
assert(RequirementSignature &&
52045223
"getting requirement signature before computing it");

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>();

lib/Serialization/Serialization.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,10 @@ class Serializer : public SerializerBase {
539539
void writeGenericRequirements(ArrayRef<Requirement> requirements,
540540
const std::array<unsigned, 256> &abbrCodes);
541541

542+
/// Writes a protocol's associated type table.
543+
void writeAssociatedTypes(ArrayRef<AssociatedTypeDecl *> assocTypes,
544+
const std::array<unsigned, 256> &abbrCodes);
545+
542546
bool allowCompilerErrors() const;
543547
};
544548

0 commit comments

Comments
 (0)