Skip to content

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)
    #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) {
        }
        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);
    // 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++) {
        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.
    // 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++) {
        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},
            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.
                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));
                    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));
                    }
                }
            // 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;
        }
        // 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);
        }
    
        i = heap_find_by_page(heap->pages, heap->pages_len, sizeof(HeapPage), page_base);
        if (i != (u32)-1) {
            *idx_out = i;
    // 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];
            u8    class_idx;
            u8    _pad;
        } HeapPage;
    
        typedef struct HeapPageXL {
            PageAllocator page;
    
            HeapPage *pages;
            u32       pages_len;
            u32       pages_cap;
Last updated on