mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-11-12 21:56:54 +00:00
784b900218
When we were previously removing allocators, we were only able to work with containers whose allocators appeared as their last template parameter. Now we can replace allocators in the middle of a parameter list. This fixes tests for folly::sorted_vector_set.
185 lines
4.6 KiB
C++
185 lines
4.6 KiB
C++
#define NDEBUG 1
|
|
// Required for compatibility with new glibc headers
|
|
#define __malloc__(x, y) __malloc__
|
|
#if !__has_builtin(__builtin_free)
|
|
#define __builtin_free(x) free(x)
|
|
#endif
|
|
#pragma clang diagnostic ignored "-Wunknown-attributes"
|
|
|
|
// clang-format off
|
|
// The header xmmintrin.h must come first. Otherwise it results in errors
|
|
// jemalloc during JIT compilation
|
|
#include <xmmintrin.h>
|
|
#include <cstdint>
|
|
|
|
#include <utility>
|
|
#include <unistd.h>
|
|
|
|
// clang-format on
|
|
|
|
#define C10_USING_CUSTOM_GENERATED_MACROS
|
|
|
|
// These globals are set by oid, see end of OIDebugger::compileCode()
|
|
extern uintptr_t dataBase;
|
|
extern size_t dataSize;
|
|
extern uintptr_t cookieValue;
|
|
extern int logFile;
|
|
|
|
constexpr int oidMagicId = 0x01DE8;
|
|
|
|
#include <array>
|
|
|
|
namespace {
|
|
|
|
class {
|
|
private:
|
|
// 1 MiB of pointers
|
|
std::array<uintptr_t, (1 << 20) / sizeof(uintptr_t)> data;
|
|
|
|
// twang_mix64 hash function, taken from Folly where it is used
|
|
// as the default hash function for 64-bit integers
|
|
constexpr static uint64_t twang_mix64(uint64_t key) noexcept {
|
|
key = (~key) + (key << 21); // key *= (1 << 21) - 1; key -= 1;
|
|
key = key ^ (key >> 24);
|
|
key = key + (key << 3) + (key << 8); // key *= 1 + (1 << 3) + (1 << 8)
|
|
key = key ^ (key >> 14);
|
|
key = key + (key << 2) + (key << 4); // key *= 1 + (1 << 2) + (1 << 4)
|
|
key = key ^ (key >> 28);
|
|
key = key + (key << 31); // key *= 1 + (1 << 31)
|
|
return key;
|
|
}
|
|
|
|
public:
|
|
void initialize() noexcept {
|
|
data.fill(0);
|
|
}
|
|
|
|
// Adds the pointer to the set.
|
|
// Returns `true` if the value was newly added,
|
|
// or `false` if the value was already present.
|
|
bool add(uintptr_t pointer) noexcept {
|
|
__builtin_assume(pointer > 0);
|
|
uint64_t index = twang_mix64(pointer) % data.size();
|
|
while (true) {
|
|
uintptr_t entry = data[index];
|
|
if (entry == 0) {
|
|
data[index] = pointer;
|
|
return true;
|
|
}
|
|
if (entry == pointer) {
|
|
return false;
|
|
}
|
|
index = (index + 1) % data.size();
|
|
}
|
|
}
|
|
} static pointers;
|
|
|
|
void __jlogptr(uintptr_t ptr) {
|
|
static constexpr char hexdigits[] = "0123456789abcdef";
|
|
static constexpr size_t ptrlen = 2 * sizeof(ptr);
|
|
|
|
static char hexstr[ptrlen + 1] = {};
|
|
|
|
size_t i = ptrlen;
|
|
while (i--) {
|
|
hexstr[i] = hexdigits[ptr & 0xf];
|
|
ptr = ptr >> 4;
|
|
}
|
|
hexstr[ptrlen] = '\n';
|
|
write(logFile, hexstr, sizeof(hexstr));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// Unforunately, this is a hack for AdFilterData.
|
|
class PredictorInterface;
|
|
class PredictionCompositionNode;
|
|
|
|
constexpr size_t kGEMMLOWPCacheLineSize = 64;
|
|
|
|
template <typename T>
|
|
struct AllocAligned {
|
|
// Allocate a T aligned at an `align` byte address
|
|
template <typename... Args>
|
|
static T* alloc(Args&&... args) {
|
|
void* p = nullptr;
|
|
|
|
#if defined(__ANDROID__)
|
|
p = memalign(kGEMMLOWPCacheLineSize, sizeof(T));
|
|
#elif defined(_MSC_VER)
|
|
p = _aligned_malloc(sizeof(T), kGEMMLOWPCacheLineSize);
|
|
#else
|
|
posix_memalign((void**)&p, kGEMMLOWPCacheLineSize, sizeof(T));
|
|
#endif
|
|
|
|
if (p) {
|
|
return new (p) T(std::forward<Args>(args)...);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Free a T previously allocated via AllocAligned<T>::alloc()
|
|
static void release(T* p) {
|
|
if (p) {
|
|
p->~T();
|
|
#if defined(_MSC_VER)
|
|
_aligned_free((void*)p);
|
|
#else
|
|
free((void*)p);
|
|
#endif
|
|
}
|
|
}
|
|
};
|
|
|
|
// Deleter object for unique_ptr for an aligned object
|
|
template <typename T>
|
|
struct AlignedDeleter {
|
|
void operator()(T* p) const {
|
|
AllocAligned<T>::release(p);
|
|
}
|
|
};
|
|
|
|
// alignas(0) is ignored according to docs so can be default
|
|
template <unsigned int N, unsigned int align = 0>
|
|
struct alignas(align) DummySizedOperator {
|
|
char c[N];
|
|
};
|
|
|
|
// The empty class specialization is, unfortunately, necessary. When this
|
|
// operator is passed as a template parameter to something like unordered_map,
|
|
// even though an empty class and a class with a single character have size one,
|
|
// there is some empty class optimization that changes the static size of the
|
|
// container if an empty class is passed.
|
|
|
|
// DummySizedOperator<0,0> also collapses to this
|
|
template <>
|
|
struct DummySizedOperator<0> {};
|
|
|
|
template <template <typename, size_t, size_t> typename DerivedT,
|
|
typename T,
|
|
size_t N,
|
|
size_t Align>
|
|
struct DummyAllocatorBase {
|
|
using value_type = T;
|
|
T* allocate(std::size_t n) {
|
|
return nullptr;
|
|
}
|
|
void deallocate(T* p, std::size_t n) noexcept {
|
|
}
|
|
|
|
template <typename U>
|
|
struct rebind {
|
|
using other = DerivedT<U, N, Align>;
|
|
};
|
|
};
|
|
|
|
template <typename T, size_t N, size_t Align = 0>
|
|
struct alignas(Align) DummyAllocator
|
|
: DummyAllocatorBase<DummyAllocator, T, N, Align> {
|
|
char c[N];
|
|
};
|
|
|
|
template <typename T>
|
|
struct DummyAllocator<T, 0> : DummyAllocatorBase<DummyAllocator, T, 0, 0> {};
|