Skip to content

Commit 9f79fd5

Browse files
committed
Serialize Fingerprints in Swift Modules
1 parent beeefbc commit 9f79fd5

12 files changed

+189
-7
lines changed

include/swift/AST/LazyResolver.h

+5
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ class alignas(void*) LazyMemberLoader {
8484
loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N,
8585
uint64_t contextData) = 0;
8686

87+
/// Returns the fingerprint associated with the given iterable decl context,
88+
/// or \c None if no such fingerprint is available.
89+
virtual Optional<std::string>
90+
loadFingerprint(const IterableDeclContext *IDC) = 0;
91+
8792
/// Populates the given vector with all conformances for \p D.
8893
///
8994
/// The implementation should \em not call setConformances on \p D.

lib/AST/DeclContext.cpp

+9-5
Original file line numberDiff line numberDiff line change
@@ -1012,12 +1012,16 @@ IterableDeclContext::castDeclToIterableDeclContext(const Decl *D) {
10121012
}
10131013

10141014
Optional<std::string> IterableDeclContext::getBodyFingerprint() const {
1015-
// Only makes sense for contexts in a source file
1016-
if (!getAsGenericContext()->getParentSourceFile())
1017-
return None;
1015+
auto &ctx = getASTContext();
1016+
// If this decl comes from a serialized module, grab its fingerprint from
1017+
// the file.
1018+
if (!getAsGenericContext()->getParentSourceFile()) {
1019+
auto ci = ctx.getOrCreateLazyIterableContextData(this,
1020+
/*lazyLoader=*/nullptr);
1021+
return ci->loader->loadFingerprint(this);
1022+
}
10181023
auto mutableThis = const_cast<IterableDeclContext *>(this);
1019-
return evaluateOrDefault(getASTContext().evaluator,
1020-
ParseMembersRequest{mutableThis},
1024+
return evaluateOrDefault(ctx.evaluator, ParseMembersRequest{mutableThis},
10211025
FingerprintAndMembers())
10221026
.fingerprint;
10231027
}

lib/ClangImporter/ClangImporter.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -3831,6 +3831,12 @@ void ClangImporter::Implementation::lookupAllObjCMembers(
38313831
}
38323832
}
38333833

3834+
Optional<std::string>
3835+
ClangImporter::Implementation::loadFingerprint(const IterableDeclContext *) {
3836+
// Clang decls are not fingerprinted in Swift.
3837+
return None;
3838+
}
3839+
38343840
TinyPtrVector<ValueDecl *>
38353841
ClangImporter::Implementation::loadNamedMembers(
38363842
const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) {

lib/ClangImporter/ImporterImpl.h

+3
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
12471247
loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N,
12481248
uint64_t contextData) override;
12491249

1250+
virtual Optional<std::string>
1251+
loadFingerprint(const IterableDeclContext *IDC) override;
1252+
12501253
private:
12511254
void
12521255
loadAllMembersOfObjcContainer(Decl *D,

lib/Serialization/ModuleFile.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,24 @@ void ModuleFile::loadDerivativeFunctionConfigurations(
650650
}
651651
}
652652

653+
Optional<std::string>
654+
ModuleFile::loadFingerprint(const IterableDeclContext *IDC) {
655+
PrettyStackTraceDecl trace("loading fingerprints for", IDC->getDecl());
656+
657+
assert(IDC->wasDeserialized());
658+
assert(IDC->getDeclID() != 0);
659+
660+
if (!Core->DeclFingerprints) {
661+
return None;
662+
}
663+
664+
auto it = Core->DeclFingerprints->find(IDC->getDeclID());
665+
if (it == Core->DeclFingerprints->end()) {
666+
return None;
667+
}
668+
return *it;
669+
}
670+
653671
TinyPtrVector<ValueDecl *>
654672
ModuleFile::loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N,
655673
uint64_t contextData) {

lib/Serialization/ModuleFile.h

+3
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ class ModuleFile
653653
loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N,
654654
uint64_t contextData) override;
655655

656+
virtual Optional<std::string>
657+
loadFingerprint(const IterableDeclContext *IDC) override;
658+
656659
virtual void
657660
loadAllConformances(const Decl *D, uint64_t contextData,
658661
SmallVectorImpl<ProtocolConformance*> &Conforms) override;

lib/Serialization/ModuleFileCoreTableInfo.h

