From 073ee22a45f60e683d453d3d0a7f0eaba47a34aa Mon Sep 17 00:00:00 2001 From: Becca Royal-Gordon Date: Fri, 26 Jul 2024 14:25:30 -0700 Subject: [PATCH] Accommodate 64-bit clang serialization IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several serialization IDs that used to be 32 bits are being widened to 64. Modify SwiftLookupTable and its supporting types to accommodate this. The new design uses a 64-bit integer for the pointer, decl, macro, or identifier ID, plus a 32-bit integer for the submodule ID (this field is set to all ones to indicate a decl vs. a macro). An additional in-memory bool distinguishes pointer nodes from ID nodes. Advantages: • The main ID is now 64 bits wide, accommodating recent changes in clang. • We’re no longer stealing bits from clang (we *do* steal the max value of the submodule ID, though). • There’s no on-disk bit that, when set, will cause an ID to be interpreted as a pointer. • Design is robust against `clang::serialization::SubmoduleID` also becoming 64-bit (although this will waste space). Fixes rdar://131134424. --- lib/ClangImporter/SwiftLookupTable.cpp | 218 ++++++++++++------------- lib/ClangImporter/SwiftLookupTable.h | 204 ++++++++++++++++------- 2 files changed, 251 insertions(+), 171 deletions(-) diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index c7b564d8a6111..8f0ca1a128432 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -59,6 +59,8 @@ template } namespace { + using StoredSingleEntry = SwiftLookupTable::StoredSingleEntry; + class BaseNameToEntitiesTableReaderInfo; class GlobalsAsMembersTableReaderInfo; @@ -167,8 +169,9 @@ class SwiftLookupTableReader : public clang::ModuleFileExtensionReader { /// imported as members into the given context. /// /// \returns true if we found anything, false otherwise. - bool lookupGlobalsAsMembersInContext(SwiftLookupTable::StoredContext context, - SmallVectorImpl &entries); + bool lookupGlobalsAsMembersInContext( + SwiftLookupTable::StoredContext context, + SmallVectorImpl &entries); /// Retrieve the set of global declarations that are going to be imported as members under the given /// Swift base name. @@ -444,8 +447,9 @@ static bool isGlobalAsMember(SwiftLookupTable::SingleEntry entry, return decl->getDeclContext()->getRedeclContext()->isFileContext(); } -bool SwiftLookupTable::addLocalEntry(SingleEntry newEntry, - SmallVectorImpl &entries) { +bool SwiftLookupTable::addLocalEntry( + SingleEntry newEntry, + SmallVectorImpl &entries) { // Check whether this entry matches any existing entry. auto decl = newEntry.dyn_cast(); auto macro = newEntry.dyn_cast(); @@ -453,13 +457,13 @@ bool SwiftLookupTable::addLocalEntry(SingleEntry newEntry, for (auto &existingEntry : entries) { // If it matches an existing declaration, there's nothing to do. - if (decl && isDeclEntry(existingEntry) && + if (decl && existingEntry.isDeclEntry() && matchesExistingDecl(decl, mapStoredDecl(existingEntry))) return false; // If a textual macro matches an existing macro, just drop the new // definition. - if (macro && isMacroEntry(existingEntry)) { + if (macro && existingEntry.isMacroEntry()) { return false; } @@ -474,7 +478,7 @@ bool SwiftLookupTable::addLocalEntry(SingleEntry newEntry, // Note that the above assumes that macro definitions are processed in // reverse order, i.e. the first definition seen is the last in a // translation unit. - if (moduleMacro && isMacroEntry(existingEntry)) { + if (moduleMacro && existingEntry.isMacroEntry()) { SingleEntry decodedEntry = mapStoredMacro(existingEntry, /*assumeModule*/true); const auto *existingMacro = decodedEntry.get(); @@ -491,7 +495,7 @@ bool SwiftLookupTable::addLocalEntry(SingleEntry newEntry, // FIXME: What if there are /multiple/ old definitions we should be // dropping? What if one of the earlier early exits makes us miss // entries later in the list that would match this? - existingEntry = encodeEntry(moduleMacro); + existingEntry = StoredSingleEntry(moduleMacro); return false; } @@ -501,11 +505,11 @@ bool SwiftLookupTable::addLocalEntry(SingleEntry newEntry, // Add an entry to this context. if (decl) - entries.push_back(encodeEntry(decl)); + entries.push_back(StoredSingleEntry(decl)); else if (macro) - entries.push_back(encodeEntry(macro)); + entries.push_back(StoredSingleEntry(macro)); else - entries.push_back(encodeEntry(moduleMacro)); + entries.push_back(StoredSingleEntry(moduleMacro)); return true; } @@ -545,11 +549,11 @@ void SwiftLookupTable::addEntry(DeclName name, SingleEntry newEntry, FullTableEntry entry; entry.Context = context; if (decl) - entry.DeclsOrMacros.push_back(encodeEntry(decl)); + entry.DeclsOrMacros.push_back(StoredSingleEntry(decl)); else if (macro) - entry.DeclsOrMacros.push_back(encodeEntry(macro)); + entry.DeclsOrMacros.push_back(StoredSingleEntry(macro)); else - entry.DeclsOrMacros.push_back(encodeEntry(moduleMacro)); + entry.DeclsOrMacros.push_back(StoredSingleEntry(moduleMacro)); entries.push_back(entry); }; @@ -674,7 +678,7 @@ SwiftLookupTable::allGlobalsAsMembersInContext(StoredContext context) { if (!Reader) return result; // Lookup this base name in the module extension file. - SmallVector results; + SmallVector results; (void)Reader->lookupGlobalsAsMembersInContext(context, results); // Add an entry to the table so we don't look again. @@ -791,7 +795,7 @@ SwiftLookupTable::lookupObjCMembers(SerializedSwiftName baseName) { // Map each of the declarations. for (auto &stored : entry.DeclsOrMacros) { - assert(isDeclEntry(stored) && "Not a declaration?"); + assert(stored.isDeclEntry() && "Not a declaration?"); result.push_back(mapStoredDecl(stored)); } } @@ -820,7 +824,7 @@ SwiftLookupTable::lookupMemberOperators(SerializedSwiftName baseName) { // Map each of the declarations. for (auto &stored : entry.DeclsOrMacros) { - assert(isDeclEntry(stored) && "Not a declaration?"); + assert(stored.isDeclEntry() && "Not a declaration?"); result.push_back(mapStoredDecl(stored)); } } @@ -930,42 +934,24 @@ static void printStoredContext(SwiftLookupTable::StoredContext context, } } -static uint64_t getEncodedDeclID(uint64_t entry) { - assert(SwiftLookupTable::isSerializationIDEntry(entry)); - assert(SwiftLookupTable::isDeclEntry(entry)); - return entry >> 2; -} - -namespace { -struct LocalMacroIDs { - uint32_t moduleID; - uint32_t nameOrMacroID; -}; -} - -static LocalMacroIDs getEncodedModuleMacroIDs(uint64_t entry) { - assert(SwiftLookupTable::isSerializationIDEntry(entry)); - assert(SwiftLookupTable::isMacroEntry(entry)); - return {static_cast((entry & 0xFFFFFFFF) >> 2), - static_cast(entry >> 32)}; -} - /// Print a stored entry (Clang macro or declaration) for debugging purposes. -static void printStoredEntry(const SwiftLookupTable *table, uint64_t entry, +static void printStoredEntry(const SwiftLookupTable *table, + StoredSingleEntry &entry, llvm::raw_ostream &out) { - if (SwiftLookupTable::isSerializationIDEntry(entry)) { - if (SwiftLookupTable::isDeclEntry(entry)) { - llvm::errs() << "decl ID #" << getEncodedDeclID(entry); + if (entry.isSerializationIDEntry()) { + if (entry.isDeclEntry()) { + llvm::errs() << "decl ID #" << entry.getSerializationID(); } else { - LocalMacroIDs macroIDs = getEncodedModuleMacroIDs(entry); - if (macroIDs.moduleID == 0) { - llvm::errs() << "macro ID #" << macroIDs.nameOrMacroID; + auto moduleID = entry.getModuleID(); + if (moduleID == 0) { + llvm::errs() << "macro ID #" << entry.getSerializationID(); } else { - llvm::errs() << "macro with name ID #" << macroIDs.nameOrMacroID - << "in submodule #" << macroIDs.moduleID; + llvm::errs() << "macro with name ID #" + << entry.getSerializationID() << "in submodule #" + << moduleID; } } - } else if (SwiftLookupTable::isMacroEntry(entry)) { + } else if (entry.isMacroEntry()) { llvm::errs() << "Macro"; } else { auto decl = const_cast(table)->mapStoredDecl(entry); @@ -1008,7 +994,9 @@ void SwiftLookupTable::dump(raw_ostream &os) const { llvm::interleave( entry.DeclsOrMacros.begin(), entry.DeclsOrMacros.end(), - [this, &os](uint64_t entry) { printStoredEntry(this, entry, os); }, + [this, &os](StoredSingleEntry entry) { + printStoredEntry(this, entry, os); + }, [&os] { os << ", "; }); os << "\n"; } @@ -1050,7 +1038,9 @@ void SwiftLookupTable::dump(raw_ostream &os) const { const auto &entries = GlobalsAsMembersIndex.find(context)->second; llvm::interleave( entries.begin(), entries.end(), - [this, &os](uint64_t entry) { printStoredEntry(this, entry, os); }, + [this, &os](StoredSingleEntry entry) { + printStoredEntry(this, entry, os); + }, [&os] { os << ", "; }); os << "\n"; } @@ -1098,6 +1088,36 @@ namespace { using GlobalsAsMembersIndexRecordLayout = BCRecordLayout, BCBlob>; + constexpr size_t SizeOfEmittedStoredSingleEntry + = sizeof(StoredSingleEntry::SerializationID) + + sizeof(StoredSingleEntry::SubmoduleID); + + static void emitStoredSingleEntry(SwiftLookupTable::SingleEntry &mappedEntry, + clang::ASTWriter &astWriter, + endian::Writer &blobWriter) { + StoredSingleEntry ids; + + // Construct a StoredSingleEntry with the ID(s) for `mappedEntry`. + if (auto *decl = mappedEntry.dyn_cast()) { + ids = StoredSingleEntry::forSerializedDecl( + astWriter.getDeclID(decl).getRawValue()); + } else if (auto *macro = mappedEntry.dyn_cast()) { + ids = StoredSingleEntry::forSerializedMacro(astWriter.getMacroID(macro)); + } else { + auto *moduleMacro = mappedEntry.get(); + StoredSingleEntry::SerializationID nameID = + astWriter.getIdentifierRef(moduleMacro->getName()); + StoredSingleEntry::SubmoduleID submoduleID = + astWriter.getLocalOrImportedSubmoduleID(moduleMacro->getOwningModule()); + ids = StoredSingleEntry::forSerializedMacro(nameID, submoduleID); + } + + // Write it out. + auto idsData = ids.getData(); + blobWriter.write(idsData.first); + blobWriter.write(idsData.second); + } + /// Trait used to write the on-disk hash table for the base name -> entities /// mapping. class BaseNameToEntitiesTableWriterInfo { @@ -1149,7 +1169,8 @@ namespace { dataLength += sizeof(uint16_t); // Actual entries. - dataLength += (sizeof(uint64_t) * entry.DeclsOrMacros.size()); + dataLength += (SizeOfEmittedStoredSingleEntry + * entry.DeclsOrMacros.size()); } endian::Writer writer(out, llvm::endianness::little); @@ -1187,22 +1208,8 @@ namespace { // Write the declarations and macros. for (auto &entry : fullEntry.DeclsOrMacros) { - uint64_t id; auto mappedEntry = Table.mapStored(entry, isModule); - if (auto *decl = mappedEntry.dyn_cast()) { - id = (Writer.getDeclID(decl).getRawValue() << 2) | 0x02; - } else if (auto *macro = mappedEntry.dyn_cast()) { - id = static_cast(Writer.getMacroID(macro)) << 32; - id |= 0x02 | 0x01; - } else { - auto *moduleMacro = mappedEntry.get(); - uint32_t nameID = Writer.getIdentifierRef(moduleMacro->getName()); - uint32_t submoduleID = Writer.getLocalOrImportedSubmoduleID( - moduleMacro->getOwningModule()); - id = (static_cast(nameID) << 32) | (submoduleID << 2); - id |= 0x02 | 0x01; - } - writer.write(id); + emitStoredSingleEntry(mappedEntry, Writer, writer); } } } @@ -1217,7 +1224,7 @@ namespace { public: using key_type = std::pair; using key_type_ref = key_type; - using data_type = SmallVector; + using data_type = SmallVector; using data_type_ref = data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; @@ -1243,7 +1250,7 @@ namespace { // # of entries uint32_t dataLength = - sizeof(uint16_t) + sizeof(uint64_t) * data.size(); + sizeof(uint16_t) + SizeOfEmittedStoredSingleEntry * data.size(); assert(dataLength == static_cast(dataLength)); endian::Writer writer(out, llvm::endianness::little); @@ -1269,22 +1276,8 @@ namespace { // Actual entries. bool isModule = Writer.getLangOpts().isCompilingModule(); for (auto &entry : data) { - uint64_t id; auto mappedEntry = Table.mapStored(entry, isModule); - if (auto *decl = mappedEntry.dyn_cast()) { - id = (Writer.getDeclID(decl).getRawValue() << 2) | 0x02; - } else if (auto *macro = mappedEntry.dyn_cast()) { - id = static_cast(Writer.getMacroID(macro)) << 32; - id |= 0x02 | 0x01; - } else { - auto *moduleMacro = mappedEntry.get(); - uint32_t nameID = Writer.getIdentifierRef(moduleMacro->getName()); - uint32_t submoduleID = Writer.getLocalOrImportedSubmoduleID( - moduleMacro->getOwningModule()); - id = (static_cast(nameID) << 32) | (submoduleID << 2); - id |= 0x02 | 0x01; - } - writer.write(id); + emitStoredSingleEntry(mappedEntry, Writer, writer); } } }; @@ -1402,6 +1395,14 @@ void SwiftLookupTableWriter::writeExtensionContents( } namespace { + StoredSingleEntry readNextStoredSingleEntry(const uint8_t *&data) { + std::pair ids; + ids.first = readNext(data); + ids.second = readNext(data); + return StoredSingleEntry(ids); + } + /// Used to deserialize the on-disk base name -> entities table. class BaseNameToEntitiesTableReaderInfo { public: @@ -1477,8 +1478,7 @@ namespace { // Read the declarations and macros. unsigned numDeclsOrMacros = readNext(data); while (numDeclsOrMacros--) { - auto id = readNext(data); - entry.DeclsOrMacros.push_back(id); + entry.DeclsOrMacros.push_back(readNextStoredSingleEntry(data)); } result.push_back(entry); @@ -1493,7 +1493,7 @@ namespace { public: using internal_key_type = SwiftLookupTable::StoredContext; using external_key_type = internal_key_type; - using data_type = SmallVector; + using data_type = SmallVector; using hash_value_type = uint32_t; using offset_type = unsigned; @@ -1536,8 +1536,7 @@ namespace { // Read all of the entries. while (numEntries--) { - auto id = readNext(data); - result.push_back(id); + result.push_back(readNextStoredSingleEntry(data)); } return result; @@ -1545,24 +1544,24 @@ namespace { }; } // end anonymous namespace -clang::NamedDecl *SwiftLookupTable::mapStoredDecl(uint64_t &entry) { - assert(isDeclEntry(entry) && "Not a declaration entry"); +clang::NamedDecl *SwiftLookupTable::mapStoredDecl(StoredSingleEntry &entry) { + assert(entry.isDeclEntry() && "Not a declaration entry"); // If we have an AST node here, just cast it. - if (isASTNodeEntry(entry)) { - return static_cast(getPointerFromEntry(entry)); + if (entry.isASTNodeEntry()) { + return static_cast(entry.getASTNode()); } // Otherwise, resolve the declaration. assert(Reader && "Cannot resolve the declaration without a reader"); - auto declID = getEncodedDeclID(entry); + auto declID = entry.getSerializationID(); auto localID = clang::LocalDeclID::get(Reader->getASTReader(), Reader->getModuleFile(), declID); auto decl = cast_or_null( Reader->getASTReader().GetLocalDecl(Reader->getModuleFile(), localID)); // Update the entry now that we've resolved the declaration. - entry = encodeEntry(decl); + entry = StoredSingleEntry(decl); return decl; } @@ -1571,31 +1570,30 @@ static bool isPCH(SwiftLookupTableReader &reader) { } SwiftLookupTable::SingleEntry -SwiftLookupTable::mapStoredMacro(uint64_t &entry, bool assumeModule) { - assert(isMacroEntry(entry) && "Not a macro entry"); +SwiftLookupTable::mapStoredMacro(StoredSingleEntry &entry, bool assumeModule) { + assert(entry.isMacroEntry() && "Not a macro entry"); // If we have an AST node here, just cast it. - if (isASTNodeEntry(entry)) { + if (entry.isASTNodeEntry()) { if (assumeModule || (Reader && !isPCH(*Reader))) - return static_cast(getPointerFromEntry(entry)); + return static_cast(entry.getASTNode()); else - return static_cast(getPointerFromEntry(entry)); + return static_cast(entry.getASTNode()); } // Otherwise, resolve the macro. assert(Reader && "Cannot resolve the macro without a reader"); clang::ASTReader &astReader = Reader->getASTReader(); - LocalMacroIDs macroIDs = getEncodedModuleMacroIDs(entry); - if (!assumeModule && macroIDs.moduleID == 0) { + if (!assumeModule && entry.getModuleID() == 0) { assert(isPCH(*Reader)); // Not a module, and the second key is actually a macroID. auto macro = astReader.getMacro(astReader.getGlobalMacroID(Reader->getModuleFile(), - macroIDs.nameOrMacroID)); + entry.getSerializationID())); // Update the entry now that we've resolved the macro. - entry = encodeEntry(macro); + entry = StoredSingleEntry(macro); return macro; } @@ -1604,9 +1602,9 @@ SwiftLookupTable::mapStoredMacro(uint64_t &entry, bool assumeModule) { assert(!isPCH(*Reader)); clang::IdentifierInfo *name = astReader.getLocalIdentifier(Reader->getModuleFile(), - macroIDs.nameOrMacroID); - auto submoduleID = astReader.getGlobalSubmoduleID(Reader->getModuleFile(), - macroIDs.moduleID); + entry.getSerializationID()); + auto submoduleID = astReader.getGlobalSubmoduleID(Reader->getModuleFile(), + entry.getModuleID()); clang::Module *submodule = astReader.getSubmodule(submoduleID); assert(submodule); @@ -1617,13 +1615,13 @@ SwiftLookupTable::mapStoredMacro(uint64_t &entry, bool assumeModule) { // This might still be NULL if the module has been imported but not made // visible. We need a better answer here. if (macro) - entry = encodeEntry(macro); + entry = StoredSingleEntry(macro); return macro; } -SwiftLookupTable::SingleEntry SwiftLookupTable::mapStored(uint64_t &entry, - bool assumeModule) { - if (isDeclEntry(entry)) +SwiftLookupTable::SingleEntry +SwiftLookupTable::mapStored(StoredSingleEntry &entry, bool assumeModule) { + if (entry.isDeclEntry()) return mapStoredDecl(entry); return mapStoredMacro(entry, assumeModule); } @@ -1805,7 +1803,7 @@ SwiftLookupTableReader::getGlobalsAsMembersContexts() { bool SwiftLookupTableReader::lookupGlobalsAsMembersInContext( SwiftLookupTable::StoredContext context, - SmallVectorImpl &entries) { + SmallVectorImpl &entries) { if (!GlobalsAsMembersIndex) return false; // Look for an entry with this context name. diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h index a10fe9e30163e..4b1073a0d8c11 100644 --- a/lib/ClangImporter/SwiftLookupTable.h +++ b/lib/ClangImporter/SwiftLookupTable.h @@ -18,6 +18,7 @@ #define SWIFT_CLANGIMPORTER_SWIFTLOOKUPTABLE_H #include "swift/AST/Identifier.h" +#include "swift/Basic/Assertions.h" #include "swift/Basic/Debug.h" #include "swift/Basic/LLVM.h" #include "clang/AST/Decl.h" @@ -282,7 +283,7 @@ const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MAJOR = 1; /// Lookup table minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 18; // Unsafe C++ method renaming. +const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 19; // 64-bit clang serialization IDs /// A lookup table that maps Swift names to the set of Clang @@ -325,6 +326,137 @@ class SwiftLookupTable { /// ASTContext-independent. typedef std::pair StoredContext; + /// Much like \c SingleEntry , this type references either a named + /// declaration or a macro. However, it may reference it by either a direct + /// pointer to an AST node, or by one or more serialization IDs. + class StoredSingleEntry { + public: + using SerializationID = clang::serialization::DeclID; + using SubmoduleID = clang::serialization::SubmoduleID; + + static_assert(sizeof(SerializationID) >= sizeof(uintptr_t), + "pointer fits into SerializationID"); + static_assert(sizeof(SerializationID) >= + sizeof(clang::serialization::IdentifierID), + "IdentifierID fits into SerializationID"); + + private: + /// Either contains a pointer to an AST node or a serialization ID, + /// depending on the value of \c IsSerializationID . + SerializationID ASTNodeOrSerializationID; + + /// If this is equal to \c IS_DECL , this entry represents a declaration. + /// Otherwise it represents a macro, and the value is the associated module + /// ID. (Note that the associated module ID is often zero, meaning the ID + /// is unused but this \em is a macro.) + SubmoduleID IsDeclOrMacroModuleID; + + /// If \c true , \c ASTNodeOrSerializationID is a serialization ID; + /// otherwise, it is a pointer to an AST node. + bool IsSerializationID; + // Note: `IsSerializationID` is intentionally stored out of band so that it + // cannot be cleared by reading the wrong value from disk. If you bit-pack + // it, take care to force it to the right value when necessary. + + /// Sentinel used in \c IsDeclOrMacroModuleID to indicate that the entry is + /// for a decl. + static constexpr SubmoduleID IS_DECL = + std::numeric_limits::max(); + + StoredSingleEntry(void *astNode, SubmoduleID isDeclOrMacroModuleID) + : ASTNodeOrSerializationID(reinterpret_cast(astNode)), + IsDeclOrMacroModuleID(isDeclOrMacroModuleID), + IsSerializationID(false) + {} + + StoredSingleEntry(SerializationID serializationID, + SubmoduleID isDeclOrMacroModuleID) + : ASTNodeOrSerializationID(serializationID), + IsDeclOrMacroModuleID(isDeclOrMacroModuleID), + IsSerializationID(true) + {} + + public: + /// Whether the given entry is a declaration entry. + bool isDeclEntry() const { return IsDeclOrMacroModuleID == IS_DECL; } + + /// Whether the given entry is a macro entry. + bool isMacroEntry() const { return !isDeclEntry(); } + + /// Whether the given entry is a serialization ID. + bool isSerializationIDEntry() const { return IsSerializationID; } + + /// Whether the given entry is an AST node. + bool isASTNodeEntry() const { return !isSerializationIDEntry(); } + + /// Retrieve the pointer for an entry. + void *getASTNode() const { + ASSERT(isASTNodeEntry() && "Not an AST node entry"); + return reinterpret_cast( + static_cast(ASTNodeOrSerializationID)); + } + + /// Get the serialization ID out of the entry. + SerializationID getSerializationID() const { + ASSERT(isSerializationIDEntry()); + return ASTNodeOrSerializationID; + } + + /// Get the module ID out of the entry. Do not call on an entry representing a decl. + SubmoduleID getModuleID() const { + ASSERT(isSerializationIDEntry()); + ASSERT(isMacroEntry()); + return IsDeclOrMacroModuleID; + } + + /// Convert this entry to an on-disk representation. Do not call on an + /// entry backed by an AST node; these cannot be directly represented on + /// disk. + std::pair getData() const { + return { getSerializationID(), IsDeclOrMacroModuleID }; + } + + /// Encode an empty entry. + StoredSingleEntry() + : StoredSingleEntry(nullptr, IS_DECL) + {} + + /// Encode a Clang named declaration as an entry in the table. + StoredSingleEntry(clang::NamedDecl *decl) + : StoredSingleEntry(decl, IS_DECL) + {} + + /// Encode a Clang macro as an entry in the table. + StoredSingleEntry(clang::MacroInfo *macro) + : StoredSingleEntry(macro, 0) + {} + + /// Encode a Clang macro as an entry in the table. + StoredSingleEntry(clang::ModuleMacro *macro) + : StoredSingleEntry(macro, 0) + {} + + /// Encode a Clang decl as an entry in the table by its serialization ID. + static StoredSingleEntry + forSerializedDecl(SerializationID serializationID) { + return StoredSingleEntry(serializationID, IS_DECL); + } + + /// Encode a Clang macro as an entry in the table by its serialization ID + /// and, optionally, the serialization ID of the submodule it belongs to. + static StoredSingleEntry + forSerializedMacro(SerializationID serializationID, + SubmoduleID moduleID = 0) { + ASSERT(moduleID != IS_DECL && "oversized clang moduleID"); + return StoredSingleEntry(serializationID, moduleID); + } + + /// Convert the on-disk representation to an entry. + StoredSingleEntry(std::pair data) + : StoredSingleEntry(data.first, data.second) + {} + }; + /// An entry in the table of C entities indexed by full Swift name. struct FullTableEntry { /// The context in which the entities with the given name occur, e.g., @@ -334,63 +466,9 @@ class SwiftLookupTable { /// The set of Clang declarations and macros with this name and in /// this context. - /// - /// The low bit indicates whether we have a declaration or macro - /// (declaration = unset, macro = set) and the second lowest bit - /// indicates whether we have a serialization ID (set = DeclID or - /// {IdentifierID,SubmoduleID}, as appropriate) vs. a pointer (unset, - /// clang::NamedDecl *, clang::MacroInfo *, clang::ModuleMacro *). - /// In the ID case, the upper N-2 bits are the ID value; in the pointer - /// case, the lower two bits will always be clear due to the alignment of - /// the Clang pointers. - llvm::SmallVector DeclsOrMacros; + llvm::SmallVector DeclsOrMacros; }; - /// Whether the given entry is a macro entry. - static bool isMacroEntry(uint64_t entry) { return entry & 0x01; } - - /// Whether the given entry is a declaration entry. - static bool isDeclEntry(uint64_t entry) { return !isMacroEntry(entry); } - - /// Whether the given entry is a serialization ID. - static bool isSerializationIDEntry(uint64_t entry) { return (entry & 0x02); } - - /// Whether the given entry is an AST node. - static bool isASTNodeEntry(uint64_t entry) { - return !isSerializationIDEntry(entry); - } - - /// Retrieve the pointer for an entry. - static void *getPointerFromEntry(uint64_t entry) { - assert(isASTNodeEntry(entry) && "Not an AST node entry"); - const uint64_t mask = ~static_cast(0x03); - return reinterpret_cast(entry & mask); - } - - /// Encode a Clang named declaration as an entry in the table. - static uint64_t encodeEntry(clang::NamedDecl *decl) { - assert(decl); - auto bits = reinterpret_cast(decl); - assert((bits & 0x03) == 0 && "low bits set?"); - return bits; - } - - // Encode a Clang macro as an entry in the table. - static uint64_t encodeEntry(clang::MacroInfo *macro) { - assert(macro); - auto bits = reinterpret_cast(macro); - assert((bits & 0x03) == 0 && "low bits set?"); - return bits | 0x01; - } - - // Encode a Clang macro as an entry in the table. - static uint64_t encodeEntry(clang::ModuleMacro *macro) { - assert(macro); - auto bits = reinterpret_cast(macro); - assert((bits & 0x03) == 0 && "low bits set?"); - return bits | 0x01; - } - private: using TableType = llvm::DenseMap>; @@ -414,7 +492,8 @@ class SwiftLookupTable { /// /// The values use the same representation as /// FullTableEntry::DeclsOrMacros. - llvm::DenseMap> GlobalsAsMembersIndex; + llvm::DenseMap> + GlobalsAsMembersIndex; /// The reader responsible for lazily loading the contents of this table. SwiftLookupTableReader *Reader; @@ -437,19 +516,22 @@ class SwiftLookupTable { /// present. /// /// \returns true if the entry was added, false otherwise. - bool addLocalEntry(SingleEntry newEntry, SmallVectorImpl &entries); + bool addLocalEntry(SingleEntry newEntry, + SmallVectorImpl &entries); public: explicit SwiftLookupTable(SwiftLookupTableReader *reader) : Reader(reader) { } /// Maps a stored declaration entry to an actual Clang declaration. - clang::NamedDecl *mapStoredDecl(uint64_t &entry); + clang::NamedDecl *mapStoredDecl(StoredSingleEntry &entry); /// Maps a stored macro entry to an actual Clang macro. - SingleEntry mapStoredMacro(uint64_t &entry, bool assumeModule = false); + SingleEntry mapStoredMacro(StoredSingleEntry &entry, + bool assumeModule = false); /// Maps a stored entry to an actual Clang AST node. - SingleEntry mapStored(uint64_t &entry, bool assumeModule = false); + SingleEntry mapStored(StoredSingleEntry &entry, + bool assumeModule = false); /// Translate a Clang DeclContext into a context kind and name. static std::optional