Skip to content

Commit

Permalink
Exposes interface to free up caching data structure in DWARFDebugLine…
Browse files Browse the repository at this point in the history
… and DWARFUnit for memory management

This is minimum changes extracted from https://reviews.llvm.org/D78950. The old patch tried to add LRU eviction of caching data structure. Due to multiple layers of interfaces that users could be using, it was not clear where to put the functionality. While we work out on where to put that functionality, it'll be great to add this minimum interface change so that the user could implement their own memory management. More specifically:

* Add a clearLineTable method for DWARFDebugLine which erases the given offset from the LineTableMap.
* DWARFDebugContext adds the clearLineTableForUnit method that leverages clearLineTable to remove the object corresponding to a given compile unit, for memory management purposes. When it is referred to again, the line table object will be repopulated.

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D90006
  • Loading branch information
hk-cho authored and dwblaikie committed May 24, 2022
1 parent ca81abc commit 6c12ae8
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 0 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
Expand Up @@ -333,6 +333,10 @@ class DWARFContext : public DIContext {
getLineTableForUnit(DWARFUnit *U,
function_ref<void(Error)> 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);
}
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
Expand Up @@ -304,6 +304,7 @@ class DWARFDebugLine {
getOrParseLineTable(DWARFDataExtractor &DebugLineData, uint64_t Offset,
const DWARFContext &Ctx, const DWARFUnit *U,
function_ref<void(Error)> RecoverableErrorHandler);
void clearLineTable(uint64_t Offset);

/// Helper to allow for parsing of an entire .debug_line section in sequence.
class SectionParser {
Expand Down
16 changes: 16 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
Expand Up @@ -1003,6 +1003,22 @@ Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit(
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;
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
Expand Up @@ -601,6 +601,10 @@ Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
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)
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
Expand Up @@ -380,6 +380,9 @@ void DWARFUnit::clear() {
AddrOffsetSectionBase = None;
SU = nullptr;
clearDIEs(false);
AddrDieMap.clear();
if (DWO)
DWO->clear();
DWO.reset();
}

Expand Down
76 changes: 76 additions & 0 deletions llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
Expand Up @@ -330,6 +330,82 @@ TEST_P(DebugLineParameterisedFixture, GetOrParseLineTableValidTable) {
// correctly.
}

#ifdef _AIX
TEST_P(DebugLineParameterisedFixture, DISABLED_ClearLineValidTable) {
#else
TEST_P(DebugLineParameterisedFixture, ClearLineValidTable) {
#endif
if (!setupGenerator(Version))
GTEST_SKIP();

SCOPED_TRACE("Checking Version " + std::to_string(Version) + ", Format " +
(Format == DWARF64 ? "DWARF64" : "DWARF32"));

LineTable &LT = Gen->addLineTable(Format);
LT.addExtendedOpcode(9, DW_LNE_set_address, {{0xadd4e55, LineTable::Quad}});
LT.addStandardOpcode(DW_LNS_copy, {});
LT.addByte(0xaa);
LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});

LineTable &LT2 = Gen->addLineTable(Format);
LT2.addExtendedOpcode(9, DW_LNE_set_address, {{0x11223344, LineTable::Quad}});
LT2.addStandardOpcode(DW_LNS_copy, {});
LT2.addByte(0xbb);
LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {});
LT2.addExtendedOpcode(9, DW_LNE_set_address, {{0x55667788, LineTable::Quad}});
LT2.addStandardOpcode(DW_LNS_copy, {});
LT2.addByte(0xcc);
LT2.addExtendedOpcode(1, DW_LNE_end_sequence, {});

generate();

// Check that we have what we expect before calling clearLineTable().
auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
nullptr, RecordRecoverable);
ASSERT_TRUE((bool)ExpectedLineTable);
EXPECT_FALSE(Recoverable);
const DWARFDebugLine::LineTable *Expected = *ExpectedLineTable;
checkDefaultPrologue(Version, Format, Expected->Prologue, 16);
EXPECT_EQ(Expected->Sequences.size(), 1u);

uint64_t SecondOffset =
Expected->Prologue.sizeofTotalLength() + Expected->Prologue.TotalLength;
Recoverable = Error::success();
auto ExpectedLineTable2 = Line.getOrParseLineTable(
LineData, SecondOffset, *Context, nullptr, RecordRecoverable);
ASSERT_TRUE((bool)ExpectedLineTable2);
EXPECT_FALSE(Recoverable);
const DWARFDebugLine::LineTable *Expected2 = *ExpectedLineTable2;
checkDefaultPrologue(Version, Format, Expected2->Prologue, 32);
EXPECT_EQ(Expected2->Sequences.size(), 2u);

// Check that we no longer get the line tables after clearLineTable().
Line.clearLineTable(0);
Line.clearLineTable(SecondOffset);
EXPECT_EQ(Line.getLineTable(0), nullptr);
EXPECT_EQ(Line.getLineTable(SecondOffset), nullptr);

// Check that if the same offset is requested, the contents match what we
// had before.
Recoverable = Error::success();
auto ExpectedLineTable3 = Line.getOrParseLineTable(
LineData, 0, *Context, nullptr, RecordRecoverable);
ASSERT_TRUE((bool)ExpectedLineTable3);
EXPECT_FALSE(Recoverable);
const DWARFDebugLine::LineTable *Expected3 = *ExpectedLineTable3;
checkDefaultPrologue(Version, Format, Expected3->Prologue, 16);
EXPECT_EQ(Expected3->Sequences.size(), 1u);

Recoverable = Error::success();
auto ExpectedLineTable4 = Line.getOrParseLineTable(
LineData, SecondOffset, *Context, nullptr, RecordRecoverable);
ASSERT_TRUE((bool)ExpectedLineTable4);
EXPECT_FALSE(Recoverable);
const DWARFDebugLine::LineTable *Expected4 = *ExpectedLineTable4;
checkDefaultPrologue(Version, Format, Expected4->Prologue, 32);
EXPECT_EQ(Expected4->Sequences.size(), 2u);
}

#ifdef _AIX
TEST_F(DebugLineBasicFixture, DISABLED_ErrorForReservedLength) {
#else
Expand Down

0 comments on commit 6c12ae8

Please sign in to comment.