+36
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,42 @@ class ModuleFileSharedCore::DeclUSRTableInfo {
566566
}
567567
};
568568

569+
class ModuleFileSharedCore::DeclFingerprintsTableInfo {
570+
public:
571+
using internal_key_type = uint32_t;
572+
using external_key_type = DeclID;
573+
using data_type = std::string;
574+
using hash_value_type = uint32_t;
575+
using offset_type = unsigned;
576+
577+
internal_key_type GetInternalKey(external_key_type ID) { return ID; }
578+
579+
hash_value_type ComputeHash(internal_key_type key) {
580+
return llvm::hash_value(key);
581+
}
582+
583+
static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
584+
return lhs == rhs;
585+
}
586+
587+
static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
588+
using namespace llvm::support;
589+
unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
590+
return {sizeof(uint32_t), dataLength};
591+
}
592+
593+
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
594+
using namespace llvm::support;
595+
return endian::readNext<uint32_t, little, unaligned>(data);
596+
}
597+
598+
static data_type ReadData(internal_key_type key, const uint8_t *data,
599+
unsigned length) {
600+
using namespace llvm::support;
601+
return std::string{reinterpret_cast<const char *>(data), length};
602+
}
603+
};
604+
569605
} // end namespace swift
570606

571607
#endif

lib/Serialization/ModuleFileSharedCore.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,18 @@ ModuleFileSharedCore::readDeclMembersTable(ArrayRef<uint64_t> fields,
531531
base + sizeof(uint32_t), base));
532532
}
533533

534+
std::unique_ptr<ModuleFileSharedCore::SerializedDeclFingerprintsTable>
535+
ModuleFileSharedCore::readDeclFingerprintsTable(ArrayRef<uint64_t> fields,
536+
StringRef blobData) const {
537+
uint32_t tableOffset;
538+
index_block::DeclFingerprintsLayout::readRecord(fields, tableOffset);
539+
auto base = reinterpret_cast<const uint8_t *>(blobData.data());
540+
541+
using OwnedTable = std::unique_ptr<SerializedDeclFingerprintsTable>;
542+
return OwnedTable(SerializedDeclFingerprintsTable::Create(
543+
base + tableOffset, base + sizeof(uint32_t), base));
544+
}
545+
534546
std::unique_ptr<ModuleFileSharedCore::SerializedObjCMethodTable>
535547
ModuleFileSharedCore::readObjCMethodTable(ArrayRef<uint64_t> fields,
536548
StringRef blobData) const {
@@ -685,6 +697,9 @@ bool ModuleFileSharedCore::readIndexBlock(llvm::BitstreamCursor &cursor) {
685697
case index_block::DECL_MEMBER_NAMES:
686698
DeclMemberNames = readDeclMemberNamesTable(scratch, blobData);
687699
break;
700+
case index_block::DECL_FINGERPRINTS:
701+
DeclFingerprints = readDeclFingerprintsTable(scratch, blobData);
702+
break;
688703
case index_block::LOCAL_DECL_CONTEXT_OFFSETS:
689704
assert(blobData.empty());
690705
allocateBuffer(LocalDeclContexts, scratch);

lib/Serialization/ModuleFileSharedCore.h

+11
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ class ModuleFileSharedCore {
240240
using SerializedDeclMembersTable =
241241
llvm::OnDiskIterableChainedHashTable<DeclMembersTableInfo>;
242242

243+
class DeclFingerprintsTableInfo;
244+
using SerializedDeclFingerprintsTable =
245+
llvm::OnDiskIterableChainedHashTable<DeclFingerprintsTableInfo>;
246+
243247
std::unique_ptr<SerializedDeclTable> TopLevelDecls;
244248
std::unique_ptr<SerializedDeclTable> OperatorDecls;
245249
std::unique_ptr<SerializedDeclTable> PrecedenceGroupDecls;
@@ -250,6 +254,7 @@ class ModuleFileSharedCore {
250254
std::unique_ptr<SerializedOpaqueReturnTypeDeclTable> OpaqueReturnTypeDecls;
251255
std::unique_ptr<SerializedNestedTypeDeclsTable> NestedTypeDecls;
252256
std::unique_ptr<SerializedDeclMemberNamesTable> DeclMemberNames;
257+
std::unique_ptr<SerializedDeclFingerprintsTable> DeclFingerprints;
253258

254259
class ObjCMethodTableInfo;
255260
using SerializedObjCMethodTable =
@@ -399,6 +404,12 @@ class ModuleFileSharedCore {
399404
std::unique_ptr<SerializedDeclMembersTable>
400405
readDeclMembersTable(ArrayRef<uint64_t> fields, StringRef blobData) const;
401406

407+
/// Read an on-disk local declid-string hash table stored in
408+
/// index_block::DeclFingerprintsLayout format.
409+
std::unique_ptr<SerializedDeclFingerprintsTable>
410+
readDeclFingerprintsTable(ArrayRef<uint64_t> fields,
411+
StringRef blobData) const;
412+
402413
/// Read an on-disk derivative function configuration table stored in
403414
/// index_block::DerivativeFunctionConfigTableLayout format.
404415
std::unique_ptr<ModuleFileSharedCore::SerializedDerivativeFunctionConfigTable>

lib/Serialization/ModuleFormat.h

+9-2
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 = 586; // allow errors in modules
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 587; // fingerprints in modules
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///
@@ -2010,14 +2010,15 @@ namespace index_block {
20102010
PRECEDENCE_GROUPS,
20112011
NESTED_TYPE_DECLS,
20122012
DECL_MEMBER_NAMES,
2013+
DECL_FINGERPRINTS,
20132014

20142015
ORDERED_TOP_LEVEL_DECLS,
20152016

20162017
SUBSTITUTION_MAP_OFFSETS,
20172018
CLANG_TYPE_OFFSETS,
20182019
LastRecordKind = CLANG_TYPE_OFFSETS,
20192020
};
2020-
2021+
20212022
constexpr const unsigned RecordIDFieldWidth = 5;
20222023
static_assert(LastRecordKind < (1 << RecordIDFieldWidth),
20232024
"not enough bits for all record kinds");
@@ -2078,6 +2079,12 @@ namespace index_block {
20782079
RecordIDField, // record ID
20792080
BCArray<DeclIDField> // list of decls by ID
20802081
>;
2082+
2083+
using DeclFingerprintsLayout = BCRecordLayout<
2084+
DECL_FINGERPRINTS, // record ID
2085+
BCVBR<16>, // table offset within the blob (see below)
2086+
BCBlob // map from member DeclIDs to strings
2087+
>;
20812088
}
20822089

20832090
/// \sa DECL_MEMBER_TABLES_BLOCK_ID

lib/Serialization/Serialization.cpp

+72
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,43 @@ namespace {
434434
}
435435
}
436436
};
437+
438+
class DeclFingerprintsTableInfo {
439+
public:
440+
using key_type = DeclID;
441+
using key_type_ref = const key_type &;
442+
using data_type = std::string;
443+
using data_type_ref = llvm::StringRef;
444+
using hash_value_type = uint32_t;
445+
using offset_type = unsigned;
446+
447+
hash_value_type ComputeHash(key_type_ref key) {
448+
return llvm::hash_value(static_cast<uint32_t>(key));
449+
}
450+
451+
std::pair<unsigned, unsigned>
452+
EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) {
453+
assert((data.size() == 32) && "Fingerprint must be 32-bytes long!");
454+
endian::Writer writer(out, little);
455+
// No need to write the key length; it's constant.
456+
writer.write<uint16_t>(data.size());
457+
return {sizeof(uint32_t), data.size()};
458+
}
459+
460+
void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
461+
static_assert(declIDFitsIn32Bits(), "DeclID too large");
462+
assert(len == sizeof(uint32_t));
463+
endian::Writer writer(out, little);
464+
writer.write<uint32_t>(key);
465+
}
466+
467+
void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
468+
unsigned len) {
469+
static_assert(declIDFitsIn32Bits(), "DeclID too large");
470+
endian::Writer writer(out, little);
471+
out << data;
472+
}
473+
};
437474
} // end anonymous namespace
438475

