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