diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -38,8 +38,10 @@ #include "llvm/Support/Host.h" #include #include +#include #include #include +#include namespace llvm { @@ -114,13 +116,23 @@ // FIXME: Add support for.debug_macro.dwo section. }; + // LRU mechanism of compile units to manage memory usage. + using unit_queue_type = std::list; + using unit_queue_iterator = unit_queue_type::iterator; + using unit_map_type = std::unordered_map; + unit_queue_type CompileUnitQueue; + unit_map_type CompileUnitMap; + const int CompileUnitLRUSize; + static constexpr int DefaultLRUSize = 10; + public: DWARFContext(std::unique_ptr DObj, std::string DWPName = "", std::function RecoverableErrorHandler = WithColor::defaultErrorHandler, std::function WarningHandler = - WithColor::defaultWarningHandler); + WithColor::defaultWarningHandler, + int LRUSize = DefaultLRUSize); ~DWARFContext(); DWARFContext(DWARFContext &) = delete; @@ -316,6 +328,10 @@ getLineTableForUnit(DWARFUnit *U, function_ref RecoverableErrorHandler); + // Clear the line table object corresponding to a compile unit for memory + // management purpose. When it's referred to again, it'll be re-populated. + void clearLineTableForUnit(DWARFUnit *U); + DataExtractor getStringExtractor() const { return DataExtractor(DObj->getStrSection(), false, 0); } @@ -371,7 +387,8 @@ std::function RecoverableErrorHandler = WithColor::defaultErrorHandler, std::function WarningHandler = - WithColor::defaultWarningHandler); + WithColor::defaultWarningHandler, + int LRUSize = DefaultLRUSize); static std::unique_ptr create(const StringMap> &Sections, @@ -379,7 +396,8 @@ std::function RecoverableErrorHandler = WithColor::defaultErrorHandler, std::function WarningHandler = - WithColor::defaultWarningHandler); + WithColor::defaultWarningHandler, + int LRUSize = DefaultLRUSize); /// Loads register info for the architecture of the provided object file. /// Improves readability of dumped DWARF expressions. Requires the caller to @@ -394,6 +412,9 @@ return getDWARFObj().getFile()->getArch(); } + // Refer a compile unit so that it's pushed back in LRU. + void referCompileUnit(DWARFUnit *CU); + private: /// Parse a macro[.dwo] or macinfo[.dwo] section. std::unique_ptr diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -305,6 +305,7 @@ getOrParseLineTable(DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx, const DWARFUnit *U, function_ref RecoverableErrorHandler); + void clearLineTable(uint64_t Offset); /// Helper to allow for parsing of an entire .debug_line section in sequence. class SectionParser { diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -67,10 +67,12 @@ DWARFContext::DWARFContext(std::unique_ptr DObj, std::string DWPName, std::function RecoverableErrorHandler, - std::function WarningHandler) + std::function WarningHandler, + int LRUSize) : DIContext(CK_DWARF), DWPName(std::move(DWPName)), RecoverableErrorHandler(RecoverableErrorHandler), - WarningHandler(WarningHandler), DObj(std::move(DObj)) {} + WarningHandler(WarningHandler), DObj(std::move(DObj)), + CompileUnitLRUSize(LRUSize) {} DWARFContext::~DWARFContext() = default; @@ -917,6 +919,22 @@ RecoverableErrorHandler); } +void DWARFContext::clearLineTableForUnit(DWARFUnit *U) { + if (!Line) + return; + + auto UnitDIE = U->getUnitDIE(); + if (!UnitDIE) + return; + + auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); + if (!Offset) + return; + + uint64_t stmtOffset = *Offset + U->getLineTableOffset(); + Line->clearLineTable(stmtOffset); +} + void DWARFContext::parseNormalUnits() { if (!NormalUnits.empty()) return; @@ -954,12 +972,34 @@ return getCompileUnitForOffset(CUOffset); } +void DWARFContext::referCompileUnit(DWARFUnit *CU) { + if (CompileUnitLRUSize <= 0) + return; + if (CU == nullptr) + return; + auto I = CompileUnitMap.find(CU); + if (I == CompileUnitMap.end()) { + if (CompileUnitQueue.size() == CompileUnitLRUSize) { + DWARFUnit *LRU = CompileUnitQueue.back(); + CompileUnitQueue.pop_back(); + CompileUnitMap.erase(LRU); + clearLineTableForUnit(LRU); + LRU->clear(); + } + } else { + CompileUnitQueue.erase(I->second); + } + CompileUnitQueue.push_front(CU); + CompileUnitMap[CU] = CompileUnitQueue.begin(); +} + DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) { DIEsForAddress Result; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return Result; + referCompileUnit(CU); Result.CompileUnit = CU; Result.FunctionDIE = CU->getSubroutineForAddress(Address); @@ -1164,6 +1204,7 @@ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); if (!CU) return Result; + referCompileUnit(CU); DWARFDie Subprogram = CU->getSubroutineForAddress(Address.Address); if (Subprogram.isValid()) @@ -1178,6 +1219,7 @@ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); if (!CU) return Result; + referCompileUnit(CU); getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind, Result.FunctionName, Result.StartLine); @@ -1197,6 +1239,7 @@ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); if (!CU) return Lines; + referCompileUnit(CU); uint32_t StartLine = 0; std::string FunctionName(DILineInfo::BadString); @@ -1246,6 +1289,7 @@ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); if (!CU) return InliningInfo; + referCompileUnit(CU); const DWARFLineTable *LineTable = nullptr; SmallVector InlinedChain; @@ -1897,23 +1941,23 @@ DWARFContext::create(const object::ObjectFile &Obj, const LoadedObjectInfo *L, std::string DWPName, std::function RecoverableErrorHandler, - std::function WarningHandler) { + std::function WarningHandler, int LRUSize) { auto DObj = std::make_unique(Obj, L, RecoverableErrorHandler, WarningHandler); return std::make_unique(std::move(DObj), std::move(DWPName), - RecoverableErrorHandler, - WarningHandler); + RecoverableErrorHandler, WarningHandler, + LRUSize); } std::unique_ptr DWARFContext::create(const StringMap> &Sections, uint8_t AddrSize, bool isLittleEndian, std::function RecoverableErrorHandler, - std::function WarningHandler) { + std::function WarningHandler, int LRUSize) { auto DObj = std::make_unique(Sections, AddrSize, isLittleEndian); return std::make_unique( - std::move(DObj), "", RecoverableErrorHandler, WarningHandler); + std::move(DObj), "", RecoverableErrorHandler, WarningHandler, LRUSize); } Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) { diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -568,6 +568,10 @@ return LT; } +void DWARFDebugLine::clearLineTable(uint64_t Offset) { + LineTableMap.erase(Offset); +} + static StringRef getOpcodeName(uint8_t Opcode, uint8_t OpcodeBase) { assert(Opcode != 0); if (Opcode < OpcodeBase) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -367,6 +367,9 @@ LocSectionBase = 0; AddrOffsetSectionBase = None; clearDIEs(false); + AddrDieMap.clear(); + if (DWO) + DWO->clear(); DWO.reset(); }