439476
static ModuleDecl *getModule(ModuleOrSourceFile DC) {
@@ -799,6 +836,7 @@ void Serializer::writeBlockInfoBlock() {
799836
BLOCK_RECORD(index_block, PRECEDENCE_GROUPS);
800837
BLOCK_RECORD(index_block, NESTED_TYPE_DECLS);
801838
BLOCK_RECORD(index_block, DECL_MEMBER_NAMES);
839+
BLOCK_RECORD(index_block, DECL_FINGERPRINTS);
802840
BLOCK_RECORD(index_block, ORDERED_TOP_LEVEL_DECLS);
803841

804842
BLOCK(DECL_MEMBER_TABLES_BLOCK);
@@ -4806,6 +4844,27 @@ writeDeclMembersTable(const decl_member_tables_block::DeclMembersLayout &mems,
48064844
mems.emit(scratch, tableOffset, hashTableBlob);
48074845
}
48084846

4847+
static void
4848+
writeDeclFingerprintsTable(const index_block::DeclFingerprintsLayout &fpl,
4849+
const Serializer::DeclFingerprintsTable &table) {
4850+
SmallVector<uint64_t, 8> scratch;
4851+
llvm::SmallString<4096> hashTableBlob;
4852+
uint32_t tableOffset;
4853+
{
4854+
llvm::OnDiskChainedHashTableGenerator<DeclFingerprintsTableInfo> generator;
4855+
for (auto &entry : table) {
4856+
generator.insert(entry.first, entry.second);
4857+
}
4858+
4859+
llvm::raw_svector_ostream blobStream(hashTableBlob);
4860+
// Make sure that no bucket is at offset 0
4861+
endian::write<uint32_t>(blobStream, 0, little);
4862+
tableOffset = generator.Emit(blobStream);
4863+
}
4864+
4865+
fpl.emit(scratch, tableOffset, hashTableBlob);
4866+
}
4867+
48094868
namespace {
48104869
/// Used to serialize the on-disk Objective-C method hash table.
48114870
class ObjCMethodTableInfo {
@@ -5078,6 +5137,7 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
50785137
LocalTypeHashTableGenerator localTypeGenerator, opaqueReturnTypeGenerator;
50795138
ExtensionTable extensionDecls;
50805139
UniquedDerivativeFunctionConfigTable uniquedDerivativeConfigs;
5140+
DeclFingerprintsTable declFingerprints;
50815141
bool hasLocalTypes = false;
50825142
bool hasOpaqueReturnTypes = false;
50835143

@@ -5137,6 +5197,9 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
51375197
// derived conformance (for example, ==), force them to be
51385198
// serialized.
51395199
if (auto IDC = dyn_cast<IterableDeclContext>(D)) {
5200+
if (auto bodyFP = IDC->getBodyFingerprint()) {
5201+
declFingerprints[addDeclRef(D)] = *bodyFP;
5202+
}
51405203
collectInterestingNestedDeclarations(*this, IDC->getMembers(),
51415204
operatorMethodDecls, objcMethods,
51425205
nestedTypeDecls,
@@ -5167,6 +5230,9 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
51675230
localTypeGenerator.insert(MangledName, addDeclRef(TD));
51685231

51695232
if (auto IDC = dyn_cast<IterableDeclContext>(TD)) {
5233+
if (auto bodyFP = IDC->getBodyFingerprint()) {
5234+
declFingerprints[addDeclRef(TD)] = *bodyFP;
5235+
}
51705236
collectInterestingNestedDeclarations(*this, IDC->getMembers(),
51715237
operatorMethodDecls, objcMethods,
51725238
nestedTypeDecls,
@@ -5233,6 +5299,12 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
52335299
writeNestedTypeDeclsTable(NestedTypeDeclsTable, nestedTypeDecls);
52345300
}
52355301

5302+
if (!declFingerprints.empty()) {
5303+
// Write decl fingerprints.
5304+
index_block::DeclFingerprintsLayout DeclsFingerprints(Out);
5305+
writeDeclFingerprintsTable(DeclsFingerprints, declFingerprints);
5306+
}
5307+
52365308
// Convert uniqued derivative function config table to serialization-
52375309
// ready format: turn `GenericSignature` to `GenericSignatureID`.
52385310
DerivativeFunctionConfigTable derivativeConfigs;

lib/Serialization/Serialization.h

+2
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ class Serializer : public SerializerBase {
277277
Identifier,
278278
llvm::SmallSetVector<std::pair<Identifier, GenericSignature>, 4>>;
279279

280+
using DeclFingerprintsTable = llvm::MapVector<uint32_t, std::string>;
281+
280282
private:
281283
/// A map from identifiers to methods and properties with the given name.
282284
///

0 commit comments

Comments
 (0)