1a0698ed9Schristos #include <mutex> 2a0698ed9Schristos #include <new> 3a0698ed9Schristos 4a0698ed9Schristos #define JEMALLOC_CPP_CPP_ 5a0698ed9Schristos #ifdef __cplusplus 6a0698ed9Schristos extern "C" { 7a0698ed9Schristos #endif 8a0698ed9Schristos 9a0698ed9Schristos #include "jemalloc/internal/jemalloc_preamble.h" 10a0698ed9Schristos #include "jemalloc/internal/jemalloc_internal_includes.h" 11a0698ed9Schristos 12a0698ed9Schristos #ifdef __cplusplus 13a0698ed9Schristos } 14a0698ed9Schristos #endif 15a0698ed9Schristos 16a0698ed9Schristos // All operators in this file are exported. 17a0698ed9Schristos 18a0698ed9Schristos // Possibly alias hidden versions of malloc and sdallocx to avoid an extra plt 19a0698ed9Schristos // thunk? 20a0698ed9Schristos // 21a0698ed9Schristos // extern __typeof (sdallocx) sdallocx_int 22a0698ed9Schristos // __attribute ((alias ("sdallocx"), 23a0698ed9Schristos // visibility ("hidden"))); 24a0698ed9Schristos // 25a0698ed9Schristos // ... but it needs to work with jemalloc namespaces. 26a0698ed9Schristos 27a0698ed9Schristos void *operator new(std::size_t size); 28a0698ed9Schristos void *operator new[](std::size_t size); 29a0698ed9Schristos void *operator new(std::size_t size, const std::nothrow_t &) noexcept; 30a0698ed9Schristos void *operator new[](std::size_t size, const std::nothrow_t &) noexcept; 31a0698ed9Schristos void operator delete(void *ptr) noexcept; 32a0698ed9Schristos void operator delete[](void *ptr) noexcept; 33a0698ed9Schristos void operator delete(void *ptr, const std::nothrow_t &) noexcept; 34a0698ed9Schristos void operator delete[](void *ptr, const std::nothrow_t &) noexcept; 35a0698ed9Schristos 36a0698ed9Schristos #if __cpp_sized_deallocation >= 201309 37a0698ed9Schristos /* C++14's sized-delete operators. */ 38a0698ed9Schristos void operator delete(void *ptr, std::size_t size) noexcept; 39a0698ed9Schristos void operator delete[](void *ptr, std::size_t size) noexcept; 40a0698ed9Schristos #endif 41a0698ed9Schristos 42*7bdf38e5Schristos #if __cpp_aligned_new >= 201606 43*7bdf38e5Schristos /* C++17's over-aligned operators. */ 44*7bdf38e5Schristos void *operator new(std::size_t size, std::align_val_t); 45*7bdf38e5Schristos void *operator new(std::size_t size, std::align_val_t, const std::nothrow_t &) noexcept; 46*7bdf38e5Schristos void *operator new[](std::size_t size, std::align_val_t); 47*7bdf38e5Schristos void *operator new[](std::size_t size, std::align_val_t, const std::nothrow_t &) noexcept; 48*7bdf38e5Schristos void operator delete(void* ptr, std::align_val_t) noexcept; 49*7bdf38e5Schristos void operator delete(void* ptr, std::align_val_t, const std::nothrow_t &) noexcept; 50*7bdf38e5Schristos void operator delete(void* ptr, std::size_t size, std::align_val_t al) noexcept; 51*7bdf38e5Schristos void operator delete[](void* ptr, std::align_val_t) noexcept; 52*7bdf38e5Schristos void operator delete[](void* ptr, std::align_val_t, const std::nothrow_t &) noexcept; 53*7bdf38e5Schristos void operator delete[](void* ptr, std::size_t size, std::align_val_t al) noexcept; 54*7bdf38e5Schristos #endif 55*7bdf38e5Schristos 56a0698ed9Schristos JEMALLOC_NOINLINE 57a0698ed9Schristos static void * 58a0698ed9Schristos handleOOM(std::size_t size, bool nothrow) { 59*7bdf38e5Schristos if (opt_experimental_infallible_new) { 60*7bdf38e5Schristos safety_check_fail("<jemalloc>: Allocation failed and " 61*7bdf38e5Schristos "opt.experimental_infallible_new is true. Aborting.\n"); 62*7bdf38e5Schristos return nullptr; 63*7bdf38e5Schristos } 64*7bdf38e5Schristos 65a0698ed9Schristos void *ptr = nullptr; 66a0698ed9Schristos 67a0698ed9Schristos while (ptr == nullptr) { 68a0698ed9Schristos std::new_handler handler; 69a0698ed9Schristos // GCC-4.8 and clang 4.0 do not have std::get_new_handler. 70a0698ed9Schristos { 71a0698ed9Schristos static std::mutex mtx; 72a0698ed9Schristos std::lock_guard<std::mutex> lock(mtx); 73a0698ed9Schristos 74a0698ed9Schristos handler = std::set_new_handler(nullptr); 75a0698ed9Schristos std::set_new_handler(handler); 76a0698ed9Schristos } 77a0698ed9Schristos if (handler == nullptr) 78a0698ed9Schristos break; 79a0698ed9Schristos 80a0698ed9Schristos try { 81a0698ed9Schristos handler(); 82a0698ed9Schristos } catch (const std::bad_alloc &) { 83a0698ed9Schristos break; 84a0698ed9Schristos } 85a0698ed9Schristos 86a0698ed9Schristos ptr = je_malloc(size); 87a0698ed9Schristos } 88a0698ed9Schristos 89a0698ed9Schristos if (ptr == nullptr && !nothrow) 90a0698ed9Schristos std::__throw_bad_alloc(); 91a0698ed9Schristos return ptr; 92a0698ed9Schristos } 93a0698ed9Schristos 94a0698ed9Schristos template <bool IsNoExcept> 95*7bdf38e5Schristos JEMALLOC_NOINLINE 96*7bdf38e5Schristos static void * 97*7bdf38e5Schristos fallback_impl(std::size_t size) noexcept(IsNoExcept) { 98*7bdf38e5Schristos void *ptr = malloc_default(size); 99*7bdf38e5Schristos if (likely(ptr != nullptr)) { 100*7bdf38e5Schristos return ptr; 101*7bdf38e5Schristos } 102*7bdf38e5Schristos return handleOOM(size, IsNoExcept); 103*7bdf38e5Schristos } 104*7bdf38e5Schristos 105*7bdf38e5Schristos template <bool IsNoExcept> 106a0698ed9Schristos JEMALLOC_ALWAYS_INLINE 107a0698ed9Schristos void * 108a0698ed9Schristos newImpl(std::size_t size) noexcept(IsNoExcept) { 109*7bdf38e5Schristos return imalloc_fastpath(size, &fallback_impl<IsNoExcept>); 110a0698ed9Schristos } 111a0698ed9Schristos 112a0698ed9Schristos void * 113a0698ed9Schristos operator new(std::size_t size) { 114a0698ed9Schristos return newImpl<false>(size); 115a0698ed9Schristos } 116a0698ed9Schristos 117a0698ed9Schristos void * 118a0698ed9Schristos operator new[](std::size_t size) { 119a0698ed9Schristos return newImpl<false>(size); 120a0698ed9Schristos } 121a0698ed9Schristos 122a0698ed9Schristos void * 123a0698ed9Schristos operator new(std::size_t size, const std::nothrow_t &) noexcept { 124a0698ed9Schristos return newImpl<true>(size); 125a0698ed9Schristos } 126a0698ed9Schristos 127a0698ed9Schristos void * 128a0698ed9Schristos operator new[](std::size_t size, const std::nothrow_t &) noexcept { 129a0698ed9Schristos return newImpl<true>(size); 130a0698ed9Schristos } 131a0698ed9Schristos 132*7bdf38e5Schristos #if __cpp_aligned_new >= 201606 133*7bdf38e5Schristos 134*7bdf38e5Schristos template <bool IsNoExcept> 135*7bdf38e5Schristos JEMALLOC_ALWAYS_INLINE 136*7bdf38e5Schristos void * 137*7bdf38e5Schristos alignedNewImpl(std::size_t size, std::align_val_t alignment) noexcept(IsNoExcept) { 138*7bdf38e5Schristos void *ptr = je_aligned_alloc(static_cast<std::size_t>(alignment), size); 139*7bdf38e5Schristos if (likely(ptr != nullptr)) { 140*7bdf38e5Schristos return ptr; 141*7bdf38e5Schristos } 142*7bdf38e5Schristos 143*7bdf38e5Schristos return handleOOM(size, IsNoExcept); 144*7bdf38e5Schristos } 145*7bdf38e5Schristos 146*7bdf38e5Schristos void * 147*7bdf38e5Schristos operator new(std::size_t size, std::align_val_t alignment) { 148*7bdf38e5Schristos return alignedNewImpl<false>(size, alignment); 149*7bdf38e5Schristos } 150*7bdf38e5Schristos 151*7bdf38e5Schristos void * 152*7bdf38e5Schristos operator new[](std::size_t size, std::align_val_t alignment) { 153*7bdf38e5Schristos return alignedNewImpl<false>(size, alignment); 154*7bdf38e5Schristos } 155*7bdf38e5Schristos 156*7bdf38e5Schristos void * 157*7bdf38e5Schristos operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t &) noexcept { 158*7bdf38e5Schristos return alignedNewImpl<true>(size, alignment); 159*7bdf38e5Schristos } 160*7bdf38e5Schristos 161*7bdf38e5Schristos void * 162*7bdf38e5Schristos operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t &) noexcept { 163*7bdf38e5Schristos return alignedNewImpl<true>(size, alignment); 164*7bdf38e5Schristos } 165*7bdf38e5Schristos 166*7bdf38e5Schristos #endif // __cpp_aligned_new 167*7bdf38e5Schristos 168a0698ed9Schristos void 169a0698ed9Schristos operator delete(void *ptr) noexcept { 170a0698ed9Schristos je_free(ptr); 171a0698ed9Schristos } 172a0698ed9Schristos 173a0698ed9Schristos void 174a0698ed9Schristos operator delete[](void *ptr) noexcept { 175a0698ed9Schristos je_free(ptr); 176a0698ed9Schristos } 177a0698ed9Schristos 178a0698ed9Schristos void 179a0698ed9Schristos operator delete(void *ptr, const std::nothrow_t &) noexcept { 180a0698ed9Schristos je_free(ptr); 181a0698ed9Schristos } 182a0698ed9Schristos 183a0698ed9Schristos void operator delete[](void *ptr, const std::nothrow_t &) noexcept { 184a0698ed9Schristos je_free(ptr); 185a0698ed9Schristos } 186a0698ed9Schristos 187a0698ed9Schristos #if __cpp_sized_deallocation >= 201309 188a0698ed9Schristos 189*7bdf38e5Schristos JEMALLOC_ALWAYS_INLINE 190a0698ed9Schristos void 191*7bdf38e5Schristos sizedDeleteImpl(void* ptr, std::size_t size) noexcept { 192a0698ed9Schristos if (unlikely(ptr == nullptr)) { 193a0698ed9Schristos return; 194a0698ed9Schristos } 195*7bdf38e5Schristos je_sdallocx_noflags(ptr, size); 196a0698ed9Schristos } 197a0698ed9Schristos 198*7bdf38e5Schristos void 199*7bdf38e5Schristos operator delete(void *ptr, std::size_t size) noexcept { 200*7bdf38e5Schristos sizedDeleteImpl(ptr, size); 201a0698ed9Schristos } 202*7bdf38e5Schristos 203*7bdf38e5Schristos void 204*7bdf38e5Schristos operator delete[](void *ptr, std::size_t size) noexcept { 205*7bdf38e5Schristos sizedDeleteImpl(ptr, size); 206a0698ed9Schristos } 207a0698ed9Schristos 208a0698ed9Schristos #endif // __cpp_sized_deallocation 209*7bdf38e5Schristos 210*7bdf38e5Schristos #if __cpp_aligned_new >= 201606 211*7bdf38e5Schristos 212*7bdf38e5Schristos JEMALLOC_ALWAYS_INLINE 213*7bdf38e5Schristos void 214*7bdf38e5Schristos alignedSizedDeleteImpl(void* ptr, std::size_t size, std::align_val_t alignment) noexcept { 215*7bdf38e5Schristos if (config_debug) { 216*7bdf38e5Schristos assert(((size_t)alignment & ((size_t)alignment - 1)) == 0); 217*7bdf38e5Schristos } 218*7bdf38e5Schristos if (unlikely(ptr == nullptr)) { 219*7bdf38e5Schristos return; 220*7bdf38e5Schristos } 221*7bdf38e5Schristos je_sdallocx(ptr, size, MALLOCX_ALIGN(alignment)); 222*7bdf38e5Schristos } 223*7bdf38e5Schristos 224*7bdf38e5Schristos void 225*7bdf38e5Schristos operator delete(void* ptr, std::align_val_t) noexcept { 226*7bdf38e5Schristos je_free(ptr); 227*7bdf38e5Schristos } 228*7bdf38e5Schristos 229*7bdf38e5Schristos void 230*7bdf38e5Schristos operator delete[](void* ptr, std::align_val_t) noexcept { 231*7bdf38e5Schristos je_free(ptr); 232*7bdf38e5Schristos } 233*7bdf38e5Schristos 234*7bdf38e5Schristos void 235*7bdf38e5Schristos operator delete(void* ptr, std::align_val_t, const std::nothrow_t&) noexcept { 236*7bdf38e5Schristos je_free(ptr); 237*7bdf38e5Schristos } 238*7bdf38e5Schristos 239*7bdf38e5Schristos void 240*7bdf38e5Schristos operator delete[](void* ptr, std::align_val_t, const std::nothrow_t&) noexcept { 241*7bdf38e5Schristos je_free(ptr); 242*7bdf38e5Schristos } 243*7bdf38e5Schristos 244*7bdf38e5Schristos void 245*7bdf38e5Schristos operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept { 246*7bdf38e5Schristos alignedSizedDeleteImpl(ptr, size, alignment); 247*7bdf38e5Schristos } 248*7bdf38e5Schristos 249*7bdf38e5Schristos void 250*7bdf38e5Schristos operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept { 251*7bdf38e5Schristos alignedSizedDeleteImpl(ptr, size, alignment); 252*7bdf38e5Schristos } 253*7bdf38e5Schristos 254*7bdf38e5Schristos #endif // __cpp_aligned_new 255