xref: /aosp_15_r20/external/jemalloc_new/src/rtree.c (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
1*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_RTREE_C_
2*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_preamble.h"
3*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_internal_includes.h"
4*1208bc7eSAndroid Build Coastguard Worker 
5*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/assert.h"
6*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/mutex.h"
7*1208bc7eSAndroid Build Coastguard Worker 
8*1208bc7eSAndroid Build Coastguard Worker /*
9*1208bc7eSAndroid Build Coastguard Worker  * Only the most significant bits of keys passed to rtree_{read,write}() are
10*1208bc7eSAndroid Build Coastguard Worker  * used.
11*1208bc7eSAndroid Build Coastguard Worker  */
12*1208bc7eSAndroid Build Coastguard Worker bool
rtree_new(rtree_t * rtree,bool zeroed)13*1208bc7eSAndroid Build Coastguard Worker rtree_new(rtree_t *rtree, bool zeroed) {
14*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_JET
15*1208bc7eSAndroid Build Coastguard Worker 	if (!zeroed) {
16*1208bc7eSAndroid Build Coastguard Worker 		memset(rtree, 0, sizeof(rtree_t)); /* Clear root. */
17*1208bc7eSAndroid Build Coastguard Worker 	}
18*1208bc7eSAndroid Build Coastguard Worker #else
19*1208bc7eSAndroid Build Coastguard Worker 	assert(zeroed);
20*1208bc7eSAndroid Build Coastguard Worker #endif
21*1208bc7eSAndroid Build Coastguard Worker 
22*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE,
23*1208bc7eSAndroid Build Coastguard Worker 	    malloc_mutex_rank_exclusive)) {
24*1208bc7eSAndroid Build Coastguard Worker 		return true;
25*1208bc7eSAndroid Build Coastguard Worker 	}
26*1208bc7eSAndroid Build Coastguard Worker 
27*1208bc7eSAndroid Build Coastguard Worker 	return false;
28*1208bc7eSAndroid Build Coastguard Worker }
29*1208bc7eSAndroid Build Coastguard Worker 
30*1208bc7eSAndroid Build Coastguard Worker static rtree_node_elm_t *
rtree_node_alloc_impl(tsdn_t * tsdn,rtree_t * rtree,size_t nelms)31*1208bc7eSAndroid Build Coastguard Worker rtree_node_alloc_impl(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) {
32*1208bc7eSAndroid Build Coastguard Worker 	return (rtree_node_elm_t *)base_alloc(tsdn, b0get(), nelms *
33*1208bc7eSAndroid Build Coastguard Worker 	    sizeof(rtree_node_elm_t), CACHELINE);
34*1208bc7eSAndroid Build Coastguard Worker }
35*1208bc7eSAndroid Build Coastguard Worker rtree_node_alloc_t *JET_MUTABLE rtree_node_alloc = rtree_node_alloc_impl;
36*1208bc7eSAndroid Build Coastguard Worker 
37*1208bc7eSAndroid Build Coastguard Worker static void
rtree_node_dalloc_impl(tsdn_t * tsdn,rtree_t * rtree,rtree_node_elm_t * node)38*1208bc7eSAndroid Build Coastguard Worker rtree_node_dalloc_impl(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *node) {
39*1208bc7eSAndroid Build Coastguard Worker 	/* Nodes are never deleted during normal operation. */
40*1208bc7eSAndroid Build Coastguard Worker 	not_reached();
41*1208bc7eSAndroid Build Coastguard Worker }
42*1208bc7eSAndroid Build Coastguard Worker UNUSED rtree_node_dalloc_t *JET_MUTABLE rtree_node_dalloc =
43*1208bc7eSAndroid Build Coastguard Worker     rtree_node_dalloc_impl;
44*1208bc7eSAndroid Build Coastguard Worker 
45*1208bc7eSAndroid Build Coastguard Worker static rtree_leaf_elm_t *
rtree_leaf_alloc_impl(tsdn_t * tsdn,rtree_t * rtree,size_t nelms)46*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_alloc_impl(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) {
47*1208bc7eSAndroid Build Coastguard Worker 	return (rtree_leaf_elm_t *)base_alloc(tsdn, b0get(), nelms *
48*1208bc7eSAndroid Build Coastguard Worker 	    sizeof(rtree_leaf_elm_t), CACHELINE);
49*1208bc7eSAndroid Build Coastguard Worker }
50*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_alloc_t *JET_MUTABLE rtree_leaf_alloc = rtree_leaf_alloc_impl;
51*1208bc7eSAndroid Build Coastguard Worker 
52*1208bc7eSAndroid Build Coastguard Worker static void
rtree_leaf_dalloc_impl(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * leaf)53*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_dalloc_impl(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *leaf) {
54*1208bc7eSAndroid Build Coastguard Worker 	/* Leaves are never deleted during normal operation. */
55*1208bc7eSAndroid Build Coastguard Worker 	not_reached();
56*1208bc7eSAndroid Build Coastguard Worker }
57*1208bc7eSAndroid Build Coastguard Worker UNUSED rtree_leaf_dalloc_t *JET_MUTABLE rtree_leaf_dalloc =
58*1208bc7eSAndroid Build Coastguard Worker     rtree_leaf_dalloc_impl;
59*1208bc7eSAndroid Build Coastguard Worker 
60*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_JET
61*1208bc7eSAndroid Build Coastguard Worker #  if RTREE_HEIGHT > 1
62*1208bc7eSAndroid Build Coastguard Worker static void
rtree_delete_subtree(tsdn_t * tsdn,rtree_t * rtree,rtree_node_elm_t * subtree,unsigned level)63*1208bc7eSAndroid Build Coastguard Worker rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *subtree,
64*1208bc7eSAndroid Build Coastguard Worker     unsigned level) {
65*1208bc7eSAndroid Build Coastguard Worker 	size_t nchildren = ZU(1) << rtree_levels[level].bits;
66*1208bc7eSAndroid Build Coastguard Worker 	if (level + 2 < RTREE_HEIGHT) {
67*1208bc7eSAndroid Build Coastguard Worker 		for (size_t i = 0; i < nchildren; i++) {
68*1208bc7eSAndroid Build Coastguard Worker 			rtree_node_elm_t *node =
69*1208bc7eSAndroid Build Coastguard Worker 			    (rtree_node_elm_t *)atomic_load_p(&subtree[i].child,
70*1208bc7eSAndroid Build Coastguard Worker 			    ATOMIC_RELAXED);
71*1208bc7eSAndroid Build Coastguard Worker 			if (node != NULL) {
72*1208bc7eSAndroid Build Coastguard Worker 				rtree_delete_subtree(tsdn, rtree, node, level +
73*1208bc7eSAndroid Build Coastguard Worker 				    1);
74*1208bc7eSAndroid Build Coastguard Worker 			}
75*1208bc7eSAndroid Build Coastguard Worker 		}
76*1208bc7eSAndroid Build Coastguard Worker 	} else {
77*1208bc7eSAndroid Build Coastguard Worker 		for (size_t i = 0; i < nchildren; i++) {
78*1208bc7eSAndroid Build Coastguard Worker 			rtree_leaf_elm_t *leaf =
79*1208bc7eSAndroid Build Coastguard Worker 			    (rtree_leaf_elm_t *)atomic_load_p(&subtree[i].child,
80*1208bc7eSAndroid Build Coastguard Worker 			    ATOMIC_RELAXED);
81*1208bc7eSAndroid Build Coastguard Worker 			if (leaf != NULL) {
82*1208bc7eSAndroid Build Coastguard Worker 				rtree_leaf_dalloc(tsdn, rtree, leaf);
83*1208bc7eSAndroid Build Coastguard Worker 			}
84*1208bc7eSAndroid Build Coastguard Worker 		}
85*1208bc7eSAndroid Build Coastguard Worker 	}
86*1208bc7eSAndroid Build Coastguard Worker 
87*1208bc7eSAndroid Build Coastguard Worker 	if (subtree != rtree->root) {
88*1208bc7eSAndroid Build Coastguard Worker 		rtree_node_dalloc(tsdn, rtree, subtree);
89*1208bc7eSAndroid Build Coastguard Worker 	}
90*1208bc7eSAndroid Build Coastguard Worker }
91*1208bc7eSAndroid Build Coastguard Worker #  endif
92*1208bc7eSAndroid Build Coastguard Worker 
93*1208bc7eSAndroid Build Coastguard Worker void
rtree_delete(tsdn_t * tsdn,rtree_t * rtree)94*1208bc7eSAndroid Build Coastguard Worker rtree_delete(tsdn_t *tsdn, rtree_t *rtree) {
95*1208bc7eSAndroid Build Coastguard Worker #  if RTREE_HEIGHT > 1
96*1208bc7eSAndroid Build Coastguard Worker 	rtree_delete_subtree(tsdn, rtree, rtree->root, 0);
97*1208bc7eSAndroid Build Coastguard Worker #  endif
98*1208bc7eSAndroid Build Coastguard Worker }
99*1208bc7eSAndroid Build Coastguard Worker #endif
100*1208bc7eSAndroid Build Coastguard Worker 
101*1208bc7eSAndroid Build Coastguard Worker static rtree_node_elm_t *
rtree_node_init(tsdn_t * tsdn,rtree_t * rtree,unsigned level,atomic_p_t * elmp)102*1208bc7eSAndroid Build Coastguard Worker rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level,
103*1208bc7eSAndroid Build Coastguard Worker     atomic_p_t *elmp) {
104*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_lock(tsdn, &rtree->init_lock);
105*1208bc7eSAndroid Build Coastguard Worker 	/*
106*1208bc7eSAndroid Build Coastguard Worker 	 * If *elmp is non-null, then it was initialized with the init lock
107*1208bc7eSAndroid Build Coastguard Worker 	 * held, so we can get by with 'relaxed' here.
108*1208bc7eSAndroid Build Coastguard Worker 	 */
109*1208bc7eSAndroid Build Coastguard Worker 	rtree_node_elm_t *node = atomic_load_p(elmp, ATOMIC_RELAXED);
110*1208bc7eSAndroid Build Coastguard Worker 	if (node == NULL) {
111*1208bc7eSAndroid Build Coastguard Worker 		node = rtree_node_alloc(tsdn, rtree, ZU(1) <<
112*1208bc7eSAndroid Build Coastguard Worker 		    rtree_levels[level].bits);
113*1208bc7eSAndroid Build Coastguard Worker 		if (node == NULL) {
114*1208bc7eSAndroid Build Coastguard Worker 			malloc_mutex_unlock(tsdn, &rtree->init_lock);
115*1208bc7eSAndroid Build Coastguard Worker 			return NULL;
116*1208bc7eSAndroid Build Coastguard Worker 		}
117*1208bc7eSAndroid Build Coastguard Worker 		/*
118*1208bc7eSAndroid Build Coastguard Worker 		 * Even though we hold the lock, a later reader might not; we
119*1208bc7eSAndroid Build Coastguard Worker 		 * need release semantics.
120*1208bc7eSAndroid Build Coastguard Worker 		 */
121*1208bc7eSAndroid Build Coastguard Worker 		atomic_store_p(elmp, node, ATOMIC_RELEASE);
122*1208bc7eSAndroid Build Coastguard Worker 	}
123*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_unlock(tsdn, &rtree->init_lock);
124*1208bc7eSAndroid Build Coastguard Worker 
125*1208bc7eSAndroid Build Coastguard Worker 	return node;
126*1208bc7eSAndroid Build Coastguard Worker }
127*1208bc7eSAndroid Build Coastguard Worker 
128*1208bc7eSAndroid Build Coastguard Worker static rtree_leaf_elm_t *
rtree_leaf_init(tsdn_t * tsdn,rtree_t * rtree,atomic_p_t * elmp)129*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_init(tsdn_t *tsdn, rtree_t *rtree, atomic_p_t *elmp) {
130*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_lock(tsdn, &rtree->init_lock);
131*1208bc7eSAndroid Build Coastguard Worker 	/*
132*1208bc7eSAndroid Build Coastguard Worker 	 * If *elmp is non-null, then it was initialized with the init lock
133*1208bc7eSAndroid Build Coastguard Worker 	 * held, so we can get by with 'relaxed' here.
134*1208bc7eSAndroid Build Coastguard Worker 	 */
135*1208bc7eSAndroid Build Coastguard Worker 	rtree_leaf_elm_t *leaf = atomic_load_p(elmp, ATOMIC_RELAXED);
136*1208bc7eSAndroid Build Coastguard Worker 	if (leaf == NULL) {
137*1208bc7eSAndroid Build Coastguard Worker 		leaf = rtree_leaf_alloc(tsdn, rtree, ZU(1) <<
138*1208bc7eSAndroid Build Coastguard Worker 		    rtree_levels[RTREE_HEIGHT-1].bits);
139*1208bc7eSAndroid Build Coastguard Worker 		if (leaf == NULL) {
140*1208bc7eSAndroid Build Coastguard Worker 			malloc_mutex_unlock(tsdn, &rtree->init_lock);
141*1208bc7eSAndroid Build Coastguard Worker 			return NULL;
142*1208bc7eSAndroid Build Coastguard Worker 		}
143*1208bc7eSAndroid Build Coastguard Worker 		/*
144*1208bc7eSAndroid Build Coastguard Worker 		 * Even though we hold the lock, a later reader might not; we
145*1208bc7eSAndroid Build Coastguard Worker 		 * need release semantics.
146*1208bc7eSAndroid Build Coastguard Worker 		 */
147*1208bc7eSAndroid Build Coastguard Worker 		atomic_store_p(elmp, leaf, ATOMIC_RELEASE);
148*1208bc7eSAndroid Build Coastguard Worker 	}
149*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_unlock(tsdn, &rtree->init_lock);
150*1208bc7eSAndroid Build Coastguard Worker 
151*1208bc7eSAndroid Build Coastguard Worker 	return leaf;
152*1208bc7eSAndroid Build Coastguard Worker }
153*1208bc7eSAndroid Build Coastguard Worker 
154*1208bc7eSAndroid Build Coastguard Worker static bool
rtree_node_valid(rtree_node_elm_t * node)155*1208bc7eSAndroid Build Coastguard Worker rtree_node_valid(rtree_node_elm_t *node) {
156*1208bc7eSAndroid Build Coastguard Worker 	return ((uintptr_t)node != (uintptr_t)0);
157*1208bc7eSAndroid Build Coastguard Worker }
158*1208bc7eSAndroid Build Coastguard Worker 
159*1208bc7eSAndroid Build Coastguard Worker static bool
rtree_leaf_valid(rtree_leaf_elm_t * leaf)160*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_valid(rtree_leaf_elm_t *leaf) {
161*1208bc7eSAndroid Build Coastguard Worker 	return ((uintptr_t)leaf != (uintptr_t)0);
162*1208bc7eSAndroid Build Coastguard Worker }
163*1208bc7eSAndroid Build Coastguard Worker 
164*1208bc7eSAndroid Build Coastguard Worker static rtree_node_elm_t *
rtree_child_node_tryread(rtree_node_elm_t * elm,bool dependent)165*1208bc7eSAndroid Build Coastguard Worker rtree_child_node_tryread(rtree_node_elm_t *elm, bool dependent) {
166*1208bc7eSAndroid Build Coastguard Worker 	rtree_node_elm_t *node;
167*1208bc7eSAndroid Build Coastguard Worker 
168*1208bc7eSAndroid Build Coastguard Worker 	if (dependent) {
169*1208bc7eSAndroid Build Coastguard Worker 		node = (rtree_node_elm_t *)atomic_load_p(&elm->child,
170*1208bc7eSAndroid Build Coastguard Worker 		    ATOMIC_RELAXED);
171*1208bc7eSAndroid Build Coastguard Worker 	} else {
172*1208bc7eSAndroid Build Coastguard Worker 		node = (rtree_node_elm_t *)atomic_load_p(&elm->child,
173*1208bc7eSAndroid Build Coastguard Worker 		    ATOMIC_ACQUIRE);
174*1208bc7eSAndroid Build Coastguard Worker 	}
175*1208bc7eSAndroid Build Coastguard Worker 
176*1208bc7eSAndroid Build Coastguard Worker 	assert(!dependent || node != NULL);
177*1208bc7eSAndroid Build Coastguard Worker 	return node;
178*1208bc7eSAndroid Build Coastguard Worker }
179*1208bc7eSAndroid Build Coastguard Worker 
180*1208bc7eSAndroid Build Coastguard Worker static rtree_node_elm_t *
rtree_child_node_read(tsdn_t * tsdn,rtree_t * rtree,rtree_node_elm_t * elm,unsigned level,bool dependent)181*1208bc7eSAndroid Build Coastguard Worker rtree_child_node_read(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *elm,
182*1208bc7eSAndroid Build Coastguard Worker     unsigned level, bool dependent) {
183*1208bc7eSAndroid Build Coastguard Worker 	rtree_node_elm_t *node;
184*1208bc7eSAndroid Build Coastguard Worker 
185*1208bc7eSAndroid Build Coastguard Worker 	node = rtree_child_node_tryread(elm, dependent);
186*1208bc7eSAndroid Build Coastguard Worker 	if (!dependent && unlikely(!rtree_node_valid(node))) {
187*1208bc7eSAndroid Build Coastguard Worker 		node = rtree_node_init(tsdn, rtree, level + 1, &elm->child);
188*1208bc7eSAndroid Build Coastguard Worker 	}
189*1208bc7eSAndroid Build Coastguard Worker 	assert(!dependent || node != NULL);
190*1208bc7eSAndroid Build Coastguard Worker 	return node;
191*1208bc7eSAndroid Build Coastguard Worker }
192*1208bc7eSAndroid Build Coastguard Worker 
193*1208bc7eSAndroid Build Coastguard Worker static rtree_leaf_elm_t *
rtree_child_leaf_tryread(rtree_node_elm_t * elm,bool dependent)194*1208bc7eSAndroid Build Coastguard Worker rtree_child_leaf_tryread(rtree_node_elm_t *elm, bool dependent) {
195*1208bc7eSAndroid Build Coastguard Worker 	rtree_leaf_elm_t *leaf;
196*1208bc7eSAndroid Build Coastguard Worker 
197*1208bc7eSAndroid Build Coastguard Worker 	if (dependent) {
198*1208bc7eSAndroid Build Coastguard Worker 		leaf = (rtree_leaf_elm_t *)atomic_load_p(&elm->child,
199*1208bc7eSAndroid Build Coastguard Worker 		    ATOMIC_RELAXED);
200*1208bc7eSAndroid Build Coastguard Worker 	} else {
201*1208bc7eSAndroid Build Coastguard Worker 		leaf = (rtree_leaf_elm_t *)atomic_load_p(&elm->child,
202*1208bc7eSAndroid Build Coastguard Worker 		    ATOMIC_ACQUIRE);
203*1208bc7eSAndroid Build Coastguard Worker 	}
204*1208bc7eSAndroid Build Coastguard Worker 
205*1208bc7eSAndroid Build Coastguard Worker 	assert(!dependent || leaf != NULL);
206*1208bc7eSAndroid Build Coastguard Worker 	return leaf;
207*1208bc7eSAndroid Build Coastguard Worker }
208*1208bc7eSAndroid Build Coastguard Worker 
209*1208bc7eSAndroid Build Coastguard Worker static rtree_leaf_elm_t *
rtree_child_leaf_read(tsdn_t * tsdn,rtree_t * rtree,rtree_node_elm_t * elm,unsigned level,bool dependent)210*1208bc7eSAndroid Build Coastguard Worker rtree_child_leaf_read(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *elm,
211*1208bc7eSAndroid Build Coastguard Worker     unsigned level, bool dependent) {
212*1208bc7eSAndroid Build Coastguard Worker 	rtree_leaf_elm_t *leaf;
213*1208bc7eSAndroid Build Coastguard Worker 
214*1208bc7eSAndroid Build Coastguard Worker 	leaf = rtree_child_leaf_tryread(elm, dependent);
215*1208bc7eSAndroid Build Coastguard Worker 	if (!dependent && unlikely(!rtree_leaf_valid(leaf))) {
216*1208bc7eSAndroid Build Coastguard Worker 		leaf = rtree_leaf_init(tsdn, rtree, &elm->child);
217*1208bc7eSAndroid Build Coastguard Worker 	}
218*1208bc7eSAndroid Build Coastguard Worker 	assert(!dependent || leaf != NULL);
219*1208bc7eSAndroid Build Coastguard Worker 	return leaf;
220*1208bc7eSAndroid Build Coastguard Worker }
221*1208bc7eSAndroid Build Coastguard Worker 
222*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t *
rtree_leaf_elm_lookup_hard(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,bool dependent,bool init_missing)223*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
224*1208bc7eSAndroid Build Coastguard Worker     uintptr_t key, bool dependent, bool init_missing) {
225*1208bc7eSAndroid Build Coastguard Worker 	rtree_node_elm_t *node;
226*1208bc7eSAndroid Build Coastguard Worker 	rtree_leaf_elm_t *leaf;
227*1208bc7eSAndroid Build Coastguard Worker #if RTREE_HEIGHT > 1
228*1208bc7eSAndroid Build Coastguard Worker 	node = rtree->root;
229*1208bc7eSAndroid Build Coastguard Worker #else
230*1208bc7eSAndroid Build Coastguard Worker 	leaf = rtree->root;
231*1208bc7eSAndroid Build Coastguard Worker #endif
232*1208bc7eSAndroid Build Coastguard Worker 
233*1208bc7eSAndroid Build Coastguard Worker 	if (config_debug) {
234*1208bc7eSAndroid Build Coastguard Worker 		uintptr_t leafkey = rtree_leafkey(key);
235*1208bc7eSAndroid Build Coastguard Worker 		for (unsigned i = 0; i < RTREE_CTX_NCACHE; i++) {
236*1208bc7eSAndroid Build Coastguard Worker 			assert(rtree_ctx->cache[i].leafkey != leafkey);
237*1208bc7eSAndroid Build Coastguard Worker 		}
238*1208bc7eSAndroid Build Coastguard Worker 		for (unsigned i = 0; i < RTREE_CTX_NCACHE_L2; i++) {
239*1208bc7eSAndroid Build Coastguard Worker 			assert(rtree_ctx->l2_cache[i].leafkey != leafkey);
240*1208bc7eSAndroid Build Coastguard Worker 		}
241*1208bc7eSAndroid Build Coastguard Worker 	}
242*1208bc7eSAndroid Build Coastguard Worker 
243*1208bc7eSAndroid Build Coastguard Worker #define RTREE_GET_CHILD(level) {					\
244*1208bc7eSAndroid Build Coastguard Worker 		assert(level < RTREE_HEIGHT-1);				\
245*1208bc7eSAndroid Build Coastguard Worker 		/* ANDROID CHANGE: Bad pointers return NULL */		\
246*1208bc7eSAndroid Build Coastguard Worker 		/* if (level != 0 && !dependent && */			\
247*1208bc7eSAndroid Build Coastguard Worker 		/*    unlikely(!rtree_node_valid(node))) { */		\
248*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(!rtree_node_valid(node))) {		\
249*1208bc7eSAndroid Build Coastguard Worker 		/* ANDROID END CHANGE */				\
250*1208bc7eSAndroid Build Coastguard Worker 			return NULL;					\
251*1208bc7eSAndroid Build Coastguard Worker 		}							\
252*1208bc7eSAndroid Build Coastguard Worker 		uintptr_t subkey = rtree_subkey(key, level);		\
253*1208bc7eSAndroid Build Coastguard Worker 		if (level + 2 < RTREE_HEIGHT) {				\
254*1208bc7eSAndroid Build Coastguard Worker 			node = init_missing ?				\
255*1208bc7eSAndroid Build Coastguard Worker 			    rtree_child_node_read(tsdn, rtree,		\
256*1208bc7eSAndroid Build Coastguard Worker 			    &node[subkey], level, dependent) :		\
257*1208bc7eSAndroid Build Coastguard Worker 			    rtree_child_node_tryread(&node[subkey],	\
258*1208bc7eSAndroid Build Coastguard Worker 			    dependent);					\
259*1208bc7eSAndroid Build Coastguard Worker 		} else {						\
260*1208bc7eSAndroid Build Coastguard Worker 			leaf = init_missing ?				\
261*1208bc7eSAndroid Build Coastguard Worker 			    rtree_child_leaf_read(tsdn, rtree,		\
262*1208bc7eSAndroid Build Coastguard Worker 			    &node[subkey], level, dependent) :		\
263*1208bc7eSAndroid Build Coastguard Worker 			    rtree_child_leaf_tryread(&node[subkey],	\
264*1208bc7eSAndroid Build Coastguard Worker 			    dependent);					\
265*1208bc7eSAndroid Build Coastguard Worker 		}							\
266*1208bc7eSAndroid Build Coastguard Worker 	}
267*1208bc7eSAndroid Build Coastguard Worker 	/*
268*1208bc7eSAndroid Build Coastguard Worker 	 * Cache replacement upon hard lookup (i.e. L1 & L2 rtree cache miss):
269*1208bc7eSAndroid Build Coastguard Worker 	 * (1) evict last entry in L2 cache; (2) move the collision slot from L1
270*1208bc7eSAndroid Build Coastguard Worker 	 * cache down to L2; and 3) fill L1.
271*1208bc7eSAndroid Build Coastguard Worker 	 */
272*1208bc7eSAndroid Build Coastguard Worker #define RTREE_GET_LEAF(level) {						\
273*1208bc7eSAndroid Build Coastguard Worker 		assert(level == RTREE_HEIGHT-1);			\
274*1208bc7eSAndroid Build Coastguard Worker 		/* ANDROID CHANGE: Bad pointers return NULL */		\
275*1208bc7eSAndroid Build Coastguard Worker 		/* if (!dependent && unlikely(!rtree_leaf_valid(leaf))) {*/	\
276*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(!rtree_leaf_valid(leaf))) {		\
277*1208bc7eSAndroid Build Coastguard Worker 		/* ANDROID END CHANGE */				\
278*1208bc7eSAndroid Build Coastguard Worker 			return NULL;					\
279*1208bc7eSAndroid Build Coastguard Worker 		}							\
280*1208bc7eSAndroid Build Coastguard Worker 		if (RTREE_CTX_NCACHE_L2 > 1) {				\
281*1208bc7eSAndroid Build Coastguard Worker 			memmove(&rtree_ctx->l2_cache[1],		\
282*1208bc7eSAndroid Build Coastguard Worker 			    &rtree_ctx->l2_cache[0],			\
283*1208bc7eSAndroid Build Coastguard Worker 			    sizeof(rtree_ctx_cache_elm_t) *		\
284*1208bc7eSAndroid Build Coastguard Worker 			    (RTREE_CTX_NCACHE_L2 - 1));			\
285*1208bc7eSAndroid Build Coastguard Worker 		}							\
286*1208bc7eSAndroid Build Coastguard Worker 		size_t slot = rtree_cache_direct_map(key);		\
287*1208bc7eSAndroid Build Coastguard Worker 		rtree_ctx->l2_cache[0].leafkey =			\
288*1208bc7eSAndroid Build Coastguard Worker 		    rtree_ctx->cache[slot].leafkey;			\
289*1208bc7eSAndroid Build Coastguard Worker 		rtree_ctx->l2_cache[0].leaf =				\
290*1208bc7eSAndroid Build Coastguard Worker 		    rtree_ctx->cache[slot].leaf;			\
291*1208bc7eSAndroid Build Coastguard Worker 		uintptr_t leafkey = rtree_leafkey(key);			\
292*1208bc7eSAndroid Build Coastguard Worker 		rtree_ctx->cache[slot].leafkey = leafkey;		\
293*1208bc7eSAndroid Build Coastguard Worker 		rtree_ctx->cache[slot].leaf = leaf;			\
294*1208bc7eSAndroid Build Coastguard Worker 		uintptr_t subkey = rtree_subkey(key, level);		\
295*1208bc7eSAndroid Build Coastguard Worker 		return &leaf[subkey];					\
296*1208bc7eSAndroid Build Coastguard Worker 	}
297*1208bc7eSAndroid Build Coastguard Worker 	if (RTREE_HEIGHT > 1) {
298*1208bc7eSAndroid Build Coastguard Worker 		RTREE_GET_CHILD(0)
299*1208bc7eSAndroid Build Coastguard Worker 	}
300*1208bc7eSAndroid Build Coastguard Worker 	if (RTREE_HEIGHT > 2) {
301*1208bc7eSAndroid Build Coastguard Worker 		RTREE_GET_CHILD(1)
302*1208bc7eSAndroid Build Coastguard Worker 	}
303*1208bc7eSAndroid Build Coastguard Worker 	if (RTREE_HEIGHT > 3) {
304*1208bc7eSAndroid Build Coastguard Worker 		for (unsigned i = 2; i < RTREE_HEIGHT-1; i++) {
305*1208bc7eSAndroid Build Coastguard Worker 			RTREE_GET_CHILD(i)
306*1208bc7eSAndroid Build Coastguard Worker 		}
307*1208bc7eSAndroid Build Coastguard Worker 	}
308*1208bc7eSAndroid Build Coastguard Worker 	RTREE_GET_LEAF(RTREE_HEIGHT-1)
309*1208bc7eSAndroid Build Coastguard Worker #undef RTREE_GET_CHILD
310*1208bc7eSAndroid Build Coastguard Worker #undef RTREE_GET_LEAF
311*1208bc7eSAndroid Build Coastguard Worker 	not_reached();
312*1208bc7eSAndroid Build Coastguard Worker }
313*1208bc7eSAndroid Build Coastguard Worker 
314*1208bc7eSAndroid Build Coastguard Worker void
rtree_ctx_data_init(rtree_ctx_t * ctx)315*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_data_init(rtree_ctx_t *ctx) {
316*1208bc7eSAndroid Build Coastguard Worker 	for (unsigned i = 0; i < RTREE_CTX_NCACHE; i++) {
317*1208bc7eSAndroid Build Coastguard Worker 		rtree_ctx_cache_elm_t *cache = &ctx->cache[i];
318*1208bc7eSAndroid Build Coastguard Worker 		cache->leafkey = RTREE_LEAFKEY_INVALID;
319*1208bc7eSAndroid Build Coastguard Worker 		cache->leaf = NULL;
320*1208bc7eSAndroid Build Coastguard Worker 	}
321*1208bc7eSAndroid Build Coastguard Worker 	for (unsigned i = 0; i < RTREE_CTX_NCACHE_L2; i++) {
322*1208bc7eSAndroid Build Coastguard Worker 		rtree_ctx_cache_elm_t *cache = &ctx->l2_cache[i];
323*1208bc7eSAndroid Build Coastguard Worker 		cache->leafkey = RTREE_LEAFKEY_INVALID;
324*1208bc7eSAndroid Build Coastguard Worker 		cache->leaf = NULL;
325*1208bc7eSAndroid Build Coastguard Worker 	}
326*1208bc7eSAndroid Build Coastguard Worker }
327