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