// front_gate_classifier.c - Box FG: Pointer Classification Implementation // CRITICAL: Box FG requires header-based classification // Ensure HEADER_MAGIC and HEADER_CLASS_MASK are available #ifndef HAKMEM_TINY_HEADER_CLASSIDX #define HAKMEM_TINY_HEADER_CLASSIDX 1 #endif #include // For fprintf in debug #include // For abort in debug #include "front_gate_classifier.h" #include "../tiny_region_id.h" // Must come before hakmem_tiny_superslab.h for HEADER_MAGIC #include "../hakmem_tiny_superslab.h" #include "../superslab/superslab_inline.h" // For ss_slabs_capacity #include "../hakmem_build_flags.h" #include "../hakmem_tiny_config.h" // For TINY_NUM_CLASSES, SLAB_SIZE #include "../hakmem_super_registry.h" // For hak_super_lookup (Box REG) #ifdef HAKMEM_POOL_TLS_PHASE1 #include "../pool_tls.h" // For POOL_MAGIC #endif // ========== Debug Stats ========== #if !HAKMEM_BUILD_RELEASE __thread uint64_t g_classify_header_hit = 0; __thread uint64_t g_classify_headerless_hit = 0; __thread uint64_t g_classify_pool_hit = 0; __thread uint64_t g_classify_unknown_hit = 0; void front_gate_print_stats(void) { uint64_t total = g_classify_header_hit + g_classify_headerless_hit + g_classify_pool_hit + g_classify_unknown_hit; if (total == 0) return; fprintf(stderr, "\n========== Front Gate Classification Stats ==========\n"); fprintf(stderr, "Header (C0-C6): %lu (%.2f%%)\n", g_classify_header_hit, 100.0 * g_classify_header_hit / total); fprintf(stderr, "Headerless (C7): %lu (%.2f%%)\n", g_classify_headerless_hit, 100.0 * g_classify_headerless_hit / total); fprintf(stderr, "Pool TLS: %lu (%.2f%%)\n", g_classify_pool_hit, 100.0 * g_classify_pool_hit / total); fprintf(stderr, "Unknown: %lu (%.2f%%)\n", g_classify_unknown_hit, 100.0 * g_classify_unknown_hit / total); fprintf(stderr, "Total: %lu\n", total); fprintf(stderr, "======================================================\n"); } static void __attribute__((destructor)) front_gate_stats_destructor(void) { front_gate_print_stats(); } #endif // ========== Safe Header Probe ========== // Try to read 1-byte header at ptr-1 (safe conditions only) // Returns: class_idx (0-7) on success, -1 on failure // // Safety conditions: // 1. Same page: (ptr & 0xFFF) >= 1 → header won't cross page boundary // 2. Valid magic: (header & 0xF0) == HEADER_MAGIC (0xa0) // 3. Valid class: class_idx in range [0, 7] // // Performance: 2-3 cycles (L1 cache hit) static inline int safe_header_probe(void* ptr) { // Safety check: header must be in same page as ptr uintptr_t offset_in_page = (uintptr_t)ptr & 0xFFF; if (offset_in_page == 0) { // ptr is page-aligned → header would be on previous page (unsafe) return -1; } // Safe to read header (same page guaranteed) uint8_t* header_ptr = (uint8_t*)ptr - 1; uint8_t header = *header_ptr; // Validate magic if ((header & 0xF0) != HEADER_MAGIC) { return -1; // Not a Tiny header } // Extract class index int class_idx = header & HEADER_CLASS_MASK; // Header-based Tiny never encodes class 7 (C7 is headerless) if (class_idx == 7) { return -1; } // Validate class range if (class_idx < 0 || class_idx >= TINY_NUM_CLASSES) { return -1; // Invalid class } return class_idx; } // ========== Registry Lookup ========== // Lookup pointer in SuperSlab registry (fallback when header probe fails) // Returns: classification result with SuperSlab + class_idx + slab_idx // // Performance: 50-100 cycles (hash lookup + validation) static inline ptr_classification_t registry_lookup(void* ptr) { ptr_classification_t result = { .kind = PTR_KIND_UNKNOWN, .class_idx = -1, .ss = NULL, .slab_idx = -1 }; // Query SuperSlab registry struct SuperSlab* ss = hak_super_lookup(ptr); if (!ss) { // Not in Tiny registry return result; } // Found SuperSlab - determine slab index result.ss = ss; result.class_idx = ss->size_class; // Calculate slab index uintptr_t ptr_addr = (uintptr_t)ptr; uintptr_t ss_addr = (uintptr_t)ss; if (ptr_addr < ss_addr) { // Pointer before SuperSlab base (invalid) result.kind = PTR_KIND_UNKNOWN; return result; } size_t offset = ptr_addr - ss_addr; result.slab_idx = (int)(offset / SLAB_SIZE); // Validate slab index (ss_slabs_capacity defined in superslab_inline.h) if (result.slab_idx < 0 || result.slab_idx >= ss_slabs_capacity(ss)) { // Out of range result.kind = PTR_KIND_UNKNOWN; return result; } // Valid Tiny allocation (headerless) // Note: C7 (1KB) is the only headerless class, but Registry handles all result.kind = PTR_KIND_TINY_HEADERLESS; return result; } // ========== Pool TLS Probe ========== #ifdef HAKMEM_POOL_TLS_PHASE1 // Check if pointer has Pool TLS magic (0xb0) // Returns: 1 if Pool TLS, 0 otherwise static inline int is_pool_tls(void* ptr) { // Same safety check as header probe uintptr_t offset_in_page = (uintptr_t)ptr & 0xFFF; if (offset_in_page == 0) { return 0; // Page-aligned, skip header read } uint8_t* header_ptr = (uint8_t*)ptr - 1; uint8_t header = *header_ptr; return (header & 0xF0) == POOL_MAGIC; } #endif // ========== Front Gate Entry Point ========== ptr_classification_t classify_ptr(void* ptr) { ptr_classification_t result = { .kind = PTR_KIND_UNKNOWN, .class_idx = -1, .ss = NULL, .slab_idx = -1 }; if (!ptr) return result; // Step 1: Try safe header probe (C0-C6 fast path: 5-10 cycles) // Skip header probe on 1KB-aligned pointers to avoid misclassifying C7/headerless int class_idx = -1; if (((uintptr_t)ptr & 0x3FF) != 0) { class_idx = safe_header_probe(ptr); } if (class_idx >= 0) { // Header found - C0-C6 with header result.kind = PTR_KIND_TINY_HEADER; result.class_idx = class_idx; #if !HAKMEM_BUILD_RELEASE g_classify_header_hit++; #endif return result; } // Step 2: Check Pool TLS (before Registry to avoid false positives) #ifdef HAKMEM_POOL_TLS_PHASE1 if (is_pool_tls(ptr)) { result.kind = PTR_KIND_POOL_TLS; #if !HAKMEM_BUILD_RELEASE g_classify_pool_hit++; #endif return result; } #endif // Step 3: Fallback to Registry lookup (C7 headerless or header failed) result = registry_lookup(ptr); if (result.kind == PTR_KIND_TINY_HEADERLESS) { #if !HAKMEM_BUILD_RELEASE g_classify_headerless_hit++; #endif return result; } // Step 4: Not Tiny or Pool - return UNKNOWN // Caller should check AllocHeader (16-byte) or delegate to system free result.kind = PTR_KIND_UNKNOWN; #if !HAKMEM_BUILD_RELEASE g_classify_unknown_hit++; #endif return result; }