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