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 |