mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-04-15 07:01:42 +03:00
Support C++17 over-aligned allocation
Summary: Add support for C++17 over-aligned allocation: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r4.html Supporting all 10 operators means we avoid thunking thru libstdc++-v3/libsupc++ and just call jemalloc directly. It's also worth noting that there is now an aligned *and sized* operator delete: ``` void operator delete(void* ptr, std::size_t size, std::align_val_t al) noexcept; ``` If JeMalloc did not provide this, the default implementation would ignore the size parameter entirely: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/del_opsa.cc#L30-L33 (I must also update ax_cxx_compile_stdcxx.m4 to a newer version with C++17 support.) Test Plan: Wrote a simple test that allocates and then deletes an over-aligned type: ``` struct alignas(32) Foo {}; Foo *f; int main() { f = new Foo; delete f; } ``` Before this change, both new and delete go thru PLT, and we end up calling regular old free: ``` (gdb) disassemble Dump of assembler code for function main(): ... 0x00000000004029b7 <+55>: call 0x4022d0 <_ZnwmSt11align_val_t@plt> ... 0x00000000004029d5 <+85>: call 0x4022e0 <_ZdlPvmSt11align_val_t@plt> ... (gdb) s free (ptr=0x7ffff6408020) at /home/engshare/third-party2/jemalloc/master/src/jemalloc.git-trunk/src/jemalloc.c:2842 2842 if (!free_fastpath(ptr, 0, false)) { ``` After this change, we directly call new/delete and ultimately call sdallocx: ``` (gdb) disassemble Dump of assembler code for function main(): ... 0x0000000000402b77 <+55>: call 0x496ca0 <operator new(unsigned long, std::align_val_t)> ... 0x0000000000402b95 <+85>: call 0x496e60 <operator delete(void*, unsigned long, std::align_val_t)> ... (gdb) s 116 je_sdallocx_noflags(ptr, size); ```
This commit is contained in:
parent
9a3c738009
commit
8b2c2a596d
4 changed files with 536 additions and 42 deletions
|
|
@ -39,6 +39,20 @@ void operator delete(void *ptr, std::size_t size) noexcept;
|
|||
void operator delete[](void *ptr, std::size_t size) noexcept;
|
||||
#endif
|
||||
|
||||
#if __cpp_aligned_new >= 201606
|
||||
/* C++17's over-aligned operators. */
|
||||
void *operator new(std::size_t size, std::align_val_t);
|
||||
void *operator new(std::size_t size, std::align_val_t, const std::nothrow_t &) noexcept;
|
||||
void *operator new[](std::size_t size, std::align_val_t);
|
||||
void *operator new[](std::size_t size, std::align_val_t, const std::nothrow_t &) noexcept;
|
||||
void operator delete(void* ptr, std::align_val_t) noexcept;
|
||||
void operator delete(void* ptr, std::align_val_t, const std::nothrow_t &) noexcept;
|
||||
void operator delete(void* ptr, std::size_t size, std::align_val_t al) noexcept;
|
||||
void operator delete[](void* ptr, std::align_val_t) noexcept;
|
||||
void operator delete[](void* ptr, std::align_val_t, const std::nothrow_t &) noexcept;
|
||||
void operator delete[](void* ptr, std::size_t size, std::align_val_t al) noexcept;
|
||||
#endif
|
||||
|
||||
JEMALLOC_NOINLINE
|
||||
static void *
|
||||
handleOOM(std::size_t size, bool nothrow) {
|
||||
|
|
@ -76,12 +90,46 @@ JEMALLOC_ALWAYS_INLINE
|
|||
void *
|
||||
newImpl(std::size_t size) noexcept(IsNoExcept) {
|
||||
void *ptr = je_malloc(size);
|
||||
if (likely(ptr != nullptr))
|
||||
if (likely(ptr != nullptr)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return handleOOM(size, IsNoExcept);
|
||||
}
|
||||
|
||||
template <bool IsNoExcept>
|
||||
JEMALLOC_ALWAYS_INLINE
|
||||
void *
|
||||
alignedNewImpl(std::size_t size, std::align_val_t alignment) noexcept(IsNoExcept) {
|
||||
void *ptr = je_aligned_alloc(static_cast<std::size_t>(alignment), size);
|
||||
if (likely(ptr != nullptr)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return handleOOM(size, IsNoExcept);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE
|
||||
void
|
||||
sizedDeleteImpl(void* ptr, std::size_t size) noexcept {
|
||||
if (unlikely(ptr == nullptr)) {
|
||||
return;
|
||||
}
|
||||
je_sdallocx_noflags(ptr, size);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE
|
||||
void
|
||||
alignedSizedDeleteImpl(void* ptr, std::size_t size, std::align_val_t alignment) noexcept {
|
||||
if (config_debug) {
|
||||
assert(((size_t)alignment & ((size_t)alignment - 1)) == 0);
|
||||
}
|
||||
if (unlikely(ptr == nullptr)) {
|
||||
return;
|
||||
}
|
||||
je_sdallocx(ptr, size, MALLOCX_ALIGN(alignment));
|
||||
}
|
||||
|
||||
void *
|
||||
operator new(std::size_t size) {
|
||||
return newImpl<false>(size);
|
||||
|
|
@ -102,6 +150,30 @@ operator new[](std::size_t size, const std::nothrow_t &) noexcept {
|
|||
return newImpl<true>(size);
|
||||
}
|
||||
|
||||
#if __cpp_aligned_new >= 201606
|
||||
|
||||
void *
|
||||
operator new(std::size_t size, std::align_val_t alignment) {
|
||||
return alignedNewImpl<false>(size, alignment);
|
||||
}
|
||||
|
||||
void *
|
||||
operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t &) noexcept {
|
||||
return alignedNewImpl<true>(size, alignment);
|
||||
}
|
||||
|
||||
void *
|
||||
operator new[](std::size_t size, std::align_val_t alignment) {
|
||||
return alignedNewImpl<false>(size, alignment);
|
||||
}
|
||||
|
||||
void *
|
||||
operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t &) noexcept {
|
||||
return alignedNewImpl<true>(size, alignment);
|
||||
}
|
||||
|
||||
#endif // __cpp_aligned_new
|
||||
|
||||
void
|
||||
operator delete(void *ptr) noexcept {
|
||||
je_free(ptr);
|
||||
|
|
@ -125,17 +197,46 @@ void operator delete[](void *ptr, const std::nothrow_t &) noexcept {
|
|||
|
||||
void
|
||||
operator delete(void *ptr, std::size_t size) noexcept {
|
||||
if (unlikely(ptr == nullptr)) {
|
||||
return;
|
||||
}
|
||||
je_sdallocx_noflags(ptr, size);
|
||||
sizedDeleteImpl(ptr, size);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr, std::size_t size) noexcept {
|
||||
if (unlikely(ptr == nullptr)) {
|
||||
return;
|
||||
}
|
||||
je_sdallocx_noflags(ptr, size);
|
||||
void
|
||||
operator delete[](void *ptr, std::size_t size) noexcept {
|
||||
sizedDeleteImpl(ptr, size);
|
||||
}
|
||||
|
||||
#endif // __cpp_sized_deallocation
|
||||
|
||||
#if __cpp_aligned_new >= 201606
|
||||
|
||||
void
|
||||
operator delete(void* ptr, std::align_val_t) noexcept {
|
||||
je_free(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
operator delete(void* ptr, std::align_val_t, const std::nothrow_t&) noexcept {
|
||||
je_free(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
operator delete[](void* ptr, std::align_val_t) noexcept {
|
||||
je_free(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
operator delete[](void* ptr, std::align_val_t, const std::nothrow_t&) noexcept {
|
||||
je_free(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept {
|
||||
alignedSizedDeleteImpl(ptr, size, alignment);
|
||||
}
|
||||
|
||||
void
|
||||
operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept {
|
||||
alignedSizedDeleteImpl(ptr, size, alignment);
|
||||
}
|
||||
|
||||
#endif // __cpp_aligned_new
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue