DWARFLinkerDeclContext.h 7.3 KB

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