1*8e33eff8Schristos #ifndef JEMALLOC_INTERNAL_RTREE_H 2*8e33eff8Schristos #define JEMALLOC_INTERNAL_RTREE_H 3*8e33eff8Schristos 4*8e33eff8Schristos #include "jemalloc/internal/atomic.h" 5*8e33eff8Schristos #include "jemalloc/internal/mutex.h" 6*8e33eff8Schristos #include "jemalloc/internal/rtree_tsd.h" 7*8e33eff8Schristos #include "jemalloc/internal/size_classes.h" 8*8e33eff8Schristos #include "jemalloc/internal/tsd.h" 9*8e33eff8Schristos 10*8e33eff8Schristos /* 11*8e33eff8Schristos * This radix tree implementation is tailored to the singular purpose of 12*8e33eff8Schristos * associating metadata with extents that are currently owned by jemalloc. 13*8e33eff8Schristos * 14*8e33eff8Schristos ******************************************************************************* 15*8e33eff8Schristos */ 16*8e33eff8Schristos 17*8e33eff8Schristos /* Number of high insignificant bits. */ 18*8e33eff8Schristos #define RTREE_NHIB ((1U << (LG_SIZEOF_PTR+3)) - LG_VADDR) 19*8e33eff8Schristos /* Number of low insigificant bits. */ 20*8e33eff8Schristos #define RTREE_NLIB LG_PAGE 21*8e33eff8Schristos /* Number of significant bits. */ 22*8e33eff8Schristos #define RTREE_NSB (LG_VADDR - RTREE_NLIB) 23*8e33eff8Schristos /* Number of levels in radix tree. */ 24*8e33eff8Schristos #if RTREE_NSB <= 10 25*8e33eff8Schristos # define RTREE_HEIGHT 1 26*8e33eff8Schristos #elif RTREE_NSB <= 36 27*8e33eff8Schristos # define RTREE_HEIGHT 2 28*8e33eff8Schristos #elif RTREE_NSB <= 52 29*8e33eff8Schristos # define RTREE_HEIGHT 3 30*8e33eff8Schristos #else 31*8e33eff8Schristos # error Unsupported number of significant virtual address bits 32*8e33eff8Schristos #endif 33*8e33eff8Schristos /* Use compact leaf representation if virtual address encoding allows. */ 34*8e33eff8Schristos #if RTREE_NHIB >= LG_CEIL_NSIZES 35*8e33eff8Schristos # define RTREE_LEAF_COMPACT 36*8e33eff8Schristos #endif 37*8e33eff8Schristos 38*8e33eff8Schristos /* Needed for initialization only. */ 39*8e33eff8Schristos #define RTREE_LEAFKEY_INVALID ((uintptr_t)1) 40*8e33eff8Schristos 41*8e33eff8Schristos typedef struct rtree_node_elm_s rtree_node_elm_t; 42*8e33eff8Schristos struct rtree_node_elm_s { 43*8e33eff8Schristos atomic_p_t child; /* (rtree_{node,leaf}_elm_t *) */ 44*8e33eff8Schristos }; 45*8e33eff8Schristos 46*8e33eff8Schristos struct rtree_leaf_elm_s { 47*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 48*8e33eff8Schristos /* 49*8e33eff8Schristos * Single pointer-width field containing all three leaf element fields. 50*8e33eff8Schristos * For example, on a 64-bit x64 system with 48 significant virtual 51*8e33eff8Schristos * memory address bits, the index, extent, and slab fields are packed as 52*8e33eff8Schristos * such: 53*8e33eff8Schristos * 54*8e33eff8Schristos * x: index 55*8e33eff8Schristos * e: extent 56*8e33eff8Schristos * b: slab 57*8e33eff8Schristos * 58*8e33eff8Schristos * 00000000 xxxxxxxx eeeeeeee [...] eeeeeeee eeee000b 59*8e33eff8Schristos */ 60*8e33eff8Schristos atomic_p_t le_bits; 61*8e33eff8Schristos #else 62*8e33eff8Schristos atomic_p_t le_extent; /* (extent_t *) */ 63*8e33eff8Schristos atomic_u_t le_szind; /* (szind_t) */ 64*8e33eff8Schristos atomic_b_t le_slab; /* (bool) */ 65*8e33eff8Schristos #endif 66*8e33eff8Schristos }; 67*8e33eff8Schristos 68*8e33eff8Schristos typedef struct rtree_level_s rtree_level_t; 69*8e33eff8Schristos struct rtree_level_s { 70*8e33eff8Schristos /* Number of key bits distinguished by this level. */ 71*8e33eff8Schristos unsigned bits; 72*8e33eff8Schristos /* 73*8e33eff8Schristos * Cumulative number of key bits distinguished by traversing to 74*8e33eff8Schristos * corresponding tree level. 75*8e33eff8Schristos */ 76*8e33eff8Schristos unsigned cumbits; 77*8e33eff8Schristos }; 78*8e33eff8Schristos 79*8e33eff8Schristos typedef struct rtree_s rtree_t; 80*8e33eff8Schristos struct rtree_s { 81*8e33eff8Schristos malloc_mutex_t init_lock; 82*8e33eff8Schristos /* Number of elements based on rtree_levels[0].bits. */ 83*8e33eff8Schristos #if RTREE_HEIGHT > 1 84*8e33eff8Schristos rtree_node_elm_t root[1U << (RTREE_NSB/RTREE_HEIGHT)]; 85*8e33eff8Schristos #else 86*8e33eff8Schristos rtree_leaf_elm_t root[1U << (RTREE_NSB/RTREE_HEIGHT)]; 87*8e33eff8Schristos #endif 88*8e33eff8Schristos }; 89*8e33eff8Schristos 90*8e33eff8Schristos /* 91*8e33eff8Schristos * Split the bits into one to three partitions depending on number of 92*8e33eff8Schristos * significant bits. It the number of bits does not divide evenly into the 93*8e33eff8Schristos * number of levels, place one remainder bit per level starting at the leaf 94*8e33eff8Schristos * level. 95*8e33eff8Schristos */ 96*8e33eff8Schristos static const rtree_level_t rtree_levels[] = { 97*8e33eff8Schristos #if RTREE_HEIGHT == 1 98*8e33eff8Schristos {RTREE_NSB, RTREE_NHIB + RTREE_NSB} 99*8e33eff8Schristos #elif RTREE_HEIGHT == 2 100*8e33eff8Schristos {RTREE_NSB/2, RTREE_NHIB + RTREE_NSB/2}, 101*8e33eff8Schristos {RTREE_NSB/2 + RTREE_NSB%2, RTREE_NHIB + RTREE_NSB} 102*8e33eff8Schristos #elif RTREE_HEIGHT == 3 103*8e33eff8Schristos {RTREE_NSB/3, RTREE_NHIB + RTREE_NSB/3}, 104*8e33eff8Schristos {RTREE_NSB/3 + RTREE_NSB%3/2, 105*8e33eff8Schristos RTREE_NHIB + RTREE_NSB/3*2 + RTREE_NSB%3/2}, 106*8e33eff8Schristos {RTREE_NSB/3 + RTREE_NSB%3 - RTREE_NSB%3/2, RTREE_NHIB + RTREE_NSB} 107*8e33eff8Schristos #else 108*8e33eff8Schristos # error Unsupported rtree height 109*8e33eff8Schristos #endif 110*8e33eff8Schristos }; 111*8e33eff8Schristos 112*8e33eff8Schristos bool rtree_new(rtree_t *rtree, bool zeroed); 113*8e33eff8Schristos 114*8e33eff8Schristos typedef rtree_node_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); 115*8e33eff8Schristos extern rtree_node_alloc_t *JET_MUTABLE rtree_node_alloc; 116*8e33eff8Schristos 117*8e33eff8Schristos typedef rtree_leaf_elm_t *(rtree_leaf_alloc_t)(tsdn_t *, rtree_t *, size_t); 118*8e33eff8Schristos extern rtree_leaf_alloc_t *JET_MUTABLE rtree_leaf_alloc; 119*8e33eff8Schristos 120*8e33eff8Schristos typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_node_elm_t *); 121*8e33eff8Schristos extern rtree_node_dalloc_t *JET_MUTABLE rtree_node_dalloc; 122*8e33eff8Schristos 123*8e33eff8Schristos typedef void (rtree_leaf_dalloc_t)(tsdn_t *, rtree_t *, rtree_leaf_elm_t *); 124*8e33eff8Schristos extern rtree_leaf_dalloc_t *JET_MUTABLE rtree_leaf_dalloc; 125*8e33eff8Schristos #ifdef JEMALLOC_JET 126*8e33eff8Schristos void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); 127*8e33eff8Schristos #endif 128*8e33eff8Schristos rtree_leaf_elm_t *rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, 129*8e33eff8Schristos rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); 130*8e33eff8Schristos 131*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE uintptr_t 132*8e33eff8Schristos rtree_leafkey(uintptr_t key) { 133*8e33eff8Schristos unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); 134*8e33eff8Schristos unsigned cumbits = (rtree_levels[RTREE_HEIGHT-1].cumbits - 135*8e33eff8Schristos rtree_levels[RTREE_HEIGHT-1].bits); 136*8e33eff8Schristos unsigned maskbits = ptrbits - cumbits; 137*8e33eff8Schristos uintptr_t mask = ~((ZU(1) << maskbits) - 1); 138*8e33eff8Schristos return (key & mask); 139*8e33eff8Schristos } 140*8e33eff8Schristos 141*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t 142*8e33eff8Schristos rtree_cache_direct_map(uintptr_t key) { 143*8e33eff8Schristos unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); 144*8e33eff8Schristos unsigned cumbits = (rtree_levels[RTREE_HEIGHT-1].cumbits - 145*8e33eff8Schristos rtree_levels[RTREE_HEIGHT-1].bits); 146*8e33eff8Schristos unsigned maskbits = ptrbits - cumbits; 147*8e33eff8Schristos return (size_t)((key >> maskbits) & (RTREE_CTX_NCACHE - 1)); 148*8e33eff8Schristos } 149*8e33eff8Schristos 150*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE uintptr_t 151*8e33eff8Schristos rtree_subkey(uintptr_t key, unsigned level) { 152*8e33eff8Schristos unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); 153*8e33eff8Schristos unsigned cumbits = rtree_levels[level].cumbits; 154*8e33eff8Schristos unsigned shiftbits = ptrbits - cumbits; 155*8e33eff8Schristos unsigned maskbits = rtree_levels[level].bits; 156*8e33eff8Schristos uintptr_t mask = (ZU(1) << maskbits) - 1; 157*8e33eff8Schristos return ((key >> shiftbits) & mask); 158*8e33eff8Schristos } 159*8e33eff8Schristos 160*8e33eff8Schristos /* 161*8e33eff8Schristos * Atomic getters. 162*8e33eff8Schristos * 163*8e33eff8Schristos * dependent: Reading a value on behalf of a pointer to a valid allocation 164*8e33eff8Schristos * is guaranteed to be a clean read even without synchronization, 165*8e33eff8Schristos * because the rtree update became visible in memory before the 166*8e33eff8Schristos * pointer came into existence. 167*8e33eff8Schristos * !dependent: An arbitrary read, e.g. on behalf of ivsalloc(), may not be 168*8e33eff8Schristos * dependent on a previous rtree write, which means a stale read 169*8e33eff8Schristos * could result if synchronization were omitted here. 170*8e33eff8Schristos */ 171*8e33eff8Schristos # ifdef RTREE_LEAF_COMPACT 172*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE uintptr_t 173*8e33eff8Schristos rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, 174*8e33eff8Schristos bool dependent) { 175*8e33eff8Schristos return (uintptr_t)atomic_load_p(&elm->le_bits, dependent 176*8e33eff8Schristos ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); 177*8e33eff8Schristos } 178*8e33eff8Schristos 179*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE extent_t * 180*8e33eff8Schristos rtree_leaf_elm_bits_extent_get(uintptr_t bits) { 181*8e33eff8Schristos # ifdef __aarch64__ 182*8e33eff8Schristos /* 183*8e33eff8Schristos * aarch64 doesn't sign extend the highest virtual address bit to set 184*8e33eff8Schristos * the higher ones. Instead, the high bits gets zeroed. 185*8e33eff8Schristos */ 186*8e33eff8Schristos uintptr_t high_bit_mask = ((uintptr_t)1 << LG_VADDR) - 1; 187*8e33eff8Schristos /* Mask off the slab bit. */ 188*8e33eff8Schristos uintptr_t low_bit_mask = ~(uintptr_t)1; 189*8e33eff8Schristos uintptr_t mask = high_bit_mask & low_bit_mask; 190*8e33eff8Schristos return (extent_t *)(bits & mask); 191*8e33eff8Schristos # else 192*8e33eff8Schristos /* Restore sign-extended high bits, mask slab bit. */ 193*8e33eff8Schristos return (extent_t *)((uintptr_t)((intptr_t)(bits << RTREE_NHIB) >> 194*8e33eff8Schristos RTREE_NHIB) & ~((uintptr_t)0x1)); 195*8e33eff8Schristos # endif 196*8e33eff8Schristos } 197*8e33eff8Schristos 198*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE szind_t 199*8e33eff8Schristos rtree_leaf_elm_bits_szind_get(uintptr_t bits) { 200*8e33eff8Schristos return (szind_t)(bits >> LG_VADDR); 201*8e33eff8Schristos } 202*8e33eff8Schristos 203*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 204*8e33eff8Schristos rtree_leaf_elm_bits_slab_get(uintptr_t bits) { 205*8e33eff8Schristos return (bool)(bits & (uintptr_t)0x1); 206*8e33eff8Schristos } 207*8e33eff8Schristos 208*8e33eff8Schristos # endif 209*8e33eff8Schristos 210*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE extent_t * 211*8e33eff8Schristos rtree_leaf_elm_extent_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree, 212*8e33eff8Schristos rtree_leaf_elm_t *elm, bool dependent) { 213*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 214*8e33eff8Schristos uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent); 215*8e33eff8Schristos return rtree_leaf_elm_bits_extent_get(bits); 216*8e33eff8Schristos #else 217*8e33eff8Schristos extent_t *extent = (extent_t *)atomic_load_p(&elm->le_extent, dependent 218*8e33eff8Schristos ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); 219*8e33eff8Schristos return extent; 220*8e33eff8Schristos #endif 221*8e33eff8Schristos } 222*8e33eff8Schristos 223*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE szind_t 224*8e33eff8Schristos rtree_leaf_elm_szind_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree, 225*8e33eff8Schristos rtree_leaf_elm_t *elm, bool dependent) { 226*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 227*8e33eff8Schristos uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent); 228*8e33eff8Schristos return rtree_leaf_elm_bits_szind_get(bits); 229*8e33eff8Schristos #else 230*8e33eff8Schristos return (szind_t)atomic_load_u(&elm->le_szind, dependent ? ATOMIC_RELAXED 231*8e33eff8Schristos : ATOMIC_ACQUIRE); 232*8e33eff8Schristos #endif 233*8e33eff8Schristos } 234*8e33eff8Schristos 235*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 236*8e33eff8Schristos rtree_leaf_elm_slab_read(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree, 237*8e33eff8Schristos rtree_leaf_elm_t *elm, bool dependent) { 238*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 239*8e33eff8Schristos uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent); 240*8e33eff8Schristos return rtree_leaf_elm_bits_slab_get(bits); 241*8e33eff8Schristos #else 242*8e33eff8Schristos return atomic_load_b(&elm->le_slab, dependent ? ATOMIC_RELAXED : 243*8e33eff8Schristos ATOMIC_ACQUIRE); 244*8e33eff8Schristos #endif 245*8e33eff8Schristos } 246*8e33eff8Schristos 247*8e33eff8Schristos static inline void 248*8e33eff8Schristos rtree_leaf_elm_extent_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree, 249*8e33eff8Schristos rtree_leaf_elm_t *elm, extent_t *extent) { 250*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 251*8e33eff8Schristos uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, true); 252*8e33eff8Schristos uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) << 253*8e33eff8Schristos LG_VADDR) | ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) 254*8e33eff8Schristos | ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits)); 255*8e33eff8Schristos atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); 256*8e33eff8Schristos #else 257*8e33eff8Schristos atomic_store_p(&elm->le_extent, extent, ATOMIC_RELEASE); 258*8e33eff8Schristos #endif 259*8e33eff8Schristos } 260*8e33eff8Schristos 261*8e33eff8Schristos static inline void 262*8e33eff8Schristos rtree_leaf_elm_szind_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree, 263*8e33eff8Schristos rtree_leaf_elm_t *elm, szind_t szind) { 264*8e33eff8Schristos assert(szind <= NSIZES); 265*8e33eff8Schristos 266*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 267*8e33eff8Schristos uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, 268*8e33eff8Schristos true); 269*8e33eff8Schristos uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | 270*8e33eff8Schristos ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) & 271*8e33eff8Schristos (((uintptr_t)0x1 << LG_VADDR) - 1)) | 272*8e33eff8Schristos ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits)); 273*8e33eff8Schristos atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); 274*8e33eff8Schristos #else 275*8e33eff8Schristos atomic_store_u(&elm->le_szind, szind, ATOMIC_RELEASE); 276*8e33eff8Schristos #endif 277*8e33eff8Schristos } 278*8e33eff8Schristos 279*8e33eff8Schristos static inline void 280*8e33eff8Schristos rtree_leaf_elm_slab_write(UNUSED tsdn_t *tsdn, UNUSED rtree_t *rtree, 281*8e33eff8Schristos rtree_leaf_elm_t *elm, bool slab) { 282*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 283*8e33eff8Schristos uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, 284*8e33eff8Schristos true); 285*8e33eff8Schristos uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) << 286*8e33eff8Schristos LG_VADDR) | ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) & 287*8e33eff8Schristos (((uintptr_t)0x1 << LG_VADDR) - 1)) | ((uintptr_t)slab); 288*8e33eff8Schristos atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); 289*8e33eff8Schristos #else 290*8e33eff8Schristos atomic_store_b(&elm->le_slab, slab, ATOMIC_RELEASE); 291*8e33eff8Schristos #endif 292*8e33eff8Schristos } 293*8e33eff8Schristos 294*8e33eff8Schristos static inline void 295*8e33eff8Schristos rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, 296*8e33eff8Schristos extent_t *extent, szind_t szind, bool slab) { 297*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 298*8e33eff8Schristos uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | 299*8e33eff8Schristos ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) | 300*8e33eff8Schristos ((uintptr_t)slab); 301*8e33eff8Schristos atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); 302*8e33eff8Schristos #else 303*8e33eff8Schristos rtree_leaf_elm_slab_write(tsdn, rtree, elm, slab); 304*8e33eff8Schristos rtree_leaf_elm_szind_write(tsdn, rtree, elm, szind); 305*8e33eff8Schristos /* 306*8e33eff8Schristos * Write extent last, since the element is atomically considered valid 307*8e33eff8Schristos * as soon as the extent field is non-NULL. 308*8e33eff8Schristos */ 309*8e33eff8Schristos rtree_leaf_elm_extent_write(tsdn, rtree, elm, extent); 310*8e33eff8Schristos #endif 311*8e33eff8Schristos } 312*8e33eff8Schristos 313*8e33eff8Schristos static inline void 314*8e33eff8Schristos rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, 315*8e33eff8Schristos rtree_leaf_elm_t *elm, szind_t szind, bool slab) { 316*8e33eff8Schristos assert(!slab || szind < NBINS); 317*8e33eff8Schristos 318*8e33eff8Schristos /* 319*8e33eff8Schristos * The caller implicitly assures that it is the only writer to the szind 320*8e33eff8Schristos * and slab fields, and that the extent field cannot currently change. 321*8e33eff8Schristos */ 322*8e33eff8Schristos rtree_leaf_elm_slab_write(tsdn, rtree, elm, slab); 323*8e33eff8Schristos rtree_leaf_elm_szind_write(tsdn, rtree, elm, szind); 324*8e33eff8Schristos } 325*8e33eff8Schristos 326*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t * 327*8e33eff8Schristos rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, 328*8e33eff8Schristos uintptr_t key, bool dependent, bool init_missing) { 329*8e33eff8Schristos assert(key != 0); 330*8e33eff8Schristos assert(!dependent || !init_missing); 331*8e33eff8Schristos 332*8e33eff8Schristos size_t slot = rtree_cache_direct_map(key); 333*8e33eff8Schristos uintptr_t leafkey = rtree_leafkey(key); 334*8e33eff8Schristos assert(leafkey != RTREE_LEAFKEY_INVALID); 335*8e33eff8Schristos 336*8e33eff8Schristos /* Fast path: L1 direct mapped cache. */ 337*8e33eff8Schristos if (likely(rtree_ctx->cache[slot].leafkey == leafkey)) { 338*8e33eff8Schristos rtree_leaf_elm_t *leaf = rtree_ctx->cache[slot].leaf; 339*8e33eff8Schristos assert(leaf != NULL); 340*8e33eff8Schristos uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1); 341*8e33eff8Schristos return &leaf[subkey]; 342*8e33eff8Schristos } 343*8e33eff8Schristos /* 344*8e33eff8Schristos * Search the L2 LRU cache. On hit, swap the matching element into the 345*8e33eff8Schristos * slot in L1 cache, and move the position in L2 up by 1. 346*8e33eff8Schristos */ 347*8e33eff8Schristos #define RTREE_CACHE_CHECK_L2(i) do { \ 348*8e33eff8Schristos if (likely(rtree_ctx->l2_cache[i].leafkey == leafkey)) { \ 349*8e33eff8Schristos rtree_leaf_elm_t *leaf = rtree_ctx->l2_cache[i].leaf; \ 350*8e33eff8Schristos assert(leaf != NULL); \ 351*8e33eff8Schristos if (i > 0) { \ 352*8e33eff8Schristos /* Bubble up by one. */ \ 353*8e33eff8Schristos rtree_ctx->l2_cache[i].leafkey = \ 354*8e33eff8Schristos rtree_ctx->l2_cache[i - 1].leafkey; \ 355*8e33eff8Schristos rtree_ctx->l2_cache[i].leaf = \ 356*8e33eff8Schristos rtree_ctx->l2_cache[i - 1].leaf; \ 357*8e33eff8Schristos rtree_ctx->l2_cache[i - 1].leafkey = \ 358*8e33eff8Schristos rtree_ctx->cache[slot].leafkey; \ 359*8e33eff8Schristos rtree_ctx->l2_cache[i - 1].leaf = \ 360*8e33eff8Schristos rtree_ctx->cache[slot].leaf; \ 361*8e33eff8Schristos } else { \ 362*8e33eff8Schristos rtree_ctx->l2_cache[0].leafkey = \ 363*8e33eff8Schristos rtree_ctx->cache[slot].leafkey; \ 364*8e33eff8Schristos rtree_ctx->l2_cache[0].leaf = \ 365*8e33eff8Schristos rtree_ctx->cache[slot].leaf; \ 366*8e33eff8Schristos } \ 367*8e33eff8Schristos rtree_ctx->cache[slot].leafkey = leafkey; \ 368*8e33eff8Schristos rtree_ctx->cache[slot].leaf = leaf; \ 369*8e33eff8Schristos uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1); \ 370*8e33eff8Schristos return &leaf[subkey]; \ 371*8e33eff8Schristos } \ 372*8e33eff8Schristos } while (0) 373*8e33eff8Schristos /* Check the first cache entry. */ 374*8e33eff8Schristos RTREE_CACHE_CHECK_L2(0); 375*8e33eff8Schristos /* Search the remaining cache elements. */ 376*8e33eff8Schristos for (unsigned i = 1; i < RTREE_CTX_NCACHE_L2; i++) { 377*8e33eff8Schristos RTREE_CACHE_CHECK_L2(i); 378*8e33eff8Schristos } 379*8e33eff8Schristos #undef RTREE_CACHE_CHECK_L2 380*8e33eff8Schristos 381*8e33eff8Schristos return rtree_leaf_elm_lookup_hard(tsdn, rtree, rtree_ctx, key, 382*8e33eff8Schristos dependent, init_missing); 383*8e33eff8Schristos } 384*8e33eff8Schristos 385*8e33eff8Schristos static inline bool 386*8e33eff8Schristos rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, 387*8e33eff8Schristos extent_t *extent, szind_t szind, bool slab) { 388*8e33eff8Schristos /* Use rtree_clear() to set the extent to NULL. */ 389*8e33eff8Schristos assert(extent != NULL); 390*8e33eff8Schristos 391*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, 392*8e33eff8Schristos key, false, true); 393*8e33eff8Schristos if (elm == NULL) { 394*8e33eff8Schristos return true; 395*8e33eff8Schristos } 396*8e33eff8Schristos 397*8e33eff8Schristos assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false) == NULL); 398*8e33eff8Schristos rtree_leaf_elm_write(tsdn, rtree, elm, extent, szind, slab); 399*8e33eff8Schristos 400*8e33eff8Schristos return false; 401*8e33eff8Schristos } 402*8e33eff8Schristos 403*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t * 404*8e33eff8Schristos rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, 405*8e33eff8Schristos bool dependent) { 406*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, 407*8e33eff8Schristos key, dependent, false); 408*8e33eff8Schristos if (!dependent && elm == NULL) { 409*8e33eff8Schristos return NULL; 410*8e33eff8Schristos } 411*8e33eff8Schristos assert(elm != NULL); 412*8e33eff8Schristos return elm; 413*8e33eff8Schristos } 414*8e33eff8Schristos 415*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE extent_t * 416*8e33eff8Schristos rtree_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, 417*8e33eff8Schristos uintptr_t key, bool dependent) { 418*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, 419*8e33eff8Schristos dependent); 420*8e33eff8Schristos if (!dependent && elm == NULL) { 421*8e33eff8Schristos return NULL; 422*8e33eff8Schristos } 423*8e33eff8Schristos return rtree_leaf_elm_extent_read(tsdn, rtree, elm, dependent); 424*8e33eff8Schristos } 425*8e33eff8Schristos 426*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE szind_t 427*8e33eff8Schristos rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, 428*8e33eff8Schristos uintptr_t key, bool dependent) { 429*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, 430*8e33eff8Schristos dependent); 431*8e33eff8Schristos if (!dependent && elm == NULL) { 432*8e33eff8Schristos return NSIZES; 433*8e33eff8Schristos } 434*8e33eff8Schristos return rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent); 435*8e33eff8Schristos } 436*8e33eff8Schristos 437*8e33eff8Schristos /* 438*8e33eff8Schristos * rtree_slab_read() is intentionally omitted because slab is always read in 439*8e33eff8Schristos * conjunction with szind, which makes rtree_szind_slab_read() a better choice. 440*8e33eff8Schristos */ 441*8e33eff8Schristos 442*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 443*8e33eff8Schristos rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, 444*8e33eff8Schristos uintptr_t key, bool dependent, extent_t **r_extent, szind_t *r_szind) { 445*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, 446*8e33eff8Schristos dependent); 447*8e33eff8Schristos if (!dependent && elm == NULL) { 448*8e33eff8Schristos return true; 449*8e33eff8Schristos } 450*8e33eff8Schristos *r_extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, dependent); 451*8e33eff8Schristos *r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent); 452*8e33eff8Schristos return false; 453*8e33eff8Schristos } 454*8e33eff8Schristos 455*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 456*8e33eff8Schristos rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, 457*8e33eff8Schristos uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab) { 458*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, 459*8e33eff8Schristos dependent); 460*8e33eff8Schristos if (!dependent && elm == NULL) { 461*8e33eff8Schristos return true; 462*8e33eff8Schristos } 463*8e33eff8Schristos #ifdef RTREE_LEAF_COMPACT 464*8e33eff8Schristos uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent); 465*8e33eff8Schristos *r_szind = rtree_leaf_elm_bits_szind_get(bits); 466*8e33eff8Schristos *r_slab = rtree_leaf_elm_bits_slab_get(bits); 467*8e33eff8Schristos #else 468*8e33eff8Schristos *r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent); 469*8e33eff8Schristos *r_slab = rtree_leaf_elm_slab_read(tsdn, rtree, elm, dependent); 470*8e33eff8Schristos #endif 471*8e33eff8Schristos return false; 472*8e33eff8Schristos } 473*8e33eff8Schristos 474*8e33eff8Schristos static inline void 475*8e33eff8Schristos rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, 476*8e33eff8Schristos uintptr_t key, szind_t szind, bool slab) { 477*8e33eff8Schristos assert(!slab || szind < NBINS); 478*8e33eff8Schristos 479*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true); 480*8e33eff8Schristos rtree_leaf_elm_szind_slab_update(tsdn, rtree, elm, szind, slab); 481*8e33eff8Schristos } 482*8e33eff8Schristos 483*8e33eff8Schristos static inline void 484*8e33eff8Schristos rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, 485*8e33eff8Schristos uintptr_t key) { 486*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true); 487*8e33eff8Schristos assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false) != 488*8e33eff8Schristos NULL); 489*8e33eff8Schristos rtree_leaf_elm_write(tsdn, rtree, elm, NULL, NSIZES, false); 490*8e33eff8Schristos } 491*8e33eff8Schristos 492*8e33eff8Schristos #endif /* JEMALLOC_INTERNAL_RTREE_H */ 493