190 lines
5.5 KiB
C++
190 lines
5.5 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef mozjemalloc_h
|
|
#define mozjemalloc_h
|
|
|
|
#include <errno.h>
|
|
|
|
#include "mozjemalloc_types.h"
|
|
#include "malloc_decls.h"
|
|
#include "mozilla/MacroArgs.h"
|
|
|
|
// Macro helpers
|
|
|
|
#define MACRO_CALL(a, b) a b
|
|
// Can't use macros recursively, so we need another one doing the same as above.
|
|
#define MACRO_CALL2(a, b) a b
|
|
|
|
#define ARGS_HELPER(name, ...) \
|
|
MACRO_CALL2(MOZ_PASTE_PREFIX_AND_ARG_COUNT(name, ##__VA_ARGS__), \
|
|
(__VA_ARGS__))
|
|
#define TYPED_ARGS0()
|
|
#define TYPED_ARGS1(t1) t1 arg1
|
|
#define TYPED_ARGS2(t1, t2) TYPED_ARGS1(t1), t2 arg2
|
|
#define TYPED_ARGS3(t1, t2, t3) TYPED_ARGS2(t1, t2), t3 arg3
|
|
|
|
#define ARGS0()
|
|
#define ARGS1(t1) arg1
|
|
#define ARGS2(t1, t2) ARGS1(t1), arg2
|
|
#define ARGS3(t1, t2, t3) ARGS2(t1, t2), arg3
|
|
|
|
#ifdef MOZ_MEMORY
|
|
|
|
size_t GetKernelPageSize();
|
|
|
|
// Implement the set of alignment functions in terms of memalign.
|
|
template <void* (*memalign)(size_t, size_t)>
|
|
struct AlignedAllocator {
|
|
static inline int posix_memalign(void** aMemPtr, size_t aAlignment,
|
|
size_t aSize) {
|
|
void* result;
|
|
|
|
// alignment must be a power of two and a multiple of sizeof(void*)
|
|
if (((aAlignment - 1) & aAlignment) != 0 || aAlignment < sizeof(void*)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
// The 0-->1 size promotion is done in the memalign() call below
|
|
result = memalign(aAlignment, aSize);
|
|
|
|
if (!result) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
*aMemPtr = result;
|
|
return 0;
|
|
}
|
|
|
|
static inline void* aligned_alloc(size_t aAlignment, size_t aSize) {
|
|
if (aSize % aAlignment) {
|
|
return nullptr;
|
|
}
|
|
return memalign(aAlignment, aSize);
|
|
}
|
|
|
|
static inline void* valloc(size_t aSize) {
|
|
return memalign(GetKernelPageSize(), aSize);
|
|
}
|
|
};
|
|
|
|
// These classes each implement the same interface. Writing out the
|
|
// interface for each one rather than using inheritance makes things more
|
|
// explicit.
|
|
//
|
|
// Note: compilers are expected to be able to optimize out `this`.
|
|
|
|
// The MozJemalloc allocator
|
|
struct MozJemalloc {
|
|
# define MALLOC_DECL(name, return_type, ...) \
|
|
static inline return_type name(__VA_ARGS__);
|
|
# include "malloc_decls.h"
|
|
};
|
|
|
|
# ifdef MOZ_PHC
|
|
struct MozJemallocPHC : public MozJemalloc {
|
|
# define MALLOC_DECL(name, return_type, ...) \
|
|
static return_type name(__VA_ARGS__);
|
|
# define MALLOC_FUNCS MALLOC_FUNCS_MALLOC_BASE
|
|
# include "malloc_decls.h"
|
|
|
|
static inline int posix_memalign(void** aMemPtr, size_t aAlignment,
|
|
size_t aSize) {
|
|
return AlignedAllocator<memalign>::posix_memalign(aMemPtr, aAlignment,
|
|
aSize);
|
|
}
|
|
|
|
static inline void* aligned_alloc(size_t aAlignment, size_t aSize) {
|
|
return AlignedAllocator<memalign>::aligned_alloc(aAlignment, aSize);
|
|
}
|
|
|
|
static inline void* valloc(size_t aSize) {
|
|
return AlignedAllocator<memalign>::valloc(aSize);
|
|
}
|
|
|
|
static size_t malloc_usable_size(usable_ptr_t);
|
|
|
|
static void jemalloc_stats_internal(jemalloc_stats_t*, jemalloc_bin_stats_t*);
|
|
|
|
static void jemalloc_stats_lite(jemalloc_stats_lite_t*);
|
|
|
|
static void jemalloc_ptr_info(const void*, jemalloc_ptr_info_t*);
|
|
|
|
# define MALLOC_DECL(name, return_type, ...) \
|
|
static return_type name(__VA_ARGS__);
|
|
# define MALLOC_FUNCS MALLOC_FUNCS_ARENA_ALLOC
|
|
# include "malloc_decls.h"
|
|
};
|
|
# endif
|
|
|
|
# ifdef MOZ_REPLACE_MALLOC
|
|
// The replace-malloc allocator
|
|
struct ReplaceMalloc {
|
|
# define MALLOC_DECL(name, return_type, ...) \
|
|
static return_type name(__VA_ARGS__);
|
|
# include "malloc_decls.h"
|
|
};
|
|
# endif
|
|
|
|
# ifdef MOZ_PHC
|
|
using CanonicalMalloc = MozJemallocPHC;
|
|
# else
|
|
using CanonicalMalloc = MozJemalloc;
|
|
# endif
|
|
|
|
# ifdef MOZ_REPLACE_MALLOC
|
|
using DefaultMalloc = ReplaceMalloc;
|
|
# else
|
|
using DefaultMalloc = CanonicalMalloc;
|
|
# endif
|
|
|
|
// Poison - write "poison" to cells upon deallocation.
|
|
constexpr uint8_t kAllocPoison = 0xe5;
|
|
|
|
// Junk - write this junk value to freshly allocated cells.
|
|
constexpr uint8_t kAllocJunk = 0xe4;
|
|
|
|
// Maximum size of L1 cache line. This is used to avoid cache line aliasing,
|
|
// so over-estimates are okay (up to a point), but under-estimates will
|
|
// negatively affect performance.
|
|
constexpr size_t kCacheLineSize =
|
|
# if defined(XP_DARWIN) && defined(__aarch64__)
|
|
128
|
|
# else
|
|
64
|
|
# endif
|
|
;
|
|
|
|
#endif // MOZ_MEMORY
|
|
|
|
// Dummy implementation of the moz_arena_* API, falling back to a given
|
|
// implementation of the base allocator.
|
|
template <typename T>
|
|
struct DummyArenaAllocator {
|
|
static arena_id_t moz_create_arena_with_params(arena_params_t*) { return 0; }
|
|
|
|
static void moz_dispose_arena(arena_id_t) {}
|
|
|
|
static void moz_set_max_dirty_page_modifier(int32_t) {}
|
|
|
|
static bool moz_enable_deferred_purge(bool aEnable) { return false; }
|
|
|
|
static purge_result_t moz_may_purge_now(
|
|
bool aPeekOnly, uint32_t aReuseGraceMS,
|
|
const mozilla::Maybe<std::function<bool()>>& aKeepGoing) {
|
|
return purge_result_t::Done;
|
|
}
|
|
|
|
#define MALLOC_DECL(name, return_type, ...) \
|
|
static return_type moz_arena_##name( \
|
|
arena_id_t, ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) { \
|
|
return T::name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
|
|
}
|
|
#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC_BASE
|
|
#include "malloc_decls.h"
|
|
};
|
|
|
|
#endif
|