xref: /netbsd-src/external/bsd/jemalloc/dist/src/jemalloc_cpp.cpp (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
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