2015-01-05 22:29:28 +01:00
|
|
|
//===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// 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
|
2015-01-05 22:29:28 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This program is a utility that aims to be a dropin replacement for
|
|
|
|
// Darwin's dsymutil.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
|
|
|
|
#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
|
|
|
|
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2020-03-11 23:30:04 +01:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2015-07-24 08:41:04 +02:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2015-01-05 22:29:28 +01:00
|
|
|
#include "llvm/Object/Archive.h"
|
|
|
|
#include "llvm/Object/Error.h"
|
2015-07-24 08:41:11 +02:00
|
|
|
#include "llvm/Object/MachOUniversal.h"
|
2015-01-05 22:29:28 +01:00
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2016-11-09 12:43:52 +01:00
|
|
|
#include "llvm/Support/Chrono.h"
|
2015-01-05 22:29:28 +01:00
|
|
|
#include "llvm/Support/Errc.h"
|
|
|
|
#include "llvm/Support/ErrorOr.h"
|
|
|
|
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
#include <mutex>
|
|
|
|
|
2015-01-05 22:29:28 +01:00
|
|
|
namespace llvm {
|
|
|
|
namespace dsymutil {
|
|
|
|
|
2018-06-29 18:51:52 +02:00
|
|
|
/// The BinaryHolder class is responsible for creating and owning
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
/// ObjectFiles and their underlying MemoryBuffers. It differs from a simple
|
|
|
|
/// OwningBinary in that it handles accessing and caching of archives and its
|
|
|
|
/// members.
|
2018-06-29 18:51:52 +02:00
|
|
|
class BinaryHolder {
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
public:
|
|
|
|
using TimestampTy = sys::TimePoint<std::chrono::seconds>;
|
|
|
|
|
2018-06-29 18:51:52 +02:00
|
|
|
BinaryHolder(bool Verbose = false) : Verbose(Verbose) {}
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
|
|
|
|
// Forward declarations for friend declaration.
|
|
|
|
class ObjectEntry;
|
|
|
|
class ArchiveEntry;
|
|
|
|
|
|
|
|
/// Base class shared by cached entries, representing objects and archives.
|
|
|
|
class EntryBase {
|
|
|
|
protected:
|
2018-06-29 19:11:34 +02:00
|
|
|
std::unique_ptr<MemoryBuffer> MemBuffer;
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
std::unique_ptr<object::MachOUniversalBinary> FatBinary;
|
|
|
|
std::string FatBinaryName;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Cached entry holding one or more (in case of a fat binary) object files.
|
|
|
|
class ObjectEntry : public EntryBase {
|
|
|
|
public:
|
|
|
|
/// Load the given object binary in memory.
|
|
|
|
Error load(StringRef Filename, bool Verbose = false);
|
|
|
|
|
|
|
|
/// Access all owned ObjectFiles.
|
|
|
|
std::vector<const object::ObjectFile *> getObjects() const;
|
|
|
|
|
|
|
|
/// Access to a derived version of all the currently owned ObjectFiles. The
|
|
|
|
/// conversion might be invalid, in which case an Error is returned.
|
|
|
|
template <typename ObjectFileType>
|
|
|
|
Expected<std::vector<const ObjectFileType *>> getObjectsAs() const {
|
2018-06-29 18:51:52 +02:00
|
|
|
std::vector<const ObjectFileType *> Result;
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
Result.reserve(Objects.size());
|
|
|
|
for (auto &Object : Objects) {
|
|
|
|
const auto *Derived = dyn_cast<ObjectFileType>(Object.get());
|
|
|
|
if (!Derived)
|
|
|
|
return errorCodeToError(object::object_error::invalid_file_type);
|
|
|
|
Result.push_back(Derived);
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Access the owned ObjectFile with architecture \p T.
|
|
|
|
Expected<const object::ObjectFile &> getObject(const Triple &T) const;
|
|
|
|
|
|
|
|
/// Access to a derived version of the currently owned ObjectFile with
|
|
|
|
/// architecture \p T. The conversion must be known to be valid.
|
|
|
|
template <typename ObjectFileType>
|
|
|
|
Expected<const ObjectFileType &> getObjectAs(const Triple &T) const {
|
|
|
|
auto Object = getObject(T);
|
|
|
|
if (!Object)
|
|
|
|
return Object.takeError();
|
|
|
|
return cast<ObjectFileType>(*Object);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<std::unique_ptr<object::ObjectFile>> Objects;
|
|
|
|
friend ArchiveEntry;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Cached entry holding one or more (in the of a fat binary) archive files.
|
|
|
|
class ArchiveEntry : public EntryBase {
|
|
|
|
public:
|
|
|
|
struct KeyTy {
|
|
|
|
std::string Filename;
|
|
|
|
TimestampTy Timestamp;
|
|
|
|
|
|
|
|
KeyTy() : Filename(), Timestamp() {}
|
|
|
|
KeyTy(StringRef Filename, TimestampTy Timestamp)
|
|
|
|
: Filename(Filename.str()), Timestamp(Timestamp) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Load the given object binary in memory.
|
|
|
|
Error load(StringRef Filename, TimestampTy Timestamp, bool Verbose = false);
|
|
|
|
|
|
|
|
Expected<const ObjectEntry &> getObjectEntry(StringRef Filename,
|
|
|
|
TimestampTy Timestamp,
|
|
|
|
bool Verbose = false);
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<std::unique_ptr<object::Archive>> Archives;
|
|
|
|
DenseMap<KeyTy, ObjectEntry> MemberCache;
|
|
|
|
std::mutex MemberCacheMutex;
|
|
|
|
};
|
|
|
|
|
2018-06-29 18:51:52 +02:00
|
|
|
Expected<const ObjectEntry &>
|
|
|
|
getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy());
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
|
|
|
|
void clear();
|
|
|
|
|
|
|
|
private:
|
|
|
|
/// Cache of static archives. Objects that are part of a static archive are
|
|
|
|
/// stored under this object, rather than in the map below.
|
|
|
|
StringMap<ArchiveEntry> ArchiveCache;
|
|
|
|
std::mutex ArchiveCacheMutex;
|
|
|
|
|
|
|
|
/// Object entries for objects that are not in a static archive.
|
|
|
|
StringMap<ObjectEntry> ObjectCache;
|
|
|
|
std::mutex ObjectCacheMutex;
|
|
|
|
|
|
|
|
bool Verbose;
|
|
|
|
};
|
|
|
|
|
2018-02-22 12:32:51 +01:00
|
|
|
} // namespace dsymutil
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
|
2018-06-29 18:51:52 +02:00
|
|
|
template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> {
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
|
2018-06-29 18:51:52 +02:00
|
|
|
static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() {
|
|
|
|
return dsymutil::BinaryHolder::ArchiveEntry::KeyTy();
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
}
|
|
|
|
|
2018-06-29 18:51:52 +02:00
|
|
|
static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() {
|
|
|
|
return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {});
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned
|
2018-06-29 18:51:52 +02:00
|
|
|
getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) {
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename),
|
|
|
|
DenseMapInfo<unsigned>::getHashValue(
|
|
|
|
K.Timestamp.time_since_epoch().count()));
|
|
|
|
}
|
|
|
|
|
2018-06-29 18:51:52 +02:00
|
|
|
static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS,
|
|
|
|
const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) {
|
[dsymutil] Introduce a new CachedBinaryHolder
The original binary holder has an optimization where it caches a static
library (archive) between consecutive calls to GetObjects. However, the
actual memory buffer wasn't cached between calls.
This made sense when dsymutil was processing objects one after each
other, but when processing them in parallel, several binaries have to be
in memory at the same time. For this reason, every link context
contained a binary holder.
Having one binary holder per context is problematic, because the same
static archive was cached for every object file. Luckily, when the file
is mmap'ed, this was only costing us virtual memory.
This patch introduces a new BinaryHolder variant that is fully cached,
for all the object files it load, as well as the static archives. This
way, we don't have to give up on this optimization of bypassing the
file system.
Differential revision: https://reviews.llvm.org/D48501
llvm-svn: 335990
2018-06-29 18:50:41 +02:00
|
|
|
return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-02-22 12:32:51 +01:00
|
|
|
} // namespace llvm
|
2015-01-05 22:29:28 +01:00
|
|
|
#endif
|