xref: /netbsd-src/external/bsd/jemalloc.old/include/jemalloc/internal/arena_inlines_b.h (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
1*8e33eff8Schristos #ifndef JEMALLOC_INTERNAL_ARENA_INLINES_B_H
2*8e33eff8Schristos #define JEMALLOC_INTERNAL_ARENA_INLINES_B_H
3*8e33eff8Schristos 
4*8e33eff8Schristos #include "jemalloc/internal/jemalloc_internal_types.h"
5*8e33eff8Schristos #include "jemalloc/internal/mutex.h"
6*8e33eff8Schristos #include "jemalloc/internal/rtree.h"
7*8e33eff8Schristos #include "jemalloc/internal/size_classes.h"
8*8e33eff8Schristos #include "jemalloc/internal/sz.h"
9*8e33eff8Schristos #include "jemalloc/internal/ticker.h"
10*8e33eff8Schristos 
11*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE prof_tctx_t *
12*8e33eff8Schristos arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
13*8e33eff8Schristos 	cassert(config_prof);
14*8e33eff8Schristos 	assert(ptr != NULL);
15*8e33eff8Schristos 
16*8e33eff8Schristos 	/* Static check. */
17*8e33eff8Schristos 	if (alloc_ctx == NULL) {
18*8e33eff8Schristos 		const extent_t *extent = iealloc(tsdn, ptr);
19*8e33eff8Schristos 		if (unlikely(!extent_slab_get(extent))) {
20*8e33eff8Schristos 			return large_prof_tctx_get(tsdn, extent);
21*8e33eff8Schristos 		}
22*8e33eff8Schristos 	} else {
23*8e33eff8Schristos 		if (unlikely(!alloc_ctx->slab)) {
24*8e33eff8Schristos 			return large_prof_tctx_get(tsdn, iealloc(tsdn, ptr));
25*8e33eff8Schristos 		}
26*8e33eff8Schristos 	}
27*8e33eff8Schristos 	return (prof_tctx_t *)(uintptr_t)1U;
28*8e33eff8Schristos }
29*8e33eff8Schristos 
30*8e33eff8Schristos JEMALLOC_NORETURN JEMALLOC_ALWAYS_INLINE void
31*8e33eff8Schristos arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, UNUSED size_t usize,
32*8e33eff8Schristos     alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) {
33*8e33eff8Schristos 	cassert(config_prof);
34*8e33eff8Schristos 	assert(ptr != NULL);
35*8e33eff8Schristos 
36*8e33eff8Schristos 	/* Static check. */
37*8e33eff8Schristos 	if (alloc_ctx == NULL) {
38*8e33eff8Schristos 		extent_t *extent = iealloc(tsdn, ptr);
39*8e33eff8Schristos 		if (unlikely(!extent_slab_get(extent))) {
40*8e33eff8Schristos 			large_prof_tctx_set(tsdn, extent, tctx);
41*8e33eff8Schristos 		}
42*8e33eff8Schristos 	} else {
43*8e33eff8Schristos 		if (unlikely(!alloc_ctx->slab)) {
44*8e33eff8Schristos 			large_prof_tctx_set(tsdn, iealloc(tsdn, ptr), tctx);
45*8e33eff8Schristos 		}
46*8e33eff8Schristos 	}
47*8e33eff8Schristos }
48*8e33eff8Schristos 
49*8e33eff8Schristos static JEMALLOC_NORETURN inline void
50*8e33eff8Schristos arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, UNUSED prof_tctx_t *tctx) {
51*8e33eff8Schristos 	cassert(config_prof);
52*8e33eff8Schristos 	assert(ptr != NULL);
53*8e33eff8Schristos 
54*8e33eff8Schristos 	extent_t *extent = iealloc(tsdn, ptr);
55*8e33eff8Schristos 	assert(!extent_slab_get(extent));
56*8e33eff8Schristos 
57*8e33eff8Schristos 	large_prof_tctx_reset(tsdn, extent);
58*8e33eff8Schristos }
59*8e33eff8Schristos 
60*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void
61*8e33eff8Schristos arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) {
62*8e33eff8Schristos 	tsd_t *tsd;
63*8e33eff8Schristos 	ticker_t *decay_ticker;
64*8e33eff8Schristos 
65*8e33eff8Schristos 	if (unlikely(tsdn_null(tsdn))) {
66*8e33eff8Schristos 		return;
67*8e33eff8Schristos 	}
68*8e33eff8Schristos 	tsd = tsdn_tsd(tsdn);
69*8e33eff8Schristos 	decay_ticker = decay_ticker_get(tsd, arena_ind_get(arena));
70*8e33eff8Schristos 	if (unlikely(decay_ticker == NULL)) {
71*8e33eff8Schristos 		return;
72*8e33eff8Schristos 	}
73*8e33eff8Schristos 	if (unlikely(ticker_ticks(decay_ticker, nticks))) {
74*8e33eff8Schristos 		arena_decay(tsdn, arena, false, false);
75*8e33eff8Schristos 	}
76*8e33eff8Schristos }
77*8e33eff8Schristos 
78*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void
79*8e33eff8Schristos arena_decay_tick(tsdn_t *tsdn, arena_t *arena) {
80*8e33eff8Schristos 	malloc_mutex_assert_not_owner(tsdn, &arena->decay_dirty.mtx);
81*8e33eff8Schristos 	malloc_mutex_assert_not_owner(tsdn, &arena->decay_muzzy.mtx);
82*8e33eff8Schristos 
83*8e33eff8Schristos 	arena_decay_ticks(tsdn, arena, 1);
84*8e33eff8Schristos }
85*8e33eff8Schristos 
86*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void *
87*8e33eff8Schristos arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero,
88*8e33eff8Schristos     tcache_t *tcache, bool slow_path) {
89*8e33eff8Schristos 	assert(!tsdn_null(tsdn) || tcache == NULL);
90*8e33eff8Schristos 	assert(size != 0);
91*8e33eff8Schristos 
92*8e33eff8Schristos 	if (likely(tcache != NULL)) {
93*8e33eff8Schristos 		if (likely(size <= SMALL_MAXCLASS)) {
94*8e33eff8Schristos 			return tcache_alloc_small(tsdn_tsd(tsdn), arena,
95*8e33eff8Schristos 			    tcache, size, ind, zero, slow_path);
96*8e33eff8Schristos 		}
97*8e33eff8Schristos 		if (likely(size <= tcache_maxclass)) {
98*8e33eff8Schristos 			return tcache_alloc_large(tsdn_tsd(tsdn), arena,
99*8e33eff8Schristos 			    tcache, size, ind, zero, slow_path);
100*8e33eff8Schristos 		}
101*8e33eff8Schristos 		/* (size > tcache_maxclass) case falls through. */
102*8e33eff8Schristos 		assert(size > tcache_maxclass);
103*8e33eff8Schristos 	}
104*8e33eff8Schristos 
105*8e33eff8Schristos 	return arena_malloc_hard(tsdn, arena, size, ind, zero);
106*8e33eff8Schristos }
107*8e33eff8Schristos 
108*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE arena_t *
109*8e33eff8Schristos arena_aalloc(tsdn_t *tsdn, const void *ptr) {
110*8e33eff8Schristos 	return extent_arena_get(iealloc(tsdn, ptr));
111*8e33eff8Schristos }
112*8e33eff8Schristos 
113*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t
114*8e33eff8Schristos arena_salloc(tsdn_t *tsdn, const void *ptr) {
115*8e33eff8Schristos 	assert(ptr != NULL);
116*8e33eff8Schristos 
117*8e33eff8Schristos 	rtree_ctx_t rtree_ctx_fallback;
118*8e33eff8Schristos 	rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
119*8e33eff8Schristos 
120*8e33eff8Schristos 	szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx,
121*8e33eff8Schristos 	    (uintptr_t)ptr, true);
122*8e33eff8Schristos 	assert(szind != NSIZES);
123*8e33eff8Schristos 
124*8e33eff8Schristos 	return sz_index2size(szind);
125*8e33eff8Schristos }
126*8e33eff8Schristos 
127*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t
128*8e33eff8Schristos arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
129*8e33eff8Schristos 	/*
130*8e33eff8Schristos 	 * Return 0 if ptr is not within an extent managed by jemalloc.  This
131*8e33eff8Schristos 	 * function has two extra costs relative to isalloc():
132*8e33eff8Schristos 	 * - The rtree calls cannot claim to be dependent lookups, which induces
133*8e33eff8Schristos 	 *   rtree lookup load dependencies.
134*8e33eff8Schristos 	 * - The lookup may fail, so there is an extra branch to check for
135*8e33eff8Schristos 	 *   failure.
136*8e33eff8Schristos 	 */
137*8e33eff8Schristos 
138*8e33eff8Schristos 	rtree_ctx_t rtree_ctx_fallback;
139*8e33eff8Schristos 	rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
140*8e33eff8Schristos 
141*8e33eff8Schristos 	extent_t *extent;
142*8e33eff8Schristos 	szind_t szind;
143*8e33eff8Schristos 	if (rtree_extent_szind_read(tsdn, &extents_rtree, rtree_ctx,
144*8e33eff8Schristos 	    (uintptr_t)ptr, false, &extent, &szind)) {
145*8e33eff8Schristos 		return 0;
146*8e33eff8Schristos 	}
147*8e33eff8Schristos 
148*8e33eff8Schristos 	if (extent == NULL) {
149*8e33eff8Schristos 		return 0;
150*8e33eff8Schristos 	}
151*8e33eff8Schristos 	assert(extent_state_get(extent) == extent_state_active);
152*8e33eff8Schristos 	/* Only slab members should be looked up via interior pointers. */
153*8e33eff8Schristos 	assert(extent_addr_get(extent) == ptr || extent_slab_get(extent));
154*8e33eff8Schristos 
155*8e33eff8Schristos 	assert(szind != NSIZES);
156*8e33eff8Schristos 
157*8e33eff8Schristos 	return sz_index2size(szind);
158*8e33eff8Schristos }
159*8e33eff8Schristos 
160*8e33eff8Schristos static inline void
161*8e33eff8Schristos arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
162*8e33eff8Schristos 	assert(ptr != NULL);
163*8e33eff8Schristos 
164*8e33eff8Schristos 	rtree_ctx_t rtree_ctx_fallback;
165*8e33eff8Schristos 	rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
166*8e33eff8Schristos 
167*8e33eff8Schristos 	szind_t szind;
168*8e33eff8Schristos 	bool slab;
169*8e33eff8Schristos 	rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr,
170*8e33eff8Schristos 	    true, &szind, &slab);
171*8e33eff8Schristos 
172*8e33eff8Schristos 	if (config_debug) {
173*8e33eff8Schristos 		extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
174*8e33eff8Schristos 		    rtree_ctx, (uintptr_t)ptr, true);
175*8e33eff8Schristos 		assert(szind == extent_szind_get(extent));
176*8e33eff8Schristos 		assert(szind < NSIZES);
177*8e33eff8Schristos 		assert(slab == extent_slab_get(extent));
178*8e33eff8Schristos 	}
179*8e33eff8Schristos 
180*8e33eff8Schristos 	if (likely(slab)) {
181*8e33eff8Schristos 		/* Small allocation. */
182*8e33eff8Schristos 		arena_dalloc_small(tsdn, ptr);
183*8e33eff8Schristos 	} else {
184*8e33eff8Schristos 		extent_t *extent = iealloc(tsdn, ptr);
185*8e33eff8Schristos 		large_dalloc(tsdn, extent);
186*8e33eff8Schristos 	}
187*8e33eff8Schristos }
188*8e33eff8Schristos 
189*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void
190*8e33eff8Schristos arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
191*8e33eff8Schristos     alloc_ctx_t *alloc_ctx, bool slow_path) {
192*8e33eff8Schristos 	assert(!tsdn_null(tsdn) || tcache == NULL);
193*8e33eff8Schristos 	assert(ptr != NULL);
194*8e33eff8Schristos 
195*8e33eff8Schristos 	if (unlikely(tcache == NULL)) {
196*8e33eff8Schristos 		arena_dalloc_no_tcache(tsdn, ptr);
197*8e33eff8Schristos 		return;
198*8e33eff8Schristos 	}
199*8e33eff8Schristos 
200*8e33eff8Schristos 	szind_t szind;
201*8e33eff8Schristos 	bool slab;
202*8e33eff8Schristos 	rtree_ctx_t *rtree_ctx;
203*8e33eff8Schristos 	if (alloc_ctx != NULL) {
204*8e33eff8Schristos 		szind = alloc_ctx->szind;
205*8e33eff8Schristos 		slab = alloc_ctx->slab;
206*8e33eff8Schristos 		assert(szind != NSIZES);
207*8e33eff8Schristos 	} else {
208*8e33eff8Schristos 		rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
209*8e33eff8Schristos 		rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
210*8e33eff8Schristos 		    (uintptr_t)ptr, true, &szind, &slab);
211*8e33eff8Schristos 	}
212*8e33eff8Schristos 
213*8e33eff8Schristos 	if (config_debug) {
214*8e33eff8Schristos 		rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
215*8e33eff8Schristos 		extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
216*8e33eff8Schristos 		    rtree_ctx, (uintptr_t)ptr, true);
217*8e33eff8Schristos 		assert(szind == extent_szind_get(extent));
218*8e33eff8Schristos 		assert(szind < NSIZES);
219*8e33eff8Schristos 		assert(slab == extent_slab_get(extent));
220*8e33eff8Schristos 	}
221*8e33eff8Schristos 
222*8e33eff8Schristos 	if (likely(slab)) {
223*8e33eff8Schristos 		/* Small allocation. */
224*8e33eff8Schristos 		tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
225*8e33eff8Schristos 		    slow_path);
226*8e33eff8Schristos 	} else {
227*8e33eff8Schristos 		if (szind < nhbins) {
228*8e33eff8Schristos 			if (config_prof && unlikely(szind < NBINS)) {
229*8e33eff8Schristos 				arena_dalloc_promoted(tsdn, ptr, tcache,
230*8e33eff8Schristos 				    slow_path);
231*8e33eff8Schristos 			} else {
232*8e33eff8Schristos 				tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr,
233*8e33eff8Schristos 				    szind, slow_path);
234*8e33eff8Schristos 			}
235*8e33eff8Schristos 		} else {
236*8e33eff8Schristos 			extent_t *extent = iealloc(tsdn, ptr);
237*8e33eff8Schristos 			large_dalloc(tsdn, extent);
238*8e33eff8Schristos 		}
239*8e33eff8Schristos 	}
240*8e33eff8Schristos }
241*8e33eff8Schristos 
242*8e33eff8Schristos static inline void
243*8e33eff8Schristos arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
244*8e33eff8Schristos 	assert(ptr != NULL);
245*8e33eff8Schristos 	assert(size <= LARGE_MAXCLASS);
246*8e33eff8Schristos 
247*8e33eff8Schristos 	szind_t szind;
248*8e33eff8Schristos 	bool slab;
249*8e33eff8Schristos 	if (!config_prof || !opt_prof) {
250*8e33eff8Schristos 		/*
251*8e33eff8Schristos 		 * There is no risk of being confused by a promoted sampled
252*8e33eff8Schristos 		 * object, so base szind and slab on the given size.
253*8e33eff8Schristos 		 */
254*8e33eff8Schristos 		szind = sz_size2index(size);
255*8e33eff8Schristos 		slab = (szind < NBINS);
256*8e33eff8Schristos 	}
257*8e33eff8Schristos 
258*8e33eff8Schristos 	if ((config_prof && opt_prof) || config_debug) {
259*8e33eff8Schristos 		rtree_ctx_t rtree_ctx_fallback;
260*8e33eff8Schristos 		rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn,
261*8e33eff8Schristos 		    &rtree_ctx_fallback);
262*8e33eff8Schristos 
263*8e33eff8Schristos 		rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
264*8e33eff8Schristos 		    (uintptr_t)ptr, true, &szind, &slab);
265*8e33eff8Schristos 
266*8e33eff8Schristos 		assert(szind == sz_size2index(size));
267*8e33eff8Schristos 		assert((config_prof && opt_prof) || slab == (szind < NBINS));
268*8e33eff8Schristos 
269*8e33eff8Schristos 		if (config_debug) {
270*8e33eff8Schristos 			extent_t *extent = rtree_extent_read(tsdn,
271*8e33eff8Schristos 			    &extents_rtree, rtree_ctx, (uintptr_t)ptr, true);
272*8e33eff8Schristos 			assert(szind == extent_szind_get(extent));
273*8e33eff8Schristos 			assert(slab == extent_slab_get(extent));
274*8e33eff8Schristos 		}
275*8e33eff8Schristos 	}
276*8e33eff8Schristos 
277*8e33eff8Schristos 	if (likely(slab)) {
278*8e33eff8Schristos 		/* Small allocation. */
279*8e33eff8Schristos 		arena_dalloc_small(tsdn, ptr);
280*8e33eff8Schristos 	} else {
281*8e33eff8Schristos 		extent_t *extent = iealloc(tsdn, ptr);
282*8e33eff8Schristos 		large_dalloc(tsdn, extent);
283*8e33eff8Schristos 	}
284*8e33eff8Schristos }
285*8e33eff8Schristos 
286*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void
287*8e33eff8Schristos arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
288*8e33eff8Schristos     alloc_ctx_t *alloc_ctx, bool slow_path) {
289*8e33eff8Schristos 	assert(!tsdn_null(tsdn) || tcache == NULL);
290*8e33eff8Schristos 	assert(ptr != NULL);
291*8e33eff8Schristos 	assert(size <= LARGE_MAXCLASS);
292*8e33eff8Schristos 
293*8e33eff8Schristos 	if (unlikely(tcache == NULL)) {
294*8e33eff8Schristos 		arena_sdalloc_no_tcache(tsdn, ptr, size);
295*8e33eff8Schristos 		return;
296*8e33eff8Schristos 	}
297*8e33eff8Schristos 
298*8e33eff8Schristos 	szind_t szind;
299*8e33eff8Schristos 	bool slab;
300*8e33eff8Schristos 	UNUSED alloc_ctx_t local_ctx;
301*8e33eff8Schristos 	if (config_prof && opt_prof) {
302*8e33eff8Schristos 		if (alloc_ctx == NULL) {
303*8e33eff8Schristos 			/* Uncommon case and should be a static check. */
304*8e33eff8Schristos 			rtree_ctx_t rtree_ctx_fallback;
305*8e33eff8Schristos 			rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn,
306*8e33eff8Schristos 			    &rtree_ctx_fallback);
307*8e33eff8Schristos 			rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
308*8e33eff8Schristos 			    (uintptr_t)ptr, true, &local_ctx.szind,
309*8e33eff8Schristos 			    &local_ctx.slab);
310*8e33eff8Schristos 			assert(local_ctx.szind == sz_size2index(size));
311*8e33eff8Schristos 			alloc_ctx = &local_ctx;
312*8e33eff8Schristos 		}
313*8e33eff8Schristos 		slab = alloc_ctx->slab;
314*8e33eff8Schristos 		szind = alloc_ctx->szind;
315*8e33eff8Schristos 	} else {
316*8e33eff8Schristos 		/*
317*8e33eff8Schristos 		 * There is no risk of being confused by a promoted sampled
318*8e33eff8Schristos 		 * object, so base szind and slab on the given size.
319*8e33eff8Schristos 		 */
320*8e33eff8Schristos 		szind = sz_size2index(size);
321*8e33eff8Schristos 		slab = (szind < NBINS);
322*8e33eff8Schristos 	}
323*8e33eff8Schristos 
324*8e33eff8Schristos 	if (config_debug) {
325*8e33eff8Schristos 		rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
326*8e33eff8Schristos 		rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
327*8e33eff8Schristos 		    (uintptr_t)ptr, true, &szind, &slab);
328*8e33eff8Schristos 		extent_t *extent = rtree_extent_read(tsdn,
329*8e33eff8Schristos 		    &extents_rtree, rtree_ctx, (uintptr_t)ptr, true);
330*8e33eff8Schristos 		assert(szind == extent_szind_get(extent));
331*8e33eff8Schristos 		assert(slab == extent_slab_get(extent));
332*8e33eff8Schristos 	}
333*8e33eff8Schristos 
334*8e33eff8Schristos 	if (likely(slab)) {
335*8e33eff8Schristos 		/* Small allocation. */
336*8e33eff8Schristos 		tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
337*8e33eff8Schristos 		    slow_path);
338*8e33eff8Schristos 	} else {
339*8e33eff8Schristos 		if (szind < nhbins) {
340*8e33eff8Schristos 			if (config_prof && unlikely(szind < NBINS)) {
341*8e33eff8Schristos 				arena_dalloc_promoted(tsdn, ptr, tcache,
342*8e33eff8Schristos 				    slow_path);
343*8e33eff8Schristos 			} else {
344*8e33eff8Schristos 				tcache_dalloc_large(tsdn_tsd(tsdn),
345*8e33eff8Schristos 				    tcache, ptr, szind, slow_path);
346*8e33eff8Schristos 			}
347*8e33eff8Schristos 		} else {
348*8e33eff8Schristos 			extent_t *extent = iealloc(tsdn, ptr);
349*8e33eff8Schristos 			large_dalloc(tsdn, extent);
350*8e33eff8Schristos 		}
351*8e33eff8Schristos 	}
352*8e33eff8Schristos }
353*8e33eff8Schristos 
354*8e33eff8Schristos #endif /* JEMALLOC_INTERNAL_ARENA_INLINES_B_H */
355