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