// tiny_first_page_cache.h // Phase 3 C2 Patch 2: First Page Inline Cache // // Purpose: Cache current slab page pointer in TLS to avoid superslab metadata lookup // // Design: // - TinyFirstPageCache struct: first_page_base + first_page_free_count // - Per-class cache (C0-C7) // - Fast-path check in free path (before superslab lookup) // - Auto-invalidate on refill/retire // // Integration: // - tiny_legacy_fallback_free_base(): Check cache hit before superslab lookup // - Refill/retire: Update cache with new page info #ifndef HAK_FRONT_TINY_FIRST_PAGE_CACHE_H #define HAK_FRONT_TINY_FIRST_PAGE_CACHE_H #include #include #include "../hakmem_tiny_config.h" // For TINY_NUM_CLASSES // ============================================================================ // First Page Cache Structure // ============================================================================ typedef struct { void* first_page_base; // Current page base pointer (avoid superslab lookup) uint16_t first_page_free_count; // Free slots in current page (hint only) } TinyFirstPageCache; // ============================================================================ // External TLS Variable // ============================================================================ extern __thread TinyFirstPageCache g_first_page_cache[TINY_NUM_CLASSES]; // ============================================================================ // First Page Cache API // ============================================================================ /// Check if ptr is in cached first page (fast path hint) /// @param class_idx: Size class (0-7) /// @param ptr: Pointer to check (BASE pointer) /// @param page_size: Page size for this class /// @return: true if ptr is in cached page, false otherwise __attribute__((always_inline)) static inline bool tiny_first_page_cache_hit(uint32_t class_idx, void* ptr, size_t page_size) { if (class_idx >= TINY_NUM_CLASSES) return false; void* base = g_first_page_cache[class_idx].first_page_base; if (base == NULL) return false; // Check if ptr is within [base, base + page_size) uintptr_t ptr_addr = (uintptr_t)ptr; uintptr_t base_addr = (uintptr_t)base; return (ptr_addr >= base_addr) && (ptr_addr < base_addr + page_size); } /// Update first page cache (on refill) /// @param class_idx: Size class (0-7) /// @param base: New page base pointer /// @param count: Free slots in page __attribute__((always_inline)) static inline void tiny_first_page_cache_update(uint32_t class_idx, void* base, uint16_t count) { if (class_idx >= TINY_NUM_CLASSES) return; g_first_page_cache[class_idx].first_page_base = base; g_first_page_cache[class_idx].first_page_free_count = count; } /// Invalidate first page cache (on retire or page full) /// @param class_idx: Size class (0-7) __attribute__((always_inline)) static inline void tiny_first_page_cache_invalidate(uint32_t class_idx) { if (class_idx >= TINY_NUM_CLASSES) return; g_first_page_cache[class_idx].first_page_base = NULL; g_first_page_cache[class_idx].first_page_free_count = 0; } #endif // HAK_FRONT_TINY_FIRST_PAGE_CACHE_H