Jonas Devlieghere | 928fea2 | 2018-06-27 16:13:40 +0000 | [diff] [blame] | 1 | //===- tools/dsymutil/DeclContext.h - Dwarf debug info linker ---*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
Argyrios Kyrtzidis | f4bf809 | 2018-09-03 16:22:05 +0000 | [diff] [blame] | 10 | #ifndef LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H |
| 11 | #define LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H |
| 12 | |
Jonas Devlieghere | 928fea2 | 2018-06-27 16:13:40 +0000 | [diff] [blame] | 13 | #include "CompileUnit.h" |
| 14 | #include "NonRelocatableStringpool.h" |
| 15 | #include "llvm/ADT/DenseMap.h" |
| 16 | #include "llvm/ADT/DenseMapInfo.h" |
| 17 | #include "llvm/ADT/DenseSet.h" |
| 18 | #include "llvm/ADT/StringRef.h" |
| 19 | #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
| 20 | #include "llvm/Support/Path.h" |
| 21 | |
Jonas Devlieghere | 928fea2 | 2018-06-27 16:13:40 +0000 | [diff] [blame] | 22 | namespace llvm { |
| 23 | namespace dsymutil { |
| 24 | |
| 25 | struct DeclMapInfo; |
| 26 | |
| 27 | /// Small helper that resolves and caches file paths. This helps reduce the |
| 28 | /// number of calls to realpath which is expensive. We assume the input are |
| 29 | /// files, and cache the realpath of their parent. This way we can quickly |
| 30 | /// resolve different files under the same path. |
| 31 | class CachedPathResolver { |
| 32 | public: |
| 33 | /// Resolve a path by calling realpath and cache its result. The returned |
| 34 | /// StringRef is interned in the given \p StringPool. |
| 35 | StringRef resolve(std::string Path, NonRelocatableStringpool &StringPool) { |
| 36 | StringRef FileName = sys::path::filename(Path); |
| 37 | SmallString<256> ParentPath = sys::path::parent_path(Path); |
| 38 | |
| 39 | // If the ParentPath has not yet been resolved, resolve and cache it for |
| 40 | // future look-ups. |
| 41 | if (!ResolvedPaths.count(ParentPath)) { |
| 42 | SmallString<256> RealPath; |
| 43 | sys::fs::real_path(ParentPath, RealPath); |
| 44 | ResolvedPaths.insert({ParentPath, StringRef(RealPath).str()}); |
| 45 | } |
| 46 | |
| 47 | // Join the file name again with the resolved path. |
| 48 | SmallString<256> ResolvedPath(ResolvedPaths[ParentPath]); |
| 49 | sys::path::append(ResolvedPath, FileName); |
| 50 | return StringPool.internString(ResolvedPath); |
| 51 | } |
| 52 | |
| 53 | private: |
| 54 | StringMap<std::string> ResolvedPaths; |
| 55 | }; |
| 56 | |
| 57 | /// A DeclContext is a named program scope that is used for ODR uniquing of |
| 58 | /// types. |
| 59 | /// |
| 60 | /// The set of DeclContext for the ODR-subject parts of a Dwarf link is |
| 61 | /// expanded (and uniqued) with each new object file processed. We need to |
| 62 | /// determine the context of each DIE in an linked object file to see if the |
| 63 | /// corresponding type has already been emitted. |
| 64 | /// |
| 65 | /// The contexts are conceptually organized as a tree (eg. a function scope is |
| 66 | /// contained in a namespace scope that contains other scopes), but |
| 67 | /// storing/accessing them in an actual tree is too inefficient: we need to be |
| 68 | /// able to very quickly query a context for a given child context by name. |
| 69 | /// Storing a StringMap in each DeclContext would be too space inefficient. |
| 70 | /// |
| 71 | /// The solution here is to give each DeclContext a link to its parent (this |
| 72 | /// allows to walk up the tree), but to query the existence of a specific |
| 73 | /// DeclContext using a separate DenseMap keyed on the hash of the fully |
| 74 | /// qualified name of the context. |
| 75 | class DeclContext { |
| 76 | public: |
| 77 | using Map = DenseSet<DeclContext *, DeclMapInfo>; |
| 78 | |
| 79 | DeclContext() : DefinedInClangModule(0), Parent(*this) {} |
| 80 | |
| 81 | DeclContext(unsigned Hash, uint32_t Line, uint32_t ByteSize, uint16_t Tag, |
| 82 | StringRef Name, StringRef File, const DeclContext &Parent, |
| 83 | DWARFDie LastSeenDIE = DWARFDie(), unsigned CUId = 0) |
| 84 | : QualifiedNameHash(Hash), Line(Line), ByteSize(ByteSize), Tag(Tag), |
| 85 | DefinedInClangModule(0), Name(Name), File(File), Parent(Parent), |
| 86 | LastSeenDIE(LastSeenDIE), LastSeenCompileUnitID(CUId) {} |
| 87 | |
| 88 | uint32_t getQualifiedNameHash() const { return QualifiedNameHash; } |
| 89 | |
| 90 | bool setLastSeenDIE(CompileUnit &U, const DWARFDie &Die); |
| 91 | |
| 92 | uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; } |
| 93 | void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset = Offset; } |
| 94 | |
| 95 | bool isDefinedInClangModule() const { return DefinedInClangModule; } |
| 96 | void setDefinedInClangModule(bool Val) { DefinedInClangModule = Val; } |
| 97 | |
| 98 | uint16_t getTag() const { return Tag; } |
| 99 | StringRef getName() const { return Name; } |
| 100 | |
| 101 | private: |
| 102 | friend DeclMapInfo; |
| 103 | |
| 104 | unsigned QualifiedNameHash = 0; |
| 105 | uint32_t Line = 0; |
| 106 | uint32_t ByteSize = 0; |
| 107 | uint16_t Tag = dwarf::DW_TAG_compile_unit; |
| 108 | unsigned DefinedInClangModule : 1; |
| 109 | StringRef Name; |
| 110 | StringRef File; |
| 111 | const DeclContext &Parent; |
| 112 | DWARFDie LastSeenDIE; |
| 113 | uint32_t LastSeenCompileUnitID = 0; |
| 114 | uint32_t CanonicalDIEOffset = 0; |
| 115 | }; |
| 116 | |
| 117 | /// This class gives a tree-like API to the DenseMap that stores the |
| 118 | /// DeclContext objects. It holds the BumpPtrAllocator where these objects will |
| 119 | /// be allocated. |
| 120 | class DeclContextTree { |
| 121 | public: |
| 122 | /// Get the child of \a Context described by \a DIE in \a Unit. The |
| 123 | /// required strings will be interned in \a StringPool. |
| 124 | /// \returns The child DeclContext along with one bit that is set if |
| 125 | /// this context is invalid. |
| 126 | /// |
| 127 | /// An invalid context means it shouldn't be considered for uniquing, but its |
| 128 | /// not returning null, because some children of that context might be |
| 129 | /// uniquing candidates. |
| 130 | /// |
| 131 | /// FIXME: The invalid bit along the return value is to emulate some |
| 132 | /// dsymutil-classic functionality. |
| 133 | PointerIntPair<DeclContext *, 1> |
| 134 | getChildDeclContext(DeclContext &Context, const DWARFDie &DIE, |
| 135 | CompileUnit &Unit, UniquingStringPool &StringPool, |
| 136 | bool InClangModule); |
| 137 | |
| 138 | DeclContext &getRoot() { return Root; } |
| 139 | |
| 140 | private: |
| 141 | BumpPtrAllocator Allocator; |
| 142 | DeclContext Root; |
| 143 | DeclContext::Map Contexts; |
| 144 | |
| 145 | /// Cache resolved paths from the line table. |
| 146 | CachedPathResolver PathResolver; |
| 147 | }; |
| 148 | |
| 149 | /// Info type for the DenseMap storing the DeclContext pointers. |
| 150 | struct DeclMapInfo : private DenseMapInfo<DeclContext *> { |
| 151 | using DenseMapInfo<DeclContext *>::getEmptyKey; |
| 152 | using DenseMapInfo<DeclContext *>::getTombstoneKey; |
| 153 | |
| 154 | static unsigned getHashValue(const DeclContext *Ctxt) { |
| 155 | return Ctxt->QualifiedNameHash; |
| 156 | } |
| 157 | |
| 158 | static bool isEqual(const DeclContext *LHS, const DeclContext *RHS) { |
| 159 | if (RHS == getEmptyKey() || RHS == getTombstoneKey()) |
| 160 | return RHS == LHS; |
| 161 | return LHS->QualifiedNameHash == RHS->QualifiedNameHash && |
| 162 | LHS->Line == RHS->Line && LHS->ByteSize == RHS->ByteSize && |
| 163 | LHS->Name.data() == RHS->Name.data() && |
| 164 | LHS->File.data() == RHS->File.data() && |
| 165 | LHS->Parent.QualifiedNameHash == RHS->Parent.QualifiedNameHash; |
| 166 | } |
| 167 | }; |
| 168 | |
| 169 | } // end namespace dsymutil |
| 170 | } // end namespace llvm |
| 171 | |
| 172 | #endif // LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H |