|
6 | 6 | //
|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 |
|
| 9 | +#include "llvm/ADT/Hashing.h" |
9 | 10 | #include "llvm/IR/DebugLoc.h"
|
10 | 11 | #include "llvm/Config/llvm-config.h"
|
11 | 12 | #include "llvm/IR/DebugInfo.h"
|
|
16 | 17 |
|
17 | 18 | using namespace llvm;
|
18 | 19 |
|
| 20 | +struct StacktraceOrList { |
| 21 | + union { |
| 22 | + std::array<void *, DbgLocOriginStacktrace::MaxDepth> Single; |
| 23 | + std::array<size_t, DbgLocOriginStacktrace::MaxDepth> STList; |
| 24 | + }; |
| 25 | + uint8_t Size : 7; |
| 26 | + uint8_t IsList : 1; |
| 27 | + StacktraceOrList(int Size, std::array<size_t, DbgLocOriginStacktrace::MaxDepth> STList) : STList(STList), Size(Size), IsList(0) {} |
| 28 | + StacktraceOrList(int Size, std::array<void *, DbgLocOriginStacktrace::MaxDepth> Single) : Single(Single), Size(Size), IsList(1) {} |
| 29 | + StacktraceOrList(bool Tombstone = false) : Size(Tombstone ? 0x7F : 0), IsList(Tombstone ? 1 : 0) { |
| 30 | + static_assert(DbgLocOriginStacktrace::MaxDepth < 0x7F, "Size of backtrace array must fit in 7 bits - 1"); |
| 31 | + } |
| 32 | +}; |
| 33 | + |
| 34 | +hash_code hash_value(const StacktraceOrList &S) { |
| 35 | + static_assert(DbgLocOriginStacktrace::MaxDepth < (1 << 7)); |
| 36 | + hash_code Result; |
| 37 | + if (S.IsList) { |
| 38 | + Result = hash_combine_range(S.Single.begin(), S.Single.begin() + S.Size); |
| 39 | + } else { |
| 40 | + Result = hash_combine_range(S.STList.begin(), S.STList.begin() + S.Size); |
| 41 | + } |
| 42 | + return Result; |
| 43 | +} |
| 44 | + |
| 45 | +template <> struct DenseMapInfo<StacktraceOrList> { |
| 46 | + static inline StacktraceOrList getEmptyKey() { |
| 47 | + return StacktraceOrList(); |
| 48 | + } |
| 49 | + |
| 50 | + static inline StacktraceOrList getTombstoneKey() { |
| 51 | + return StacktraceOrList(true); |
| 52 | + } |
| 53 | + |
| 54 | + static unsigned getHashValue(const StacktraceOrList &Val) { |
| 55 | + return hash_value(Val); |
| 56 | + } |
| 57 | + |
| 58 | + static bool isEqual(const StacktraceOrList &LHS, const StacktraceOrList &RHS) { |
| 59 | + if (LHS.IsList != RHS.IsList) |
| 60 | + return false; |
| 61 | + if (LHS.IsList) |
| 62 | + return ArrayRef(LHS.Single.begin(), LHS.Single.begin() + LHS.Size) == ArrayRef(RHS.Single.begin(), RHS.Single.begin() + RHS.Size); |
| 63 | + return ArrayRef(LHS.STList.begin(), LHS.STList.begin() + LHS.Size) == ArrayRef(RHS.STList.begin(), RHS.STList.begin() + RHS.Size); |
| 64 | + } |
| 65 | +}; |
| 66 | + |
| 67 | +// Storage for every unique stacktrace or list of stacktraces collected across this run of the program. |
| 68 | +static std::vector<StacktraceOrList> CollectedStacktraces(1, StacktraceOrList()); |
| 69 | +// Mapping from a unique stacktrace or list of stacktraces to an index in the CollectedStacktraces vector. |
| 70 | +static DenseMap<StacktraceOrList, size_t> StacktraceStorageMap; |
| 71 | + |
| 72 | +size_t getIndex(const StacktraceOrList &S) { |
| 73 | + // Special empty value that can't be inserted into the map. |
| 74 | + if (S.Size == 0) |
| 75 | + return 0; |
| 76 | + auto [It, R] = StacktraceStorageMap.insert({S, CollectedStacktraces.size()}); |
| 77 | + if (R) |
| 78 | + CollectedStacktraces.push_back(S); |
| 79 | + return It->second; |
| 80 | +} |
| 81 | +inline StacktraceOrList getStacktraceFromIndex(size_t Idx) { |
| 82 | + return CollectedStacktraces[Idx]; |
| 83 | +} |
| 84 | +// Given an index to an existing stored stacktrace, and a new |
| 85 | +size_t getIndexForAddedTrace(size_t Idx, StacktraceOrList S) { |
| 86 | + size_t AddedIdx = getIndex(S); |
| 87 | + if (Idx == 0) |
| 88 | + return AddedIdx; |
| 89 | + StacktraceOrList Current = getStacktraceFromIndex(Idx); |
| 90 | + StacktraceOrList New; |
| 91 | + if (Current.IsList) { |
| 92 | + std::array<size_t, DbgLocOriginStacktrace::MaxDepth> STList = {Idx, AddedIdx}; |
| 93 | + New = StacktraceOrList(2, STList); |
| 94 | + } else { |
| 95 | + // There is no way to represent a STList-backtrace containing more than MaxDepth |
| 96 | + // backtraces, so just leave it unappended. |
| 97 | + // FIXME: We could rotate it, so that we get the MaxDepth-most recent |
| 98 | + // backtraces rather than the oldest? |
| 99 | + if (Current.Size == DbgLocOriginStacktrace::MaxDepth) |
| 100 | + return Idx; |
| 101 | + New = StacktraceOrList(Current.Size + 1, Current.STList); |
| 102 | + New.STList[Current.Size] = AddedIdx; |
| 103 | + } |
| 104 | + return getIndex(S); |
| 105 | +} |
| 106 | + |
| 107 | + |
19 | 108 | DILocAndCoverageTracking::DILocAndCoverageTracking(const DILocation *L)
|
20 | 109 | : TrackingMDNodeRef(const_cast<DILocation *>(L)),
|
21 | 110 | Kind(DebugLocKind::Normal), Origin(!L) {}
|
22 | 111 |
|
23 |
| -DbgLocOriginBacktrace::DbgLocOriginBacktrace(bool ShouldCollectTrace) { |
24 |
| - if (ShouldCollectTrace) { |
25 |
| - auto &[Depth, Stacktrace] = Stacktraces.emplace_back(); |
26 |
| - Depth = sys::getStackTrace(Stacktrace); |
27 |
| - } |
| 112 | +DbgLocOriginStacktrace::DbgLocOriginStacktrace(bool ShouldCollectTrace) : StacktraceIdx(0) { |
| 113 | + if (!ShouldCollectTrace) |
| 114 | + return; |
| 115 | + std::array<void *, DbgLocOriginStacktrace::MaxDepth> Stacktrace; |
| 116 | + int Depth = sys::getStackTrace(Stacktrace); |
| 117 | + StacktraceIdx = getIndexForAddedTrace(StacktraceIdx, StacktraceOrList(Depth, Stacktrace)); |
28 | 118 | }
|
29 |
| -void DbgLocOriginBacktrace::addTrace() { |
30 |
| - if (Stacktraces.empty()) |
| 119 | +void DbgLocOriginStacktrace::addTrace() { |
| 120 | + if (StacktraceIdx == 0) |
31 | 121 | return;
|
32 |
| - auto &[Depth, Stacktrace] = Stacktraces.emplace_back(); |
33 |
| - Depth = sys::getStackTrace(Stacktrace); |
| 122 | + std::array<void *, DbgLocOriginStacktrace::MaxDepth> Stacktrace; |
| 123 | + int Depth = sys::getStackTrace(Stacktrace); |
| 124 | + StacktraceIdx = getIndex(StacktraceOrList(Depth, Stacktrace)); |
| 125 | +} |
| 126 | +SmallVector<std::pair<int, std::array<void *, DbgLocOriginStacktrace::MaxDepth>>, 0> DbgLocOriginStacktrace::getStacktraces() { |
| 127 | + SmallVector<std::pair<int, std::array<void *, DbgLocOriginStacktrace::MaxDepth>>, 0> Stacktraces; |
| 128 | + if (StacktraceIdx == 0) |
| 129 | + return Stacktraces; |
| 130 | + StacktraceOrList S = getStacktraceFromIndex(StacktraceIdx); |
| 131 | + if (S.IsList) { |
| 132 | + Stacktraces.push_back({(int)S.Size, S.Single}); |
| 133 | + } else { |
| 134 | + for (size_t SingleIdx : ArrayRef(S.STList.data(), S.Size)) { |
| 135 | + StacktraceOrList SingleS = getStacktraceFromIndex(SingleIdx); |
| 136 | + Stacktraces.push_back({(int)SingleS.Size, SingleS.Single}); |
| 137 | + } |
| 138 | + } |
| 139 | + return Stacktraces; |
34 | 140 | }
|
35 | 141 |
|
36 | 142 | DebugLoc DebugLoc::getTemporary() {
|
|
0 commit comments