Index: clang/include/clang/Basic/SourceManager.h =================================================================== --- clang/include/clang/Basic/SourceManager.h +++ clang/include/clang/Basic/SourceManager.h @@ -69,6 +69,33 @@ /// SourceManager implementation. namespace SrcMgr { + /// Optional index for loadable SLoc entries. Semantics of Optional + /// but without storage overhead. + class LoadedSLocEntryIndex { + public: + explicit operator bool() const { return Data; } + unsigned operator*() const { + assert(*this && "Dereferencing None?"); + return Data - 1; + } + + LoadedSLocEntryIndex &operator=(llvm::NoneType) { + return *this = LoadedSLocEntryIndex(None); + } + LoadedSLocEntryIndex &operator=(unsigned I) { + return *this = LoadedSLocEntryIndex(I); + } + LoadedSLocEntryIndex(llvm::NoneType = None) : Data(0) {} + LoadedSLocEntryIndex(unsigned I) : Data(I + 1) { + assert(*this && "Index too big"); + } + + private: + /// Index stored off-by-one with 0 as a sentinel to enable + /// zero-initialization. + unsigned Data; + }; + /// Indicates whether a file or directory holds normal user code, /// system code, or system code which is implicitly 'extern "C"' in C++ mode. /// @@ -677,8 +704,8 @@ /// The table of SLocEntries that are loaded from other modules. /// - /// Negative FileIDs are indexes into this table. To get from ID to an index, - /// use (-ID - 2). + /// Negative FileIDs are indexes into LoadedSLocEntryIndices, which contains the + /// index into this table. SmallVector LoadedSLocEntryTable; /// The starting offset of the next local SLocEntry. @@ -688,19 +715,21 @@ /// The starting offset of the latest batch of loaded SLocEntries. /// - /// This is LoadedSLocEntryTable.back().Offset, except that that entry might - /// not have been loaded, so that value would be unknown. + /// This is LoadedSLocEntryTable[LoadedSLocEntryIndices.back()].Offset, + /// except that that entry might not have been loaded, so that value would be + /// unknown. unsigned CurrentLoadedOffset; /// The highest possible offset is 2^31-1, so CurrentLoadedOffset /// starts at 2^31. static const unsigned MaxLoadedOffset = 1U << 31U; - /// A bitmap that indicates whether the entries of LoadedSLocEntryTable - /// have already been loaded from the external source. + /// An optional index into LoadedSLocEntryTable, where None indicates that an + /// SLocEntry has not yet been allocated. /// - /// Same indexing as LoadedSLocEntryTable. - llvm::BitVector SLocEntryLoaded; + /// Negative FileIDs are indexes into this table. To get from ID to an index, + /// use (-ID - 2). + SmallVector LoadedSLocEntryIndices; /// An external source for source location entries. ExternalSLocEntrySource *ExternalSLocEntries = nullptr; @@ -1659,14 +1688,14 @@ } /// Get the number of loaded SLocEntries we have. - unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();} + unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryIndices.size(); } /// Get a loaded SLocEntry. This is exposed for indexing. const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index, bool *Invalid = nullptr) const { - assert(Index < LoadedSLocEntryTable.size() && "Invalid index"); - if (SLocEntryLoaded[Index]) - return LoadedSLocEntryTable[Index]; + assert(Index < LoadedSLocEntryIndices.size() && "Invalid index"); + if (auto I = LoadedSLocEntryIndices[Index]) + return LoadedSLocEntryTable[*I]; return loadSLocEntry(Index, Invalid); } @@ -1682,7 +1711,7 @@ unsigned getNextLocalOffset() const { return NextLocalOffset; } void setExternalSLocEntrySource(ExternalSLocEntrySource *Source) { - assert(LoadedSLocEntryTable.empty() && + assert(LoadedSLocEntryIndices.empty() && "Invalidating existing loaded entries"); ExternalSLocEntries = Source; } Index: clang/lib/Basic/SourceManager.cpp =================================================================== --- clang/lib/Basic/SourceManager.cpp +++ clang/lib/Basic/SourceManager.cpp @@ -331,7 +331,7 @@ MainFileID = FileID(); LocalSLocEntryTable.clear(); LoadedSLocEntryTable.clear(); - SLocEntryLoaded.clear(); + LoadedSLocEntryIndices.clear(); LastLineNoFileIDQuery = FileID(); LastLineNoContentCache = nullptr; LastFileIDLookup = FileID(); @@ -367,8 +367,8 @@ }; // Ensure all SLocEntries are loaded from the external source. - for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I) - if (!Old.SLocEntryLoaded[I]) + for (unsigned I = 0, N = Old.LoadedSLocEntryIndices.size(); I != N; ++I) + if (!Old.LoadedSLocEntryIndices[I]) Old.loadSLocEntry(I, nullptr); // Inherit any content cache data from the old source manager. @@ -429,12 +429,12 @@ const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index, bool *Invalid) const { - assert(!SLocEntryLoaded[Index]); + assert(!LoadedSLocEntryIndices[Index]); if (ExternalSLocEntries->ReadSLocEntry(-(static_cast(Index) + 2))) { if (Invalid) *Invalid = true; // If the file of the SLocEntry changed we could still have loaded it. - if (!SLocEntryLoaded[Index]) { + if (!LoadedSLocEntryIndices[Index]) { // Try to recover; create a SLocEntry so the rest of clang can handle it. if (!FakeSLocEntryForRecovery) FakeSLocEntryForRecovery = std::make_unique( @@ -445,7 +445,8 @@ } } - return LoadedSLocEntryTable[Index]; + assert(LoadedSLocEntryIndices[Index] && "Failed to load but returned success"); + return LoadedSLocEntryTable[*LoadedSLocEntryIndices[Index]]; } std::pair @@ -455,10 +456,9 @@ // Make sure we're not about to run out of source locations. if (CurrentLoadedOffset - TotalSize < NextLocalOffset) return std::make_pair(0, 0); - LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries); - SLocEntryLoaded.resize(LoadedSLocEntryTable.size()); + LoadedSLocEntryIndices.resize(LoadedSLocEntryIndices.size() + NumSLocEntries); CurrentLoadedOffset -= TotalSize; - int ID = LoadedSLocEntryTable.size(); + int ID = LoadedSLocEntryIndices.size(); return std::make_pair(-ID - 1, CurrentLoadedOffset); } @@ -497,7 +497,7 @@ if (ID > 0) { if (ID-1 == 0) return FileID(); - } else if (unsigned(-(ID-1) - 2) >= LoadedSLocEntryTable.size()) { + } else if (unsigned(-(ID - 1) - 2) >= LoadedSLocEntryIndices.size()) { return FileID(); } @@ -598,11 +598,12 @@ if (LoadedID < 0) { assert(LoadedID != -1 && "Loading sentinel FileID"); unsigned Index = unsigned(-LoadedID) - 2; - assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); - assert(!SLocEntryLoaded[Index] && "FileID already loaded"); - LoadedSLocEntryTable[Index] = SLocEntry::get( - LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename)); - SLocEntryLoaded[Index] = true; + assert(Index < LoadedSLocEntryIndices.size() && "FileID out of range"); + assert(!LoadedSLocEntryIndices[Index] && "FileID already loaded"); + LoadedSLocEntryIndices[Index] = LoadedSLocEntryTable.size(); + LoadedSLocEntryTable.push_back( + SLocEntry::get(LoadedOffset, FileInfo::get(IncludePos, File, + FileCharacter, Filename))); return FileID::get(LoadedID); } unsigned FileSize = File.getSize(); @@ -664,10 +665,10 @@ if (LoadedID < 0) { assert(LoadedID != -1 && "Loading sentinel FileID"); unsigned Index = unsigned(-LoadedID) - 2; - assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); - assert(!SLocEntryLoaded[Index] && "FileID already loaded"); - LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info); - SLocEntryLoaded[Index] = true; + assert(Index < LoadedSLocEntryIndices.size() && "FileID out of range"); + assert(!LoadedSLocEntryIndices[Index] && "FileID already loaded"); + LoadedSLocEntryIndices[Index] = LoadedSLocEntryTable.size(); + LoadedSLocEntryTable.push_back(SLocEntry::get(LoadedOffset, Info)); return SourceLocation::getMacroLoc(LoadedOffset); } LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info)); @@ -899,7 +900,7 @@ // table: GreaterIndex is the one where the offset is greater, which is // actually a lower index! unsigned GreaterIndex = I; - unsigned LessIndex = LoadedSLocEntryTable.size(); + unsigned LessIndex = LoadedSLocEntryIndices.size(); NumProbes = 0; while (true) { ++NumProbes; @@ -2090,8 +2091,8 @@ << llvm::capacity_in_bytes(LocalSLocEntryTable) << " bytes of capacity), " << NextLocalOffset << "B of Sloc address space used.\n"; - llvm::errs() << LoadedSLocEntryTable.size() - << " loaded SLocEntries allocated, " + llvm::errs() << LoadedSLocEntryIndices.size() << " loaded SLocEntries (" + << LoadedSLocEntryTable.size() << " allocated), " << MaxLoadedOffset - CurrentLoadedOffset << "B of Sloc address space used.\n"; @@ -2155,11 +2156,11 @@ } // Dump loaded SLocEntries. llvm::Optional NextStart; - for (unsigned Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) { + for (unsigned Index = 0; Index != LoadedSLocEntryIndices.size(); ++Index) { int ID = -(int)Index - 2; - if (SLocEntryLoaded[Index]) { - DumpSLocEntry(ID, LoadedSLocEntryTable[Index], NextStart); - NextStart = LoadedSLocEntryTable[Index].getOffset(); + if (auto I = LoadedSLocEntryIndices[Index]) { + DumpSLocEntry(ID, LoadedSLocEntryTable[*I], NextStart); + NextStart = LoadedSLocEntryTable[*I].getOffset(); } else { NextStart = None; } @@ -2192,7 +2193,7 @@ size_t size = llvm::capacity_in_bytes(MemBufferInfos) + llvm::capacity_in_bytes(LocalSLocEntryTable) + llvm::capacity_in_bytes(LoadedSLocEntryTable) - + llvm::capacity_in_bytes(SLocEntryLoaded) + + llvm::capacity_in_bytes(LoadedSLocEntryIndices) + llvm::capacity_in_bytes(FileInfos); if (OverriddenFilesInfo) Index: clang/unittests/Basic/SourceManagerTest.cpp =================================================================== --- clang/unittests/Basic/SourceManagerTest.cpp +++ clang/unittests/Basic/SourceManagerTest.cpp @@ -514,6 +514,38 @@ EXPECT_FALSE(SourceMgr.isMainFile(*SecondFile)); } +TEST_F(SourceManagerTest, LoadedSLocEntryIndex) { + using SrcMgr::LoadedSLocEntryIndex; + + // Check operator bool. + EXPECT_FALSE(LoadedSLocEntryIndex()); + EXPECT_TRUE(LoadedSLocEntryIndex(0U)); + EXPECT_TRUE(LoadedSLocEntryIndex(1U)); + EXPECT_TRUE(LoadedSLocEntryIndex(-2U)); +#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST + EXPECT_DEATH(LoadedSLocEntryIndex(-1U), "Index too big"); +#endif + EXPECT_FALSE(LoadedSLocEntryIndex(None)); + + // Check operator*. +#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST + EXPECT_DEATH(*LoadedSLocEntryIndex(), "Dereferencing None?"); +#endif + EXPECT_EQ(0U, *LoadedSLocEntryIndex(0U)); + EXPECT_EQ(1U, *LoadedSLocEntryIndex(1U)); + EXPECT_EQ(-2U, *LoadedSLocEntryIndex(-2U)); + + // Check operator=. + LoadedSLocEntryIndex I; + EXPECT_EQ(0U, *(I = 0U)); + EXPECT_EQ(1U, *(I = 1U)); + EXPECT_EQ(-2U, *(I = -2U)); +#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST + EXPECT_DEATH((I = -1U), "Index too big"); +#endif + EXPECT_FALSE((I = None)); +} + #endif } // anonymous namespace