184 lines
7.0 KiB
C
184 lines
7.0 KiB
C
|
//===- DWARFLinkerDeclContext.h ---------------------------------*- 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_DWARFLINKER_DWARFLINKERDECLCONTEXT_H
|
||
|
#define LLVM_DWARFLINKER_DWARFLINKERDECLCONTEXT_H
|
||
|
|
||
|
#include "llvm/ADT/DenseMap.h"
|
||
|
#include "llvm/ADT/DenseMapInfo.h"
|
||
|
#include "llvm/ADT/DenseSet.h"
|
||
|
#include "llvm/ADT/StringRef.h"
|
||
|
#include "llvm/CodeGen/NonRelocatableStringpool.h"
|
||
|
#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
|
||
|
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
||
|
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
||
|
#include "llvm/Support/FileSystem.h"
|
||
|
#include "llvm/Support/Path.h"
|
||
|
|
||
|
namespace llvm {
|
||
|
|
||
|
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(const std::string &Path,
|
||
|
NonRelocatableStringpool &StringPool) {
|
||
|
StringRef FileName = sys::path::filename(Path);
|
||
|
StringRef 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, std::string(RealPath.c_str(), RealPath.size())});
|
||
|
}
|
||
|
|
||
|
// 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; }
|
||
|
|
||
|
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,
|
||
|
bool InClangModule);
|
||
|
|
||
|
DeclContext &getRoot() { return Root; }
|
||
|
|
||
|
private:
|
||
|
BumpPtrAllocator Allocator;
|
||
|
DeclContext Root;
|
||
|
DeclContext::Map Contexts;
|
||
|
|
||
|
/// Cached resolved paths from the line table.
|
||
|
/// The key is <UniqueUnitID, FileIdx>.
|
||
|
using ResolvedPathsMap = DenseMap<std::pair<unsigned, unsigned>, StringRef>;
|
||
|
ResolvedPathsMap ResolvedPaths;
|
||
|
|
||
|
/// Helper that resolves and caches fragments of file paths.
|
||
|
CachedPathResolver PathResolver;
|
||
|
|
||
|
/// String pool keeping real path bodies.
|
||
|
NonRelocatableStringpool StringPool;
|
||
|
|
||
|
StringRef getResolvedPath(CompileUnit &CU, unsigned FileNum,
|
||
|
const DWARFDebugLine::LineTable &LineTable);
|
||
|
};
|
||
|
|
||
|
/// 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 llvm
|
||
|
|
||
|
#endif // LLVM_DWARFLINKER_DWARFLINKERDECLCONTEXT_H
|