diff --git a/core/box/ptr_conversion_box.h b/core/box/ptr_conversion_box.h index 9ac13106..1b48db78 100644 --- a/core/box/ptr_conversion_box.h +++ b/core/box/ptr_conversion_box.h @@ -20,6 +20,8 @@ #include #include +#include "ptr_type_box.h" +#include "tiny_layout_box.h" #ifdef HAKMEM_PTR_CONVERSION_DEBUG #include @@ -30,42 +32,46 @@ /** * Convert BASE pointer (storage) to USER pointer (returned to caller) - * Phase E1-CORRECT: ALL classes (0-7) have 1-byte headers + * Phase E1-CORRECT: Offsets defined in tiny_layout_box.h * - * @param base_ptr Pointer to block in storage (no offset) - * @param class_idx Size class (0-7: +1 offset for all) - * @return USER pointer (usable memory address) + * @param base Block start in storage (wrapped hak_base_ptr_t) + * @param class_idx Size class + * @return User pointer (wrapped hak_user_ptr_t) */ -static inline void* ptr_base_to_user(void* base_ptr, uint8_t class_idx) { - if (base_ptr == NULL) { - return NULL; +static inline hak_user_ptr_t ptr_base_to_user(hak_base_ptr_t base, int class_idx) { + void* raw_base = HAK_BASE_TO_RAW(base); + if (raw_base == NULL) { + return HAK_USER_FROM_RAW(NULL); } - /* Phase E1-CORRECT: All classes 0-7 have 1-byte header - skip it */ - void* user_ptr = (void*)((uint8_t*)base_ptr + 1); - PTR_CONV_LOG("BASE→USER cls=%u base=%p → user=%p (+1 offset)\n", - class_idx, base_ptr, user_ptr); - return user_ptr; + size_t offset = tiny_user_offset(class_idx); + void* raw_user = (void*)((uint8_t*)raw_base + offset); + + PTR_CONV_LOG("BASE→USER cls=%d base=%p → user=%p (+%zu)\n", + class_idx, raw_base, raw_user, offset); + return HAK_USER_FROM_RAW(raw_user); } /** * Convert USER pointer (from caller) to BASE pointer (storage) - * Phase E1-CORRECT: ALL classes (0-7) have 1-byte headers + * Phase E1-CORRECT: Offsets defined in tiny_layout_box.h * - * @param user_ptr Pointer from user (may have +1 offset) - * @param class_idx Size class (0-7: -1 offset for all) - * @return BASE pointer (block start in storage) + * @param user Pointer from user (wrapped hak_user_ptr_t) + * @param class_idx Size class + * @return Base pointer (wrapped hak_base_ptr_t) */ -static inline void* ptr_user_to_base(void* user_ptr, uint8_t class_idx) { - if (user_ptr == NULL) { - return NULL; +static inline hak_base_ptr_t ptr_user_to_base(hak_user_ptr_t user, int class_idx) { + void* raw_user = HAK_USER_TO_RAW(user); + if (raw_user == NULL) { + return HAK_BASE_FROM_RAW(NULL); } - /* Phase E1-CORRECT: All classes 0-7 have 1-byte header - rewind it */ - void* base_ptr = (void*)((uint8_t*)user_ptr - 1); - PTR_CONV_LOG("USER→BASE cls=%u user=%p → base=%p (-1 offset)\n", - class_idx, user_ptr, base_ptr); - return base_ptr; + size_t offset = tiny_user_offset(class_idx); + void* raw_base = (void*)((uint8_t*)raw_user - offset); + + PTR_CONV_LOG("USER→BASE cls=%d user=%p → base=%p (-%zu)\n", + class_idx, raw_user, raw_base, offset); + return HAK_BASE_FROM_RAW(raw_base); } /** diff --git a/core/box/tiny_header_box.h b/core/box/tiny_header_box.h index 232df6d1..a95c3cab 100644 --- a/core/box/tiny_header_box.h +++ b/core/box/tiny_header_box.h @@ -24,7 +24,7 @@ #include #include #include "../hakmem_build_flags.h" -#include "../tiny_nextptr.h" +#include "tiny_layout_box.h" #include "../tiny_region_id.h" // ============================================================================ @@ -35,9 +35,9 @@ // All code must use this instead of hardcoded class_idx checks. // // Implementation: -// - Delegates to tiny_next_off() to avoid duplicating logic -// - next_off=0 → header overwritten by next pointer → false -// - next_off!=0 → header preserved → true +// - Delegates to tiny_user_offset() from tiny_layout_box.h +// - offset=0 → header overwritten by next pointer → false +// - offset!=0 → header preserved → true // // Returns: // true - C1-C6: Header preserved at offset 0, next at offset 1 @@ -45,10 +45,10 @@ static inline bool tiny_class_preserves_header(int class_idx) { #if HAKMEM_TINY_HEADER_CLASSIDX - // Delegate to tiny_nextptr.h specification (Single Source of Truth) - // next_off=0 → header overwritten (C0, C7) - // next_off=1 → header preserved (C1-C6) - return tiny_next_off(class_idx) != 0; + // Delegate to tiny_layout_box.h specification (Single Source of Truth) + // user_offset=0 → header overwritten (C0, C7) + // user_offset=1 → header preserved (C1-C6) + return tiny_user_offset(class_idx) != 0; #else // Headers disabled globally (void)class_idx; diff --git a/core/box/tiny_layout_box.h b/core/box/tiny_layout_box.h new file mode 100644 index 00000000..53b691e5 --- /dev/null +++ b/core/box/tiny_layout_box.h @@ -0,0 +1,54 @@ +/** + * @file tiny_layout_box.h + * @brief Box: Tiny Allocator Layout Definitions + * + * MISSION: Single source of truth for class size and header layout + * + * Current Design (Phase E1-CORRECT): + * - All classes (0-7) have 1-byte header + * - User pointer = base + 1 for classes 0-6, base + 0 for class 7 + * (Note: Class 7 is headerless in practice but marked for consistency) + * - No external code should hardcode offsets + */ + +#ifndef TINY_LAYOUT_BOX_H +#define TINY_LAYOUT_BOX_H + +#include +#include "../hakmem_tiny_config.h" // For g_tiny_class_sizes and TINY_NUM_CLASSES + +// Define all class-specific layout parameters +// Current: Defined in g_tiny_class_sizes[8] in hakmem_tiny.c +// This file makes them accessible via a unified Box API + +// Header size is 1 byte when enabled +#define TINY_HEADER_SIZE 1 + +// Validation macros +static inline int tiny_class_is_valid(int class_idx) { + return class_idx >= 0 && class_idx < TINY_NUM_CLASSES; +} + +static inline size_t tiny_class_stride(int class_idx) { + // Use the extern global definition from hakmem_tiny_config.h + // g_tiny_class_sizes is defined in core/hakmem_tiny_config_box.inc + return tiny_class_is_valid(class_idx) ? g_tiny_class_sizes[class_idx] : 0; +} + +// Calculate user pointer offset from base pointer +// This logic centralizes the "User = Base + 1" vs "User = Base + 0" decision +static inline size_t tiny_user_offset(int class_idx) { +#if HAKMEM_TINY_HEADER_CLASSIDX + // C0 (8B): offset 0 (8B stride too small for header + 8B pointer - would overflow) + // C7 (2048B): offset 0 (overwrites header in freelist - largest class can tolerate) + // C1-C6: offset 1 (header preserved - user data is not disturbed) + // Optimized: Use bitmask lookup instead of branching + // Bit pattern: C0=0, C1-C6=1, C7=0 → 0b01111110 = 0x7E + return (0x7Eu >> class_idx) & 1u; +#else + (void)class_idx; + return 0u; +#endif +} + +#endif // TINY_LAYOUT_BOX_H diff --git a/core/hakmem_tiny.c b/core/hakmem_tiny.c index 68ab89ac..2f7ff810 100644 --- a/core/hakmem_tiny.c +++ b/core/hakmem_tiny.c @@ -9,6 +9,7 @@ #include "hakmem_tiny_magazine.h" #include "hakmem_tiny_integrity.h" // PRIORITY 1-4: Corruption detection #include "box/tiny_next_ptr_box.h" // Box API: next pointer read/write +#include "box/ptr_conversion_box.h" // Box API: pointer conversion #include "hakmem_env_cache.h" // Priority-2: ENV cache // Phase 1 modules (must come AFTER hakmem_tiny.h for TinyPool definition) #include "hakmem_tiny_batch_refill.h" // Phase 1: Batch refill/spill for mini-magazine diff --git a/core/hakmem_tiny_config_box.inc b/core/hakmem_tiny_config_box.inc index 9cb8122e..be02db6b 100644 --- a/core/hakmem_tiny_config_box.inc +++ b/core/hakmem_tiny_config_box.inc @@ -140,8 +140,10 @@ static inline void tiny_debug_track_alloc_ret(int cls, void* ptr); // Phase E1-CORRECT: ALL classes have 1-byte headers (including C7) // Ultra-fast inline macro (3-4 instructions) #define HAK_RET_ALLOC(cls, base_ptr) do { \ - *(uint8_t*)(base_ptr) = HEADER_MAGIC | ((cls) & HEADER_CLASS_MASK); \ - return (void*)((uint8_t*)(base_ptr) + 1); \ + tiny_header_write_for_alloc((base_ptr), (cls)); \ + hak_base_ptr_t _base = HAK_BASE_FROM_RAW(base_ptr); \ + hak_user_ptr_t _user = ptr_base_to_user(_base, (cls)); \ + return (void*)HAK_USER_TO_RAW(_user); \ } while(0) #else // Debug: Keep full validation via tiny_region_id_write_header() + operation logging diff --git a/core/tiny_nextptr.h b/core/tiny_nextptr.h index 22472a7f..0ea57aa2 100644 --- a/core/tiny_nextptr.h +++ b/core/tiny_nextptr.h @@ -44,22 +44,14 @@ #include #include #include // backtrace for rare misalign diagnostics +#include "box/tiny_layout_box.h" +#include "box/tiny_header_box.h" // Compute freelist next-pointer offset within a block for the given class. // P0.1 updated: C0 and C7 use offset 0, C1-C6 use offset 1 (header preserved) // Rationale for C0: 8B stride cannot fit [1B header][8B next pointer] without overflow static inline __attribute__((always_inline)) size_t tiny_next_off(int class_idx) { -#if HAKMEM_TINY_HEADER_CLASSIDX - // C0 (8B): offset 0 (8B stride too small for header + 8B pointer - would overflow) - // C7 (2048B): offset 0 (overwrites header in freelist - largest class can tolerate) - // C1-C6: offset 1 (header preserved - user data is not disturbed) - // Optimized: Use bitmask lookup instead of branching - // Bit pattern: C0=0, C1-C6=1, C7=0 → 0b01111110 = 0x7E - return (0x7Eu >> class_idx) & 1u; -#else - (void)class_idx; - return 0u; -#endif + return tiny_user_offset(class_idx); } // Safe load of next pointer from a block base. @@ -106,7 +98,7 @@ static inline __attribute__((always_inline)) void tiny_next_store(void* base, in } if (__builtin_expect(g_restore_header, 0)) { // Legacy mode: Restore header for classes that preserve it (C0-C6) - *(uint8_t*)base = HEADER_MAGIC | (class_idx & HEADER_CLASS_MASK); + tiny_header_write_if_preserved(base, class_idx); } } #endif