reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
//===- tools/dsymutil/DeclContext.h - Dwarf debug info linker ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H
#define LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H

#include "CompileUnit.h"
#include "NonRelocatableStringpool.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/Support/Path.h"

namespace llvm {
namespace dsymutil {

struct DeclMapInfo;

/// Small helper that resolves and caches file paths. This helps reduce the
/// number of calls to realpath which is expensive. We assume the input are
/// files, and cache the realpath of their parent. This way we can quickly
/// resolve different files under the same path.
class CachedPathResolver {
public:
  /// Resolve a path by calling realpath and cache its result. The returned
  /// StringRef is interned in the given \p StringPool.
  StringRef resolve(std::string Path, NonRelocatableStringpool &StringPool) {
    StringRef FileName = sys::path::filename(Path);
    SmallString<256> ParentPath = sys::path::parent_path(Path);

    // If the ParentPath has not yet been resolved, resolve and cache it for
    // future look-ups.
    if (!ResolvedPaths.count(ParentPath)) {
      SmallString<256> RealPath;
      sys::fs::real_path(ParentPath, RealPath);
      ResolvedPaths.insert({ParentPath, StringRef(RealPath).str()});
    }

    // Join the file name again with the resolved path.
    SmallString<256> ResolvedPath(ResolvedPaths[ParentPath]);
    sys::path::append(ResolvedPath, FileName);
    return StringPool.internString(ResolvedPath);
  }

private:
  StringMap<std::string> ResolvedPaths;
};

/// A DeclContext is a named program scope that is used for ODR uniquing of
/// types.
///
/// The set of DeclContext for the ODR-subject parts of a Dwarf link is
/// expanded (and uniqued) with each new object file processed. We need to
/// determine the context of each DIE in an linked object file to see if the
/// corresponding type has already been emitted.
///
/// The contexts are conceptually organized as a tree (eg. a function scope is
/// contained in a namespace scope that contains other scopes), but
/// storing/accessing them in an actual tree is too inefficient: we need to be
/// able to very quickly query a context for a given child context by name.
/// Storing a StringMap in each DeclContext would be too space inefficient.
///
/// The solution here is to give each DeclContext a link to its parent (this
/// allows to walk up the tree), but to query the existence of a specific
/// DeclContext using a separate DenseMap keyed on the hash of the fully
/// qualified name of the context.
class DeclContext {
public:
  using Map = DenseSet<DeclContext *, DeclMapInfo>;

  DeclContext() : DefinedInClangModule(0), Parent(*this) {}

  DeclContext(unsigned Hash, uint32_t Line, uint32_t ByteSize, uint16_t Tag,
              StringRef Name, StringRef File, const DeclContext &Parent,
              DWARFDie LastSeenDIE = DWARFDie(), unsigned CUId = 0)
      : QualifiedNameHash(Hash), Line(Line), ByteSize(ByteSize), Tag(Tag),
        DefinedInClangModule(0), Name(Name), File(File), Parent(Parent),
        LastSeenDIE(LastSeenDIE), LastSeenCompileUnitID(CUId) {}

  uint32_t getQualifiedNameHash() const { return QualifiedNameHash; }

  bool setLastSeenDIE(CompileUnit &U, const DWARFDie &Die);

  uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; }
  void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset = Offset; }

  bool isDefinedInClangModule() const { return DefinedInClangModule; }
  void setDefinedInClangModule(bool Val) { DefinedInClangModule = Val; }

  uint16_t getTag() const { return Tag; }
  StringRef getName() const { return Name; }

private:
  friend DeclMapInfo;

  unsigned QualifiedNameHash = 0;
  uint32_t Line = 0;
  uint32_t ByteSize = 0;
  uint16_t Tag = dwarf::DW_TAG_compile_unit;
  unsigned DefinedInClangModule : 1;
  StringRef Name;
  StringRef File;
  const DeclContext &Parent;
  DWARFDie LastSeenDIE;
  uint32_t LastSeenCompileUnitID = 0;
  uint32_t CanonicalDIEOffset = 0;
};

/// This class gives a tree-like API to the DenseMap that stores the
/// DeclContext objects. It holds the BumpPtrAllocator where these objects will
/// be allocated.
class DeclContextTree {
public:
  /// Get the child of \a Context described by \a DIE in \a Unit. The
  /// required strings will be interned in \a StringPool.
  /// \returns The child DeclContext along with one bit that is set if
  /// this context is invalid.
  ///
  /// An invalid context means it shouldn't be considered for uniquing, but its
  /// not returning null, because some children of that context might be
  /// uniquing candidates.
  ///
  /// FIXME: The invalid bit along the return value is to emulate some
  /// dsymutil-classic functionality.
  PointerIntPair<DeclContext *, 1>
  getChildDeclContext(DeclContext &Context, const DWARFDie &DIE,
                      CompileUnit &Unit, UniquingStringPool &StringPool,
                      bool InClangModule);

  DeclContext &getRoot() { return Root; }

private:
  BumpPtrAllocator Allocator;
  DeclContext Root;
  DeclContext::Map Contexts;

  /// Cache resolved paths from the line table.
  CachedPathResolver PathResolver;
};

/// Info type for the DenseMap storing the DeclContext pointers.
struct DeclMapInfo : private DenseMapInfo<DeclContext *> {
  using DenseMapInfo<DeclContext *>::getEmptyKey;
  using DenseMapInfo<DeclContext *>::getTombstoneKey;

  static unsigned getHashValue(const DeclContext *Ctxt) {
    return Ctxt->QualifiedNameHash;
  }

  static bool isEqual(const DeclContext *LHS, const DeclContext *RHS) {
    if (RHS == getEmptyKey() || RHS == getTombstoneKey())
      return RHS == LHS;
    return LHS->QualifiedNameHash == RHS->QualifiedNameHash &&
           LHS->Line == RHS->Line && LHS->ByteSize == RHS->ByteSize &&
           LHS->Name.data() == RHS->Name.data() &&
           LHS->File.data() == RHS->File.data() &&
           LHS->Parent.QualifiedNameHash == RHS->Parent.QualifiedNameHash;
  }
};

} // end namespace dsymutil
} // end namespace llvm

#endif // LLVM_TOOLS_DSYMUTIL_DECLCONTEXT_H