blob: 425c73671e12759f050ee1c61f9184b029d1bc74 [file] [log] [blame]
Jonas Devlieghere928fea22018-06-27 16:13:40 +00001//===- 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 Kyrtzidisf4bf8092018-09-03 16:22:05 +000010#ifndef LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H
11#define LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H
12
Jonas Devlieghere928fea22018-06-27 16:13:40 +000013#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 Devlieghere928fea22018-06-27 16:13:40 +000022namespace llvm {
23namespace dsymutil {
24
25struct 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.
31class CachedPathResolver {
32public:
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
53private:
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.
75class DeclContext {
76public:
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
101private:
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.
120class DeclContextTree {
121public:
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
140private:
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.
150struct 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