xref: /netbsd-src/external/bsd/jemalloc.old/include/jemalloc/internal/rtree.h (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
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