HeapPage
Description
Per-heap-page descriptor. One per user page across every S/M/L size class. Unified type keeps the per-class arrays from multiplying. 48 bytes, naturally aligned for the u64 bitmap.
Fields
| Name | Description |
|---|---|
page |
User page base (4 KiB-aligned within an OS page). Sort key for the allocator’s descriptor array. |
bitmap |
Per-slot in-use mask, 1 bit per slot, LSB-first within each word. Unused tail bits (slots >= class slot count) are pre-set to 1 at insert time so the alloc-side ctz(~word) never finds them as free. |
used_count |
Live slot count. Reclaim when 0 (and the class still has another warm page parked). |
class_idx |
Index into heap_class_size[] (0..HEAP_NUM_CLASSES-1). |
Usage example (Cross-references)
Usage examples (Cross-references)
- In
Heap.c:227:
#if HEAP_PAGES_PER_OS_PAGE == 1u
static FORCE_INLINE void heap_reclaim_empty_page(HeapAllocator *heap, u32 idx) {
HeapPage *d = &heap->pages[idx];
u8 cls = d->class_idx;
if (heap->class_count[cls] <= 1u) {- In
Heap.c:233:
}
void *page = d->page;
heap_remove_at(heap->pages, &heap->pages_len, idx, sizeof(HeapPage));
heap->class_count[cls] -= 1u;
AllocatorFree(&heap->page.base, page);- In
Heap.c:259:
// class_idx -- pages of the same class cluster in address order, so
// this is cache-friendly in practice.
static FORCE_INLINE HeapPage *heap_find_class_page_with_free(HeapAllocator *heap, u8 cls) {
u8 bm_words = heap_class_bm_words[cls];
for (u32 i = 0; i < heap->pages_len; i++) {- In
Heap.c:262:
u8 bm_words = heap_class_bm_words[cls];
for (u32 i = 0; i < heap->pages_len; i++) {
HeapPage *d = &heap->pages[i];
if (d->class_idx != cls) continue;
// Quick reject: a full page has used_count == slots_per_class.
- In
Heap.c:280:
// Bump the user-pointer for the first free slot in `d`, set its bit,
// increment used_count. Caller has already verified `d` has space.
static FORCE_INLINE void *heap_take_slot(HeapPage *d, u8 cls) {
u8 bm_words = heap_class_bm_words[cls];
for (u32 w = 0; w < bm_words; w++) {- In
Heap.c:310:
for (u32 i = 0; i < HEAP_PAGES_PER_OS_PAGE; i++) {
void *page_i = (char *)base + (size)i * HEAP_PAGE_SIZE;
HeapPage desc = {
.page = page_i,
.bitmap = {0, 0, 0, 0},- In
Heap.c:319:
heap_set_tail_bits(desc.bitmap, slots, bm_words);
u32 idx = heap_insert_sorted(heap, (void **)&heap->pages, &heap->pages_len, &heap->pages_cap,
sizeof(HeapPage), &desc);
if (idx == (u32)-1) {
// Roll back any descriptors already inserted from this base.
- In
Heap.c:324:
for (u32 j = 0; j < inserted; j++) {
void *p_j = (char *)base + (size)j * HEAP_PAGE_SIZE;
u32 ix_j = heap_find_by_page(heap->pages, heap->pages_len, sizeof(HeapPage), p_j);
if (ix_j != (u32)-1) {
heap_remove_at(heap->pages, &heap->pages_len, ix_j, sizeof(HeapPage));- In
Heap.c:326:
u32 ix_j = heap_find_by_page(heap->pages, heap->pages_len, sizeof(HeapPage), p_j);
if (ix_j != (u32)-1) {
heap_remove_at(heap->pages, &heap->pages_len, ix_j, sizeof(HeapPage));
}
}- In
Heap.c:337:
// them. Recover first_idx by re-locating base after each step.
// Simpler than tracking shifts manually.
first_idx = heap_find_by_page(heap->pages, heap->pages_len, sizeof(HeapPage), base);
inserted += 1u;
}- In
Heap.c:384:
// cls is in [0, HEAP_NUM_CLASSES) here because bytes <= 2048.
HeapPage *d = heap_find_class_page_with_free(heap, cls);
if (!d) {
u32 idx = heap_grow_class(heap, cls);- In
Heap.c:424:
}
i = heap_find_by_page(heap->pages, heap->pages_len, sizeof(HeapPage), page_base);
if (i != (u32)-1) {
*idx_out = i;- In
Heap.c:436:
// heap_recover_size.
static void heap_free_classed(HeapAllocator *heap, void *ptr, u32 idx) {
HeapPage *d = &heap->pages[idx];
u8 cls = d->class_idx;
u32 slot_size = heap_class_size[cls];- In
Heap.h:93:
u8 class_idx;
u8 _pad;
} HeapPage;
typedef struct HeapPageXL {- In
Heap.h:109:
PageAllocator page;
HeapPage *pages;
u32 pages_len;
u32 pages_cap;
Last updated on