edata.h revision 1.1.1.1 1 1.1 christos #ifndef JEMALLOC_INTERNAL_EDATA_H
2 1.1 christos #define JEMALLOC_INTERNAL_EDATA_H
3 1.1 christos
4 1.1 christos #include "jemalloc/internal/atomic.h"
5 1.1 christos #include "jemalloc/internal/bin_info.h"
6 1.1 christos #include "jemalloc/internal/bit_util.h"
7 1.1 christos #include "jemalloc/internal/hpdata.h"
8 1.1 christos #include "jemalloc/internal/nstime.h"
9 1.1 christos #include "jemalloc/internal/ph.h"
10 1.1 christos #include "jemalloc/internal/ql.h"
11 1.1 christos #include "jemalloc/internal/sc.h"
12 1.1 christos #include "jemalloc/internal/slab_data.h"
13 1.1 christos #include "jemalloc/internal/sz.h"
14 1.1 christos #include "jemalloc/internal/typed_list.h"
15 1.1 christos
16 1.1 christos /*
17 1.1 christos * sizeof(edata_t) is 128 bytes on 64-bit architectures. Ensure the alignment
18 1.1 christos * to free up the low bits in the rtree leaf.
19 1.1 christos */
20 1.1 christos #define EDATA_ALIGNMENT 128
21 1.1 christos
22 1.1 christos enum extent_state_e {
23 1.1 christos extent_state_active = 0,
24 1.1 christos extent_state_dirty = 1,
25 1.1 christos extent_state_muzzy = 2,
26 1.1 christos extent_state_retained = 3,
27 1.1 christos extent_state_transition = 4, /* States below are intermediate. */
28 1.1 christos extent_state_merging = 5,
29 1.1 christos extent_state_max = 5 /* Sanity checking only. */
30 1.1 christos };
31 1.1 christos typedef enum extent_state_e extent_state_t;
32 1.1 christos
33 1.1 christos enum extent_head_state_e {
34 1.1 christos EXTENT_NOT_HEAD,
35 1.1 christos EXTENT_IS_HEAD /* See comments in ehooks_default_merge_impl(). */
36 1.1 christos };
37 1.1 christos typedef enum extent_head_state_e extent_head_state_t;
38 1.1 christos
39 1.1 christos /*
40 1.1 christos * Which implementation of the page allocator interface, (PAI, defined in
41 1.1 christos * pai.h) owns the given extent?
42 1.1 christos */
43 1.1 christos enum extent_pai_e {
44 1.1 christos EXTENT_PAI_PAC = 0,
45 1.1 christos EXTENT_PAI_HPA = 1
46 1.1 christos };
47 1.1 christos typedef enum extent_pai_e extent_pai_t;
48 1.1 christos
49 1.1 christos struct e_prof_info_s {
50 1.1 christos /* Time when this was allocated. */
51 1.1 christos nstime_t e_prof_alloc_time;
52 1.1 christos /* Allocation request size. */
53 1.1 christos size_t e_prof_alloc_size;
54 1.1 christos /* Points to a prof_tctx_t. */
55 1.1 christos atomic_p_t e_prof_tctx;
56 1.1 christos /*
57 1.1 christos * Points to a prof_recent_t for the allocation; NULL
58 1.1 christos * means the recent allocation record no longer exists.
59 1.1 christos * Protected by prof_recent_alloc_mtx.
60 1.1 christos */
61 1.1 christos atomic_p_t e_prof_recent_alloc;
62 1.1 christos };
63 1.1 christos typedef struct e_prof_info_s e_prof_info_t;
64 1.1 christos
65 1.1 christos /*
66 1.1 christos * The information about a particular edata that lives in an emap. Space is
67 1.1 christos * more precious there (the information, plus the edata pointer, has to live in
68 1.1 christos * a 64-bit word if we want to enable a packed representation.
69 1.1 christos *
70 1.1 christos * There are two things that are special about the information here:
71 1.1 christos * - It's quicker to access. You have one fewer pointer hop, since finding the
72 1.1 christos * edata_t associated with an item always requires accessing the rtree leaf in
73 1.1 christos * which this data is stored.
74 1.1 christos * - It can be read unsynchronized, and without worrying about lifetime issues.
75 1.1 christos */
76 1.1 christos typedef struct edata_map_info_s edata_map_info_t;
77 1.1 christos struct edata_map_info_s {
78 1.1 christos bool slab;
79 1.1 christos szind_t szind;
80 1.1 christos };
81 1.1 christos
82 1.1 christos typedef struct edata_cmp_summary_s edata_cmp_summary_t;
83 1.1 christos struct edata_cmp_summary_s {
84 1.1 christos uint64_t sn;
85 1.1 christos uintptr_t addr;
86 1.1 christos };
87 1.1 christos
88 1.1 christos /* Extent (span of pages). Use accessor functions for e_* fields. */
89 1.1 christos typedef struct edata_s edata_t;
90 1.1 christos ph_structs(edata_avail, edata_t);
91 1.1 christos ph_structs(edata_heap, edata_t);
92 1.1 christos struct edata_s {
93 1.1 christos /*
94 1.1 christos * Bitfield containing several fields:
95 1.1 christos *
96 1.1 christos * a: arena_ind
97 1.1 christos * b: slab
98 1.1 christos * c: committed
99 1.1 christos * p: pai
100 1.1 christos * z: zeroed
101 1.1 christos * g: guarded
102 1.1 christos * t: state
103 1.1 christos * i: szind
104 1.1 christos * f: nfree
105 1.1 christos * s: bin_shard
106 1.1 christos *
107 1.1 christos * 00000000 ... 0000ssss ssffffff ffffiiii iiiitttg zpcbaaaa aaaaaaaa
108 1.1 christos *
109 1.1 christos * arena_ind: Arena from which this extent came, or all 1 bits if
110 1.1 christos * unassociated.
111 1.1 christos *
112 1.1 christos * slab: The slab flag indicates whether the extent is used for a slab
113 1.1 christos * of small regions. This helps differentiate small size classes,
114 1.1 christos * and it indicates whether interior pointers can be looked up via
115 1.1 christos * iealloc().
116 1.1 christos *
117 1.1 christos * committed: The committed flag indicates whether physical memory is
118 1.1 christos * committed to the extent, whether explicitly or implicitly
119 1.1 christos * as on a system that overcommits and satisfies physical
120 1.1 christos * memory needs on demand via soft page faults.
121 1.1 christos *
122 1.1 christos * pai: The pai flag is an extent_pai_t.
123 1.1 christos *
124 1.1 christos * zeroed: The zeroed flag is used by extent recycling code to track
125 1.1 christos * whether memory is zero-filled.
126 1.1 christos *
127 1.1 christos * guarded: The guarded flag is use by the sanitizer to track whether
128 1.1 christos * the extent has page guards around it.
129 1.1 christos *
130 1.1 christos * state: The state flag is an extent_state_t.
131 1.1 christos *
132 1.1 christos * szind: The szind flag indicates usable size class index for
133 1.1 christos * allocations residing in this extent, regardless of whether the
134 1.1 christos * extent is a slab. Extent size and usable size often differ
135 1.1 christos * even for non-slabs, either due to sz_large_pad or promotion of
136 1.1 christos * sampled small regions.
137 1.1 christos *
138 1.1 christos * nfree: Number of free regions in slab.
139 1.1 christos *
140 1.1 christos * bin_shard: the shard of the bin from which this extent came.
141 1.1 christos */
142 1.1 christos uint64_t e_bits;
143 1.1 christos #define MASK(CURRENT_FIELD_WIDTH, CURRENT_FIELD_SHIFT) ((((((uint64_t)0x1U) << (CURRENT_FIELD_WIDTH)) - 1)) << (CURRENT_FIELD_SHIFT))
144 1.1 christos
145 1.1 christos #define EDATA_BITS_ARENA_WIDTH MALLOCX_ARENA_BITS
146 1.1 christos #define EDATA_BITS_ARENA_SHIFT 0
147 1.1 christos #define EDATA_BITS_ARENA_MASK MASK(EDATA_BITS_ARENA_WIDTH, EDATA_BITS_ARENA_SHIFT)
148 1.1 christos
149 1.1 christos #define EDATA_BITS_SLAB_WIDTH 1
150 1.1 christos #define EDATA_BITS_SLAB_SHIFT (EDATA_BITS_ARENA_WIDTH + EDATA_BITS_ARENA_SHIFT)
151 1.1 christos #define EDATA_BITS_SLAB_MASK MASK(EDATA_BITS_SLAB_WIDTH, EDATA_BITS_SLAB_SHIFT)
152 1.1 christos
153 1.1 christos #define EDATA_BITS_COMMITTED_WIDTH 1
154 1.1 christos #define EDATA_BITS_COMMITTED_SHIFT (EDATA_BITS_SLAB_WIDTH + EDATA_BITS_SLAB_SHIFT)
155 1.1 christos #define EDATA_BITS_COMMITTED_MASK MASK(EDATA_BITS_COMMITTED_WIDTH, EDATA_BITS_COMMITTED_SHIFT)
156 1.1 christos
157 1.1 christos #define EDATA_BITS_PAI_WIDTH 1
158 1.1 christos #define EDATA_BITS_PAI_SHIFT (EDATA_BITS_COMMITTED_WIDTH + EDATA_BITS_COMMITTED_SHIFT)
159 1.1 christos #define EDATA_BITS_PAI_MASK MASK(EDATA_BITS_PAI_WIDTH, EDATA_BITS_PAI_SHIFT)
160 1.1 christos
161 1.1 christos #define EDATA_BITS_ZEROED_WIDTH 1
162 1.1 christos #define EDATA_BITS_ZEROED_SHIFT (EDATA_BITS_PAI_WIDTH + EDATA_BITS_PAI_SHIFT)
163 1.1 christos #define EDATA_BITS_ZEROED_MASK MASK(EDATA_BITS_ZEROED_WIDTH, EDATA_BITS_ZEROED_SHIFT)
164 1.1 christos
165 1.1 christos #define EDATA_BITS_GUARDED_WIDTH 1
166 1.1 christos #define EDATA_BITS_GUARDED_SHIFT (EDATA_BITS_ZEROED_WIDTH + EDATA_BITS_ZEROED_SHIFT)
167 1.1 christos #define EDATA_BITS_GUARDED_MASK MASK(EDATA_BITS_GUARDED_WIDTH, EDATA_BITS_GUARDED_SHIFT)
168 1.1 christos
169 1.1 christos #define EDATA_BITS_STATE_WIDTH 3
170 1.1 christos #define EDATA_BITS_STATE_SHIFT (EDATA_BITS_GUARDED_WIDTH + EDATA_BITS_GUARDED_SHIFT)
171 1.1 christos #define EDATA_BITS_STATE_MASK MASK(EDATA_BITS_STATE_WIDTH, EDATA_BITS_STATE_SHIFT)
172 1.1 christos
173 1.1 christos #define EDATA_BITS_SZIND_WIDTH LG_CEIL(SC_NSIZES)
174 1.1 christos #define EDATA_BITS_SZIND_SHIFT (EDATA_BITS_STATE_WIDTH + EDATA_BITS_STATE_SHIFT)
175 1.1 christos #define EDATA_BITS_SZIND_MASK MASK(EDATA_BITS_SZIND_WIDTH, EDATA_BITS_SZIND_SHIFT)
176 1.1 christos
177 1.1 christos #define EDATA_BITS_NFREE_WIDTH (SC_LG_SLAB_MAXREGS + 1)
178 1.1 christos #define EDATA_BITS_NFREE_SHIFT (EDATA_BITS_SZIND_WIDTH + EDATA_BITS_SZIND_SHIFT)
179 1.1 christos #define EDATA_BITS_NFREE_MASK MASK(EDATA_BITS_NFREE_WIDTH, EDATA_BITS_NFREE_SHIFT)
180 1.1 christos
181 1.1 christos #define EDATA_BITS_BINSHARD_WIDTH 6
182 1.1 christos #define EDATA_BITS_BINSHARD_SHIFT (EDATA_BITS_NFREE_WIDTH + EDATA_BITS_NFREE_SHIFT)
183 1.1 christos #define EDATA_BITS_BINSHARD_MASK MASK(EDATA_BITS_BINSHARD_WIDTH, EDATA_BITS_BINSHARD_SHIFT)
184 1.1 christos
185 1.1 christos #define EDATA_BITS_IS_HEAD_WIDTH 1
186 1.1 christos #define EDATA_BITS_IS_HEAD_SHIFT (EDATA_BITS_BINSHARD_WIDTH + EDATA_BITS_BINSHARD_SHIFT)
187 1.1 christos #define EDATA_BITS_IS_HEAD_MASK MASK(EDATA_BITS_IS_HEAD_WIDTH, EDATA_BITS_IS_HEAD_SHIFT)
188 1.1 christos
189 1.1 christos /* Pointer to the extent that this structure is responsible for. */
190 1.1 christos void *e_addr;
191 1.1 christos
192 1.1 christos union {
193 1.1 christos /*
194 1.1 christos * Extent size and serial number associated with the extent
195 1.1 christos * structure (different than the serial number for the extent at
196 1.1 christos * e_addr).
197 1.1 christos *
198 1.1 christos * ssssssss [...] ssssssss ssssnnnn nnnnnnnn
199 1.1 christos */
200 1.1 christos size_t e_size_esn;
201 1.1 christos #define EDATA_SIZE_MASK ((size_t)~(PAGE-1))
202 1.1 christos #define EDATA_ESN_MASK ((size_t)PAGE-1)
203 1.1 christos /* Base extent size, which may not be a multiple of PAGE. */
204 1.1 christos size_t e_bsize;
205 1.1 christos };
206 1.1 christos
207 1.1 christos /*
208 1.1 christos * If this edata is a user allocation from an HPA, it comes out of some
209 1.1 christos * pageslab (we don't yet support huegpage allocations that don't fit
210 1.1 christos * into pageslabs). This tracks it.
211 1.1 christos */
212 1.1 christos hpdata_t *e_ps;
213 1.1 christos
214 1.1 christos /*
215 1.1 christos * Serial number. These are not necessarily unique; splitting an extent
216 1.1 christos * results in two extents with the same serial number.
217 1.1 christos */
218 1.1 christos uint64_t e_sn;
219 1.1 christos
220 1.1 christos union {
221 1.1 christos /*
222 1.1 christos * List linkage used when the edata_t is active; either in
223 1.1 christos * arena's large allocations or bin_t's slabs_full.
224 1.1 christos */
225 1.1 christos ql_elm(edata_t) ql_link_active;
226 1.1 christos /*
227 1.1 christos * Pairing heap linkage. Used whenever the extent is inactive
228 1.1 christos * (in the page allocators), or when it is active and in
229 1.1 christos * slabs_nonfull, or when the edata_t is unassociated with an
230 1.1 christos * extent and sitting in an edata_cache.
231 1.1 christos */
232 1.1 christos union {
233 1.1 christos edata_heap_link_t heap_link;
234 1.1 christos edata_avail_link_t avail_link;
235 1.1 christos };
236 1.1 christos };
237 1.1 christos
238 1.1 christos union {
239 1.1 christos /*
240 1.1 christos * List linkage used when the extent is inactive:
241 1.1 christos * - Stashed dirty extents
242 1.1 christos * - Ecache LRU functionality.
243 1.1 christos */
244 1.1 christos ql_elm(edata_t) ql_link_inactive;
245 1.1 christos /* Small region slab metadata. */
246 1.1 christos slab_data_t e_slab_data;
247 1.1 christos
248 1.1 christos /* Profiling data, used for large objects. */
249 1.1 christos e_prof_info_t e_prof_info;
250 1.1 christos };
251 1.1 christos };
252 1.1 christos
253 1.1 christos TYPED_LIST(edata_list_active, edata_t, ql_link_active)
254 1.1 christos TYPED_LIST(edata_list_inactive, edata_t, ql_link_inactive)
255 1.1 christos
256 1.1 christos static inline unsigned
257 1.1 christos edata_arena_ind_get(const edata_t *edata) {
258 1.1 christos unsigned arena_ind = (unsigned)((edata->e_bits &
259 1.1 christos EDATA_BITS_ARENA_MASK) >> EDATA_BITS_ARENA_SHIFT);
260 1.1 christos assert(arena_ind < MALLOCX_ARENA_LIMIT);
261 1.1 christos
262 1.1 christos return arena_ind;
263 1.1 christos }
264 1.1 christos
265 1.1 christos static inline szind_t
266 1.1 christos edata_szind_get_maybe_invalid(const edata_t *edata) {
267 1.1 christos szind_t szind = (szind_t)((edata->e_bits & EDATA_BITS_SZIND_MASK) >>
268 1.1 christos EDATA_BITS_SZIND_SHIFT);
269 1.1 christos assert(szind <= SC_NSIZES);
270 1.1 christos return szind;
271 1.1 christos }
272 1.1 christos
273 1.1 christos static inline szind_t
274 1.1 christos edata_szind_get(const edata_t *edata) {
275 1.1 christos szind_t szind = edata_szind_get_maybe_invalid(edata);
276 1.1 christos assert(szind < SC_NSIZES); /* Never call when "invalid". */
277 1.1 christos return szind;
278 1.1 christos }
279 1.1 christos
280 1.1 christos static inline size_t
281 1.1 christos edata_usize_get(const edata_t *edata) {
282 1.1 christos return sz_index2size(edata_szind_get(edata));
283 1.1 christos }
284 1.1 christos
285 1.1 christos static inline unsigned
286 1.1 christos edata_binshard_get(const edata_t *edata) {
287 1.1 christos unsigned binshard = (unsigned)((edata->e_bits &
288 1.1 christos EDATA_BITS_BINSHARD_MASK) >> EDATA_BITS_BINSHARD_SHIFT);
289 1.1 christos assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
290 1.1 christos return binshard;
291 1.1 christos }
292 1.1 christos
293 1.1 christos static inline uint64_t
294 1.1 christos edata_sn_get(const edata_t *edata) {
295 1.1 christos return edata->e_sn;
296 1.1 christos }
297 1.1 christos
298 1.1 christos static inline extent_state_t
299 1.1 christos edata_state_get(const edata_t *edata) {
300 1.1 christos return (extent_state_t)((edata->e_bits & EDATA_BITS_STATE_MASK) >>
301 1.1 christos EDATA_BITS_STATE_SHIFT);
302 1.1 christos }
303 1.1 christos
304 1.1 christos static inline bool
305 1.1 christos edata_guarded_get(const edata_t *edata) {
306 1.1 christos return (bool)((edata->e_bits & EDATA_BITS_GUARDED_MASK) >>
307 1.1 christos EDATA_BITS_GUARDED_SHIFT);
308 1.1 christos }
309 1.1 christos
310 1.1 christos static inline bool
311 1.1 christos edata_zeroed_get(const edata_t *edata) {
312 1.1 christos return (bool)((edata->e_bits & EDATA_BITS_ZEROED_MASK) >>
313 1.1 christos EDATA_BITS_ZEROED_SHIFT);
314 1.1 christos }
315 1.1 christos
316 1.1 christos static inline bool
317 1.1 christos edata_committed_get(const edata_t *edata) {
318 1.1 christos return (bool)((edata->e_bits & EDATA_BITS_COMMITTED_MASK) >>
319 1.1 christos EDATA_BITS_COMMITTED_SHIFT);
320 1.1 christos }
321 1.1 christos
322 1.1 christos static inline extent_pai_t
323 1.1 christos edata_pai_get(const edata_t *edata) {
324 1.1 christos return (extent_pai_t)((edata->e_bits & EDATA_BITS_PAI_MASK) >>
325 1.1 christos EDATA_BITS_PAI_SHIFT);
326 1.1 christos }
327 1.1 christos
328 1.1 christos static inline bool
329 1.1 christos edata_slab_get(const edata_t *edata) {
330 1.1 christos return (bool)((edata->e_bits & EDATA_BITS_SLAB_MASK) >>
331 1.1 christos EDATA_BITS_SLAB_SHIFT);
332 1.1 christos }
333 1.1 christos
334 1.1 christos static inline unsigned
335 1.1 christos edata_nfree_get(const edata_t *edata) {
336 1.1 christos assert(edata_slab_get(edata));
337 1.1 christos return (unsigned)((edata->e_bits & EDATA_BITS_NFREE_MASK) >>
338 1.1 christos EDATA_BITS_NFREE_SHIFT);
339 1.1 christos }
340 1.1 christos
341 1.1 christos static inline void *
342 1.1 christos edata_base_get(const edata_t *edata) {
343 1.1 christos assert(edata->e_addr == PAGE_ADDR2BASE(edata->e_addr) ||
344 1.1 christos !edata_slab_get(edata));
345 1.1 christos return PAGE_ADDR2BASE(edata->e_addr);
346 1.1 christos }
347 1.1 christos
348 1.1 christos static inline void *
349 1.1 christos edata_addr_get(const edata_t *edata) {
350 1.1 christos assert(edata->e_addr == PAGE_ADDR2BASE(edata->e_addr) ||
351 1.1 christos !edata_slab_get(edata));
352 1.1 christos return edata->e_addr;
353 1.1 christos }
354 1.1 christos
355 1.1 christos static inline size_t
356 1.1 christos edata_size_get(const edata_t *edata) {
357 1.1 christos return (edata->e_size_esn & EDATA_SIZE_MASK);
358 1.1 christos }
359 1.1 christos
360 1.1 christos static inline size_t
361 1.1 christos edata_esn_get(const edata_t *edata) {
362 1.1 christos return (edata->e_size_esn & EDATA_ESN_MASK);
363 1.1 christos }
364 1.1 christos
365 1.1 christos static inline size_t
366 1.1 christos edata_bsize_get(const edata_t *edata) {
367 1.1 christos return edata->e_bsize;
368 1.1 christos }
369 1.1 christos
370 1.1 christos static inline hpdata_t *
371 1.1 christos edata_ps_get(const edata_t *edata) {
372 1.1 christos assert(edata_pai_get(edata) == EXTENT_PAI_HPA);
373 1.1 christos return edata->e_ps;
374 1.1 christos }
375 1.1 christos
376 1.1 christos static inline void *
377 1.1 christos edata_before_get(const edata_t *edata) {
378 1.1 christos return (void *)((uintptr_t)edata_base_get(edata) - PAGE);
379 1.1 christos }
380 1.1 christos
381 1.1 christos static inline void *
382 1.1 christos edata_last_get(const edata_t *edata) {
383 1.1 christos return (void *)((uintptr_t)edata_base_get(edata) +
384 1.1 christos edata_size_get(edata) - PAGE);
385 1.1 christos }
386 1.1 christos
387 1.1 christos static inline void *
388 1.1 christos edata_past_get(const edata_t *edata) {
389 1.1 christos return (void *)((uintptr_t)edata_base_get(edata) +
390 1.1 christos edata_size_get(edata));
391 1.1 christos }
392 1.1 christos
393 1.1 christos static inline slab_data_t *
394 1.1 christos edata_slab_data_get(edata_t *edata) {
395 1.1 christos assert(edata_slab_get(edata));
396 1.1 christos return &edata->e_slab_data;
397 1.1 christos }
398 1.1 christos
399 1.1 christos static inline const slab_data_t *
400 1.1 christos edata_slab_data_get_const(const edata_t *edata) {
401 1.1 christos assert(edata_slab_get(edata));
402 1.1 christos return &edata->e_slab_data;
403 1.1 christos }
404 1.1 christos
405 1.1 christos static inline prof_tctx_t *
406 1.1 christos edata_prof_tctx_get(const edata_t *edata) {
407 1.1 christos return (prof_tctx_t *)atomic_load_p(&edata->e_prof_info.e_prof_tctx,
408 1.1 christos ATOMIC_ACQUIRE);
409 1.1 christos }
410 1.1 christos
411 1.1 christos static inline const nstime_t *
412 1.1 christos edata_prof_alloc_time_get(const edata_t *edata) {
413 1.1 christos return &edata->e_prof_info.e_prof_alloc_time;
414 1.1 christos }
415 1.1 christos
416 1.1 christos static inline size_t
417 1.1 christos edata_prof_alloc_size_get(const edata_t *edata) {
418 1.1 christos return edata->e_prof_info.e_prof_alloc_size;
419 1.1 christos }
420 1.1 christos
421 1.1 christos static inline prof_recent_t *
422 1.1 christos edata_prof_recent_alloc_get_dont_call_directly(const edata_t *edata) {
423 1.1 christos return (prof_recent_t *)atomic_load_p(
424 1.1 christos &edata->e_prof_info.e_prof_recent_alloc, ATOMIC_RELAXED);
425 1.1 christos }
426 1.1 christos
427 1.1 christos static inline void
428 1.1 christos edata_arena_ind_set(edata_t *edata, unsigned arena_ind) {
429 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_ARENA_MASK) |
430 1.1 christos ((uint64_t)arena_ind << EDATA_BITS_ARENA_SHIFT);
431 1.1 christos }
432 1.1 christos
433 1.1 christos static inline void
434 1.1 christos edata_binshard_set(edata_t *edata, unsigned binshard) {
435 1.1 christos /* The assertion assumes szind is set already. */
436 1.1 christos assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
437 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_BINSHARD_MASK) |
438 1.1 christos ((uint64_t)binshard << EDATA_BITS_BINSHARD_SHIFT);
439 1.1 christos }
440 1.1 christos
441 1.1 christos static inline void
442 1.1 christos edata_addr_set(edata_t *edata, void *addr) {
443 1.1 christos edata->e_addr = addr;
444 1.1 christos }
445 1.1 christos
446 1.1 christos static inline void
447 1.1 christos edata_size_set(edata_t *edata, size_t size) {
448 1.1 christos assert((size & ~EDATA_SIZE_MASK) == 0);
449 1.1 christos edata->e_size_esn = size | (edata->e_size_esn & ~EDATA_SIZE_MASK);
450 1.1 christos }
451 1.1 christos
452 1.1 christos static inline void
453 1.1 christos edata_esn_set(edata_t *edata, size_t esn) {
454 1.1 christos edata->e_size_esn = (edata->e_size_esn & ~EDATA_ESN_MASK) | (esn &
455 1.1 christos EDATA_ESN_MASK);
456 1.1 christos }
457 1.1 christos
458 1.1 christos static inline void
459 1.1 christos edata_bsize_set(edata_t *edata, size_t bsize) {
460 1.1 christos edata->e_bsize = bsize;
461 1.1 christos }
462 1.1 christos
463 1.1 christos static inline void
464 1.1 christos edata_ps_set(edata_t *edata, hpdata_t *ps) {
465 1.1 christos assert(edata_pai_get(edata) == EXTENT_PAI_HPA);
466 1.1 christos edata->e_ps = ps;
467 1.1 christos }
468 1.1 christos
469 1.1 christos static inline void
470 1.1 christos edata_szind_set(edata_t *edata, szind_t szind) {
471 1.1 christos assert(szind <= SC_NSIZES); /* SC_NSIZES means "invalid". */
472 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_SZIND_MASK) |
473 1.1 christos ((uint64_t)szind << EDATA_BITS_SZIND_SHIFT);
474 1.1 christos }
475 1.1 christos
476 1.1 christos static inline void
477 1.1 christos edata_nfree_set(edata_t *edata, unsigned nfree) {
478 1.1 christos assert(edata_slab_get(edata));
479 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_NFREE_MASK) |
480 1.1 christos ((uint64_t)nfree << EDATA_BITS_NFREE_SHIFT);
481 1.1 christos }
482 1.1 christos
483 1.1 christos static inline void
484 1.1 christos edata_nfree_binshard_set(edata_t *edata, unsigned nfree, unsigned binshard) {
485 1.1 christos /* The assertion assumes szind is set already. */
486 1.1 christos assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
487 1.1 christos edata->e_bits = (edata->e_bits &
488 1.1 christos (~EDATA_BITS_NFREE_MASK & ~EDATA_BITS_BINSHARD_MASK)) |
489 1.1 christos ((uint64_t)binshard << EDATA_BITS_BINSHARD_SHIFT) |
490 1.1 christos ((uint64_t)nfree << EDATA_BITS_NFREE_SHIFT);
491 1.1 christos }
492 1.1 christos
493 1.1 christos static inline void
494 1.1 christos edata_nfree_inc(edata_t *edata) {
495 1.1 christos assert(edata_slab_get(edata));
496 1.1 christos edata->e_bits += ((uint64_t)1U << EDATA_BITS_NFREE_SHIFT);
497 1.1 christos }
498 1.1 christos
499 1.1 christos static inline void
500 1.1 christos edata_nfree_dec(edata_t *edata) {
501 1.1 christos assert(edata_slab_get(edata));
502 1.1 christos edata->e_bits -= ((uint64_t)1U << EDATA_BITS_NFREE_SHIFT);
503 1.1 christos }
504 1.1 christos
505 1.1 christos static inline void
506 1.1 christos edata_nfree_sub(edata_t *edata, uint64_t n) {
507 1.1 christos assert(edata_slab_get(edata));
508 1.1 christos edata->e_bits -= (n << EDATA_BITS_NFREE_SHIFT);
509 1.1 christos }
510 1.1 christos
511 1.1 christos static inline void
512 1.1 christos edata_sn_set(edata_t *edata, uint64_t sn) {
513 1.1 christos edata->e_sn = sn;
514 1.1 christos }
515 1.1 christos
516 1.1 christos static inline void
517 1.1 christos edata_state_set(edata_t *edata, extent_state_t state) {
518 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_STATE_MASK) |
519 1.1 christos ((uint64_t)state << EDATA_BITS_STATE_SHIFT);
520 1.1 christos }
521 1.1 christos
522 1.1 christos static inline void
523 1.1 christos edata_guarded_set(edata_t *edata, bool guarded) {
524 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_GUARDED_MASK) |
525 1.1 christos ((uint64_t)guarded << EDATA_BITS_GUARDED_SHIFT);
526 1.1 christos }
527 1.1 christos
528 1.1 christos static inline void
529 1.1 christos edata_zeroed_set(edata_t *edata, bool zeroed) {
530 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_ZEROED_MASK) |
531 1.1 christos ((uint64_t)zeroed << EDATA_BITS_ZEROED_SHIFT);
532 1.1 christos }
533 1.1 christos
534 1.1 christos static inline void
535 1.1 christos edata_committed_set(edata_t *edata, bool committed) {
536 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_COMMITTED_MASK) |
537 1.1 christos ((uint64_t)committed << EDATA_BITS_COMMITTED_SHIFT);
538 1.1 christos }
539 1.1 christos
540 1.1 christos static inline void
541 1.1 christos edata_pai_set(edata_t *edata, extent_pai_t pai) {
542 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_PAI_MASK) |
543 1.1 christos ((uint64_t)pai << EDATA_BITS_PAI_SHIFT);
544 1.1 christos }
545 1.1 christos
546 1.1 christos static inline void
547 1.1 christos edata_slab_set(edata_t *edata, bool slab) {
548 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_SLAB_MASK) |
549 1.1 christos ((uint64_t)slab << EDATA_BITS_SLAB_SHIFT);
550 1.1 christos }
551 1.1 christos
552 1.1 christos static inline void
553 1.1 christos edata_prof_tctx_set(edata_t *edata, prof_tctx_t *tctx) {
554 1.1 christos atomic_store_p(&edata->e_prof_info.e_prof_tctx, tctx, ATOMIC_RELEASE);
555 1.1 christos }
556 1.1 christos
557 1.1 christos static inline void
558 1.1 christos edata_prof_alloc_time_set(edata_t *edata, nstime_t *t) {
559 1.1 christos nstime_copy(&edata->e_prof_info.e_prof_alloc_time, t);
560 1.1 christos }
561 1.1 christos
562 1.1 christos static inline void
563 1.1 christos edata_prof_alloc_size_set(edata_t *edata, size_t size) {
564 1.1 christos edata->e_prof_info.e_prof_alloc_size = size;
565 1.1 christos }
566 1.1 christos
567 1.1 christos static inline void
568 1.1 christos edata_prof_recent_alloc_set_dont_call_directly(edata_t *edata,
569 1.1 christos prof_recent_t *recent_alloc) {
570 1.1 christos atomic_store_p(&edata->e_prof_info.e_prof_recent_alloc, recent_alloc,
571 1.1 christos ATOMIC_RELAXED);
572 1.1 christos }
573 1.1 christos
574 1.1 christos static inline bool
575 1.1 christos edata_is_head_get(edata_t *edata) {
576 1.1 christos return (bool)((edata->e_bits & EDATA_BITS_IS_HEAD_MASK) >>
577 1.1 christos EDATA_BITS_IS_HEAD_SHIFT);
578 1.1 christos }
579 1.1 christos
580 1.1 christos static inline void
581 1.1 christos edata_is_head_set(edata_t *edata, bool is_head) {
582 1.1 christos edata->e_bits = (edata->e_bits & ~EDATA_BITS_IS_HEAD_MASK) |
583 1.1 christos ((uint64_t)is_head << EDATA_BITS_IS_HEAD_SHIFT);
584 1.1 christos }
585 1.1 christos
586 1.1 christos static inline bool
587 1.1 christos edata_state_in_transition(extent_state_t state) {
588 1.1 christos return state >= extent_state_transition;
589 1.1 christos }
590 1.1 christos
591 1.1 christos /*
592 1.1 christos * Because this function is implemented as a sequence of bitfield modifications,
593 1.1 christos * even though each individual bit is properly initialized, we technically read
594 1.1 christos * uninitialized data within it. This is mostly fine, since most callers get
595 1.1 christos * their edatas from zeroing sources, but callers who make stack edata_ts need
596 1.1 christos * to manually zero them.
597 1.1 christos */
598 1.1 christos static inline void
599 1.1 christos edata_init(edata_t *edata, unsigned arena_ind, void *addr, size_t size,
600 1.1 christos bool slab, szind_t szind, uint64_t sn, extent_state_t state, bool zeroed,
601 1.1 christos bool committed, extent_pai_t pai, extent_head_state_t is_head) {
602 1.1 christos assert(addr == PAGE_ADDR2BASE(addr) || !slab);
603 1.1 christos
604 1.1 christos edata_arena_ind_set(edata, arena_ind);
605 1.1 christos edata_addr_set(edata, addr);
606 1.1 christos edata_size_set(edata, size);
607 1.1 christos edata_slab_set(edata, slab);
608 1.1 christos edata_szind_set(edata, szind);
609 1.1 christos edata_sn_set(edata, sn);
610 1.1 christos edata_state_set(edata, state);
611 1.1 christos edata_guarded_set(edata, false);
612 1.1 christos edata_zeroed_set(edata, zeroed);
613 1.1 christos edata_committed_set(edata, committed);
614 1.1 christos edata_pai_set(edata, pai);
615 1.1 christos edata_is_head_set(edata, is_head == EXTENT_IS_HEAD);
616 1.1 christos if (config_prof) {
617 1.1 christos edata_prof_tctx_set(edata, NULL);
618 1.1 christos }
619 1.1 christos }
620 1.1 christos
621 1.1 christos static inline void
622 1.1 christos edata_binit(edata_t *edata, void *addr, size_t bsize, uint64_t sn) {
623 1.1 christos edata_arena_ind_set(edata, (1U << MALLOCX_ARENA_BITS) - 1);
624 1.1 christos edata_addr_set(edata, addr);
625 1.1 christos edata_bsize_set(edata, bsize);
626 1.1 christos edata_slab_set(edata, false);
627 1.1 christos edata_szind_set(edata, SC_NSIZES);
628 1.1 christos edata_sn_set(edata, sn);
629 1.1 christos edata_state_set(edata, extent_state_active);
630 1.1 christos edata_guarded_set(edata, false);
631 1.1 christos edata_zeroed_set(edata, true);
632 1.1 christos edata_committed_set(edata, true);
633 1.1 christos /*
634 1.1 christos * This isn't strictly true, but base allocated extents never get
635 1.1 christos * deallocated and can't be looked up in the emap, but no sense in
636 1.1 christos * wasting a state bit to encode this fact.
637 1.1 christos */
638 1.1 christos edata_pai_set(edata, EXTENT_PAI_PAC);
639 1.1 christos }
640 1.1 christos
641 1.1 christos static inline int
642 1.1 christos edata_esn_comp(const edata_t *a, const edata_t *b) {
643 1.1 christos size_t a_esn = edata_esn_get(a);
644 1.1 christos size_t b_esn = edata_esn_get(b);
645 1.1 christos
646 1.1 christos return (a_esn > b_esn) - (a_esn < b_esn);
647 1.1 christos }
648 1.1 christos
649 1.1 christos static inline int
650 1.1 christos edata_ead_comp(const edata_t *a, const edata_t *b) {
651 1.1 christos uintptr_t a_eaddr = (uintptr_t)a;
652 1.1 christos uintptr_t b_eaddr = (uintptr_t)b;
653 1.1 christos
654 1.1 christos return (a_eaddr > b_eaddr) - (a_eaddr < b_eaddr);
655 1.1 christos }
656 1.1 christos
657 1.1 christos static inline edata_cmp_summary_t
658 1.1 christos edata_cmp_summary_get(const edata_t *edata) {
659 1.1 christos return (edata_cmp_summary_t){edata_sn_get(edata),
660 1.1 christos (uintptr_t)edata_addr_get(edata)};
661 1.1 christos }
662 1.1 christos
663 1.1 christos static inline int
664 1.1 christos edata_cmp_summary_comp(edata_cmp_summary_t a, edata_cmp_summary_t b) {
665 1.1 christos int ret;
666 1.1 christos ret = (a.sn > b.sn) - (a.sn < b.sn);
667 1.1 christos if (ret != 0) {
668 1.1 christos return ret;
669 1.1 christos }
670 1.1 christos ret = (a.addr > b.addr) - (a.addr < b.addr);
671 1.1 christos return ret;
672 1.1 christos }
673 1.1 christos
674 1.1 christos static inline int
675 1.1 christos edata_snad_comp(const edata_t *a, const edata_t *b) {
676 1.1 christos edata_cmp_summary_t a_cmp = edata_cmp_summary_get(a);
677 1.1 christos edata_cmp_summary_t b_cmp = edata_cmp_summary_get(b);
678 1.1 christos
679 1.1 christos return edata_cmp_summary_comp(a_cmp, b_cmp);
680 1.1 christos }
681 1.1 christos
682 1.1 christos static inline int
683 1.1 christos edata_esnead_comp(const edata_t *a, const edata_t *b) {
684 1.1 christos int ret;
685 1.1 christos
686 1.1 christos ret = edata_esn_comp(a, b);
687 1.1 christos if (ret != 0) {
688 1.1 christos return ret;
689 1.1 christos }
690 1.1 christos
691 1.1 christos ret = edata_ead_comp(a, b);
692 1.1 christos return ret;
693 1.1 christos }
694 1.1 christos
695 1.1 christos ph_proto(, edata_avail, edata_t);
696 1.1 christos ph_proto(, edata_heap, edata_t);
697 1.1 christos
698 1.1 christos #endif /* JEMALLOC_INTERNAL_EDATA_H */
699