680 lines
23 KiB
C++
Raw Normal View History

//===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing accelerator tables.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/AccelTable.h"
#include "DwarfCompileUnit.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <vector>
using namespace llvm;
void AccelTableBase::computeBucketCount() {
// First get the number of unique hashes.
std::vector<uint32_t> Uniques;
Uniques.reserve(Entries.size());
for (const auto &E : Entries)
Uniques.push_back(E.second.HashValue);
array_pod_sort(Uniques.begin(), Uniques.end());
std::vector<uint32_t>::iterator P =
std::unique(Uniques.begin(), Uniques.end());
UniqueHashCount = std::distance(Uniques.begin(), P);
if (UniqueHashCount > 1024)
BucketCount = UniqueHashCount / 4;
else if (UniqueHashCount > 16)
BucketCount = UniqueHashCount / 2;
else
BucketCount = std::max<uint32_t>(UniqueHashCount, 1);
}
void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
// Create the individual hash data outputs.
for (auto &E : Entries) {
// Unique the entries.
std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
[](const AccelTableData *A, const AccelTableData *B) {
return *A < *B;
});
E.second.Values.erase(
std::unique(E.second.Values.begin(), E.second.Values.end()),
E.second.Values.end());
}
// Figure out how many buckets we need, then compute the bucket contents and
// the final ordering. The hashes and offsets can be emitted by walking these
// data structures. We add temporary symbols to the data so they can be
// referenced when emitting the offsets.
computeBucketCount();
// Compute bucket contents and final ordering.
Buckets.resize(BucketCount);
for (auto &E : Entries) {
uint32_t Bucket = E.second.HashValue % BucketCount;
Buckets[Bucket].push_back(&E.second);
E.second.Sym = Asm->createTempSymbol(Prefix);
}
// Sort the contents of the buckets by hash value so that hash collisions end
// up together. Stable sort makes testing easier and doesn't cost much more.
for (auto &Bucket : Buckets)
std::stable_sort(Bucket.begin(), Bucket.end(),
[](HashData *LHS, HashData *RHS) {
return LHS->HashValue < RHS->HashValue;
});
}
namespace {
/// Base class for writing out Accelerator tables. It holds the common
/// functionality for the two Accelerator table types.
class AccelTableEmitter {
protected:
AsmPrinter *const Asm; ///< Destination.
const AccelTableBase &Contents; ///< Data to emit.
/// Controls whether to emit duplicate hash and offset table entries for names
/// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
/// tables do.
const bool SkipIdenticalHashes;
void emitHashes() const;
/// Emit offsets to lists of entries with identical names. The offsets are
/// relative to the Base argument.
void emitOffsets(const MCSymbol *Base) const;
public:
AccelTableEmitter(AsmPrinter *Asm, const AccelTableBase &Contents,
bool SkipIdenticalHashes)
: Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
}
};
class AppleAccelTableEmitter : public AccelTableEmitter {
using Atom = AppleAccelTableData::Atom;
/// The fixed header of an Apple Accelerator Table.
struct Header {
uint32_t Magic = MagicHash;
uint16_t Version = 1;
uint16_t HashFunction = dwarf::DW_hash_function_djb;
uint32_t BucketCount;
uint32_t HashCount;
uint32_t HeaderDataLength;
/// 'HASH' magic value to detect endianness.
static const uint32_t MagicHash = 0x48415348;
Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
: BucketCount(BucketCount), HashCount(UniqueHashCount),
HeaderDataLength(DataLength) {}
void emit(AsmPrinter *Asm) const;
#ifndef NDEBUG
void print(raw_ostream &OS) const;
void dump() const { print(dbgs()); }
#endif
};
/// The HeaderData describes the structure of an Apple accelerator table
/// through a list of Atoms.
struct HeaderData {
/// In the case of data that is referenced via DW_FORM_ref_* the offset
/// base is used to describe the offset for all forms in the list of atoms.
uint32_t DieOffsetBase;
const SmallVector<Atom, 4> Atoms;
HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
: DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
void emit(AsmPrinter *Asm) const;
#ifndef NDEBUG
void print(raw_ostream &OS) const;
void dump() const { print(dbgs()); }
#endif
};
Header Header;
HeaderData HeaderData;
const MCSymbol *SecBegin;
void emitBuckets() const;
void emitData() const;
public:
AppleAccelTableEmitter(AsmPrinter *Asm, const AccelTableBase &Contents,
ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
: AccelTableEmitter(Asm, Contents, true),
Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
8 + (Atoms.size() * 4)),
HeaderData(Atoms), SecBegin(SecBegin) {}
void emit() const;
#ifndef NDEBUG
void print(raw_ostream &OS) const;
void dump() const { print(dbgs()); }
#endif
};
/// Class responsible for emitting a DWARF v5 Accelerator Table. The only public
/// function is emit(), which performs the actual emission.
class Dwarf5AccelTableEmitter : public AccelTableEmitter {
struct Header {
uint32_t UnitLength = 0;
uint16_t Version = 5;
uint16_t Padding = 0;
uint32_t CompUnitCount;
uint32_t LocalTypeUnitCount = 0;
uint32_t ForeignTypeUnitCount = 0;
uint32_t BucketCount;
uint32_t NameCount;
uint32_t AbbrevTableSize = 0;
uint32_t AugmentationStringSize = sizeof(AugmentationString);
char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount)
: CompUnitCount(CompUnitCount), BucketCount(BucketCount),
NameCount(NameCount) {}
void emit(const Dwarf5AccelTableEmitter &Ctx) const;
};
struct AttributeEncoding {
dwarf::Index Index;
dwarf::Form Form;
};
Header Header;
DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations;
const DwarfDebug &DD;
ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits;
MCSymbol *ContributionStart = Asm->createTempSymbol("names_start");
MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end");
MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
DenseSet<uint32_t> getUniqueTags() const;
// Right now, we emit uniform attributes for all tags.
SmallVector<AttributeEncoding, 2> getUniformAttributes() const;
void emitCUList() const;
void emitBuckets() const;
void emitStringOffsets() const;
void emitAbbrevs() const;
void emitEntry(const DWARF5AccelTableData &Data) const;
void emitData() const;
public:
Dwarf5AccelTableEmitter(
AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD,
ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits);
void emit() const;
};
} // namespace
void AccelTableEmitter::emitHashes() const {
uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
unsigned BucketIdx = 0;
for (auto &Bucket : Contents.getBuckets()) {
for (auto &Hash : Bucket) {
uint32_t HashValue = Hash->HashValue;
if (SkipIdenticalHashes && PrevHash == HashValue)
continue;
Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
Asm->emitInt32(HashValue);
PrevHash = HashValue;
}
BucketIdx++;
}
}
void AccelTableEmitter::emitOffsets(const MCSymbol *Base) const {
const auto &Buckets = Contents.getBuckets();
uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
for (auto *Hash : Buckets[i]) {
uint32_t HashValue = Hash->HashValue;
if (SkipIdenticalHashes && PrevHash == HashValue)
continue;
PrevHash = HashValue;
Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
Asm->EmitLabelDifference(Hash->Sym, Base, sizeof(uint32_t));
}
}
}
void AppleAccelTableEmitter::Header::emit(AsmPrinter *Asm) const {
Asm->OutStreamer->AddComment("Header Magic");
Asm->emitInt32(Magic);
Asm->OutStreamer->AddComment("Header Version");
Asm->emitInt16(Version);
Asm->OutStreamer->AddComment("Header Hash Function");
Asm->emitInt16(HashFunction);
Asm->OutStreamer->AddComment("Header Bucket Count");
Asm->emitInt32(BucketCount);
Asm->OutStreamer->AddComment("Header Hash Count");
Asm->emitInt32(HashCount);
Asm->OutStreamer->AddComment("Header Data Length");
Asm->emitInt32(HeaderDataLength);
}
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
void AppleAccelTableEmitter::HeaderData::emit(AsmPrinter *Asm) const {
Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
Asm->emitInt32(DieOffsetBase);
Asm->OutStreamer->AddComment("HeaderData Atom Count");
Asm->emitInt32(Atoms.size());
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
for (const Atom &A : Atoms) {
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
Asm->emitInt16(A.Type);
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
Asm->emitInt16(A.Form);
}
}
void AppleAccelTableEmitter::emitBuckets() const {
const auto &Buckets = Contents.getBuckets();
unsigned index = 0;
for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Asm->OutStreamer->AddComment("Bucket " + Twine(i));
if (!Buckets[i].empty())
Asm->emitInt32(index);
else
Asm->emitInt32(std::numeric_limits<uint32_t>::max());
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
// Buckets point in the list of hashes, not to the data. Do not increment
// the index multiple times in case of hash collisions.
uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
for (auto *HD : Buckets[i]) {
uint32_t HashValue = HD->HashValue;
if (PrevHash != HashValue)
++index;
PrevHash = HashValue;
}
}
}
void AppleAccelTableEmitter::emitData() const {
const auto &Buckets = Contents.getBuckets();
for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
for (auto &Hash : Buckets[i]) {
// Terminate the previous entry if there is no hash collision with the
// current one.
if (PrevHash != std::numeric_limits<uint64_t>::max() &&
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
PrevHash != Hash->HashValue)
Asm->emitInt32(0);
// Remember to emit the label for our offset.
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
Asm->OutStreamer->EmitLabel(Hash->Sym);
Asm->OutStreamer->AddComment(Hash->Name.getString());
Asm->emitDwarfStringOffset(Hash->Name);
Asm->OutStreamer->AddComment("Num DIEs");
Asm->emitInt32(Hash->Values.size());
for (const auto *V : Hash->Values)
static_cast<const AppleAccelTableData *>(V)->emit(Asm);
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
PrevHash = Hash->HashValue;
}
// Emit the final end marker for the bucket.
if (!Buckets[i].empty())
Asm->emitInt32(0);
}
}
void AppleAccelTableEmitter::emit() const {
Header.emit(Asm);
HeaderData.emit(Asm);
emitBuckets();
emitHashes();
emitOffsets(SecBegin);
emitData();
}
void Dwarf5AccelTableEmitter::Header::emit(
const Dwarf5AccelTableEmitter &Ctx) const {
assert(CompUnitCount > 0 && "Index must have at least one CU.");
AsmPrinter *Asm = Ctx.Asm;
Asm->OutStreamer->AddComment("Header: unit length");
Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart,
sizeof(uint32_t));
Asm->OutStreamer->EmitLabel(Ctx.ContributionStart);
Asm->OutStreamer->AddComment("Header: version");
Asm->emitInt16(Version);
Asm->OutStreamer->AddComment("Header: padding");
Asm->emitInt16(Padding);
Asm->OutStreamer->AddComment("Header: compilation unit count");
Asm->emitInt32(CompUnitCount);
Asm->OutStreamer->AddComment("Header: local type unit count");
Asm->emitInt32(LocalTypeUnitCount);
Asm->OutStreamer->AddComment("Header: foreign type unit count");
Asm->emitInt32(ForeignTypeUnitCount);
Asm->OutStreamer->AddComment("Header: bucket count");
Asm->emitInt32(BucketCount);
Asm->OutStreamer->AddComment("Header: name count");
Asm->emitInt32(NameCount);
Asm->OutStreamer->AddComment("Header: abbreviation table size");
Asm->EmitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
Asm->OutStreamer->AddComment("Header: augmentation string size");
assert(AugmentationStringSize % 4 == 0);
Asm->emitInt32(AugmentationStringSize);
Asm->OutStreamer->AddComment("Header: augmentation string");
Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize});
}
DenseSet<uint32_t> Dwarf5AccelTableEmitter::getUniqueTags() const {
DenseSet<uint32_t> UniqueTags;
for (auto &Bucket : Contents.getBuckets()) {
for (auto *Hash : Bucket) {
for (auto *Value : Hash->Values) {
const DIE &Die =
static_cast<const DWARF5AccelTableData *>(Value)->getDie();
UniqueTags.insert(Die.getTag());
}
}
}
return UniqueTags;
}
SmallVector<Dwarf5AccelTableEmitter::AttributeEncoding, 2>
Dwarf5AccelTableEmitter::getUniformAttributes() const {
SmallVector<AttributeEncoding, 2> UA;
if (CompUnits.size() > 1) {
size_t LargestCUIndex = CompUnits.size() - 1;
dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex);
UA.push_back({dwarf::DW_IDX_compile_unit, Form});
}
UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
return UA;
}
void Dwarf5AccelTableEmitter::emitCUList() const {
for (const auto &CU : enumerate(CompUnits)) {
assert(CU.index() == CU.value()->getUniqueID());
Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
const DwarfCompileUnit *MainCU =
DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
Asm->emitDwarfSymbolReference(MainCU->getLabelBegin());
}
}
void Dwarf5AccelTableEmitter::emitBuckets() const {
uint32_t Index = 1;
for (const auto &Bucket : enumerate(Contents.getBuckets())) {
Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
Index += Bucket.value().size();
}
}
void Dwarf5AccelTableEmitter::emitStringOffsets() const {
for (const auto &Bucket : enumerate(Contents.getBuckets())) {
for (auto *Hash : Bucket.value()) {
DwarfStringPoolEntryRef String = Hash->Name;
Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
": " + String.getString());
Asm->emitDwarfStringOffset(String);
}
}
}
void Dwarf5AccelTableEmitter::emitAbbrevs() const {
Asm->OutStreamer->EmitLabel(AbbrevStart);
for (const auto &Abbrev : Abbreviations) {
Asm->OutStreamer->AddComment("Abbrev code");
assert(Abbrev.first != 0);
Asm->EmitULEB128(Abbrev.first);
Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first));
Asm->EmitULEB128(Abbrev.first);
for (const auto &AttrEnc : Abbrev.second) {
Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
Asm->EmitULEB128(AttrEnc.Form,
dwarf::FormEncodingString(AttrEnc.Form).data());
}
Asm->EmitULEB128(0, "End of abbrev");
Asm->EmitULEB128(0, "End of abbrev");
}
Asm->EmitULEB128(0, "End of abbrev list");
Asm->OutStreamer->EmitLabel(AbbrevEnd);
}
void Dwarf5AccelTableEmitter::emitEntry(
const DWARF5AccelTableData &Entry) const {
auto AbbrevIt = Abbreviations.find(Entry.getDie().getTag());
assert(AbbrevIt != Abbreviations.end() &&
"Why wasn't this abbrev generated?");
Asm->EmitULEB128(AbbrevIt->first, "Abbreviation code");
for (const auto &AttrEnc : AbbrevIt->second) {
Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
switch (AttrEnc.Index) {
case dwarf::DW_IDX_compile_unit: {
const DIE *CUDie = Entry.getDie().getUnitDie();
DIEInteger ID(DD.lookupCU(CUDie)->getUniqueID());
ID.EmitValue(Asm, AttrEnc.Form);
break;
}
case dwarf::DW_IDX_die_offset:
assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
Asm->emitInt32(Entry.getDie().getOffset());
break;
default:
llvm_unreachable("Unexpected index attribute!");
}
}
}
void Dwarf5AccelTableEmitter::emitData() const {
Asm->OutStreamer->EmitLabel(EntryPool);
for (auto &Bucket : Contents.getBuckets()) {
for (auto *Hash : Bucket) {
// Remember to emit the label for our offset.
Asm->OutStreamer->EmitLabel(Hash->Sym);
for (const auto *Value : Hash->Values)
emitEntry(*static_cast<const DWARF5AccelTableData *>(Value));
Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
Asm->emitInt32(0);
}
}
}
Dwarf5AccelTableEmitter::Dwarf5AccelTableEmitter(
AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD,
ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits)
: AccelTableEmitter(Asm, Contents, false),
Header(CompUnits.size(), Contents.getBucketCount(),
Contents.getUniqueNameCount()),
DD(DD), CompUnits(CompUnits) {
DenseSet<uint32_t> UniqueTags = getUniqueTags();
SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes();
Abbreviations.reserve(UniqueTags.size());
for (uint32_t Tag : UniqueTags)
Abbreviations.try_emplace(Tag, UniformAttributes);
}
void Dwarf5AccelTableEmitter::emit() const {
Header.emit(*this);
emitCUList();
emitBuckets();
emitHashes();
emitStringOffsets();
emitOffsets(EntryPool);
emitAbbrevs();
emitData();
Asm->OutStreamer->EmitValueToAlignment(4, 0);
Asm->OutStreamer->EmitLabel(ContributionEnd);
}
void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
StringRef Prefix, const MCSymbol *SecBegin,
ArrayRef<AppleAccelTableData::Atom> Atoms) {
Contents.finalize(Asm, Prefix);
AppleAccelTableEmitter(Asm, Contents, Atoms, SecBegin).emit();
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
}
void llvm::emitDWARF5AccelTable(
AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents,
const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
Contents.finalize(Asm, "names");
Dwarf5AccelTableEmitter(Asm, Contents, DD, CUs).emit();
}
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
Asm->emitInt32(Die->getDebugSectionOffset());
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
}
[NFC] Refactor Apple Accelerator Tables This patch refactors the way data is stored in the accelerator table and makes them truly generic. There have been several attempts to do this in the past: - D8215 & D8216: Using a union and partial hardcoding. - D11805: Using inheritance. - D42246: Using a callback. In the end I didn't like either of them, because for some reason or another parts of it felt hacky or decreased runtime performance. I didn't want to completely rewrite them as I was hoping that we could reuse parts for the successor in the DWARF standard. However, it seems less and less likely that there will be a lot of opportunities for sharing code and/or an interface. Originally I choose to template the whole class, because it introduces no performance overhead compared to the original implementation. We ended up settling on a hybrid between a templated method and a virtual call to emit the data. The motivation is that we don't want to increase code size for a feature that should soon be superseded by the DWARFv5 accelerator tables. While the code will continue to be used for compatibility, it won't be on the hot path. Furthermore this does not regress performance compared to Apple's internal implementation that already uses virtual calls for this. A quick summary for why these changes are necessary: dsymutil likes to reuse the current implementation of the Apple accelerator tables. However, LLDB expects a slightly different interface than what is currently emitted. Additionally, in dsymutil we only have offsets and no actual DIEs. Although the patch suggests a lot of code has changed, this change is pretty straightforward: - We created an abstract class `AppleAccelTableData` to serve as an interface for the different data classes. - We created two implementations of this class, one for type tables and one for everything else. There will be a third one for dsymutil that takes just the offset. - We use the supplied class to deduct the atoms for the header which makes the structure of the table fully self contained, although not enforced by the interface as was the case for the fully templated approach. - We renamed the prefix from DWARF- to Apple- to make space for the future implementation of .debug_names. This change is NFC and relies on the existing tests. Differential revision: https://reviews.llvm.org/D42334 llvm-svn: 323653
2018-01-29 14:52:34 +00:00
void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
Asm->emitInt32(Die->getDebugSectionOffset());
Asm->emitInt16(Die->getTag());
Asm->emitInt8(0);
}
void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
Asm->emitInt32(Offset);
}
void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
Asm->emitInt32(Offset);
Asm->emitInt16(Tag);
Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
: 0);
Asm->emitInt32(QualifiedNameHash);
}
#ifndef _MSC_VER
// The lines below are rejected by older versions (TBD) of MSVC.
constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
#else
// FIXME: Erase this path once the minimum MSCV version has been bumped.
const SmallVector<AppleAccelTableData::Atom, 4>
AppleAccelTableOffsetData::Atoms = {
Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms =
{Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)};
const SmallVector<AppleAccelTableData::Atom, 4>
AppleAccelTableStaticOffsetData::Atoms = {
Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
const SmallVector<AppleAccelTableData::Atom, 4>
AppleAccelTableStaticTypeData::Atoms = {
Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)};
#endif
#ifndef NDEBUG
void AppleAccelTableEmitter::Header::print(raw_ostream &OS) const {
OS << "Magic: " << format("0x%x", Magic) << "\n"
<< "Version: " << Version << "\n"
<< "Hash Function: " << HashFunction << "\n"
<< "Bucket Count: " << BucketCount << "\n"
<< "Header Data Length: " << HeaderDataLength << "\n";
}
void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
<< "Form: " << dwarf::FormEncodingString(Form) << "\n";
}
void AppleAccelTableEmitter::HeaderData::print(raw_ostream &OS) const {
OS << "DIE Offset Base: " << DieOffsetBase << "\n";
for (auto Atom : Atoms)
Atom.print(OS);
}
void AppleAccelTableEmitter::print(raw_ostream &OS) const {
Header.print(OS);
HeaderData.print(OS);
Contents.print(OS);
SecBegin->print(OS, nullptr);
}
void AccelTableBase::HashData::print(raw_ostream &OS) const {
OS << "Name: " << Name.getString() << "\n";
OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
OS << " Symbol: ";
if (Sym)
OS << *Sym;
else
OS << "<none>";
OS << "\n";
for (auto *Value : Values)
Value->print(OS);
}
void AccelTableBase::print(raw_ostream &OS) const {
// Print Content.
OS << "Entries: \n";
for (const auto &Entry : Entries) {
OS << "Name: " << Entry.first() << "\n";
for (auto *V : Entry.second.Values)
V->print(OS);
}
OS << "Buckets and Hashes: \n";
for (auto &Bucket : Buckets)
for (auto &Hash : Bucket)
Hash->print(OS);
OS << "Data: \n";
for (auto &E : Entries)
E.second.print(OS);
}
void DWARF5AccelTableData::print(raw_ostream &OS) const {
OS << " Offset: " << Die.getOffset() << "\n";
OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
}
void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
OS << " Offset: " << Die->getOffset() << "\n";
}
void AppleAccelTableTypeData::print(raw_ostream &OS) const {
OS << " Offset: " << Die->getOffset() << "\n";
OS << " Tag: " << dwarf::TagString(Die->getTag()) << "\n";
}
void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
OS << " Static Offset: " << Offset << "\n";
}
void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
OS << " Static Offset: " << Offset << "\n";
OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
OS << " Tag: " << dwarf::TagString(Tag) << "\n";
OS << " ObjCClassIsImplementation: "
<< (ObjCClassIsImplementation ? "true" : "false");
OS << "\n";
}
#endif