// tiny_nextptr.h - Authoritative next-pointer offset/load/store for tiny boxes // // Finalized Phase E1-CORRECT spec (物理制約込み): // P0.1 updated: C0 and C7 use offset 0, C1-C6 use offset 1 (header preserved) // // HAKMEM_TINY_HEADER_CLASSIDX != 0 のとき: // // Class 0: // [1B header][7B payload] (total 8B stride) // → 8B stride に 1B header + 8B next pointer は収まらない(1B溢れる) // → next は base+0 に格納(headerを上書き) // → next_off = 0 // // Class 1〜6: // [1B header][payload >= 15B] (stride >= 16B) // → headerは保持し、next は header直後 base+1 に格納 // → next_off = 1 // // Class 7: // [1B header][payload 2047B] // → headerは上書きし、next は base+0 に格納(最大サイズなので許容) // → next_off = 0 // // HAKMEM_TINY_HEADER_CLASSIDX == 0 のとき: // // 全クラス headerなし → next_off = 0 // // このヘッダは上記仕様を唯一の真実として提供する。 // すべての tiny freelist / TLS / fast-cache / refill / SLL で // tiny_next_off/tiny_next_load/tiny_next_store を経由すること。 // 直接の *(void**) アクセスやローカルな offset 分岐は使用禁止。 #ifndef TINY_NEXTPTR_H #define TINY_NEXTPTR_H #include #include #include // P2.3: for getenv() #include "hakmem_build_flags.h" #include "tiny_region_id.h" // HEADER_MAGIC/HEADER_CLASS_MASK for header repair/logging #include "hakmem_super_registry.h" // hak_super_lookup #include "superslab/superslab_inline.h" // slab_index_for #include #include #include #include // backtrace for rare misalign diagnostics // 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 } // Safe load of next pointer from a block base. static inline __attribute__((always_inline)) void* tiny_next_load(const void* base, int class_idx) { size_t off = tiny_next_off(class_idx); if (off == 0) { // Aligned access at base (header無し or C7 freelist時) return *(void* const*)base; } // off != 0: use memcpy to avoid UB on architectures that forbid unaligned loads. // C0-C6: offset 1 (header preserved) void* next = NULL; const uint8_t* p = (const uint8_t*)base + off; memcpy(&next, p, sizeof(void*)); return next; } // Safe store of next pointer into a block base. // P2.3: Header restoration is now conditional (default: skip when class_map is active) // - When class_map is used for class_idx lookup (default), header restoration is unnecessary // - Alloc path always writes fresh header before returning block to user (HAK_RET_ALLOC) // - ENV: HAKMEM_TINY_RESTORE_HEADER=1 to force header restoration (legacy mode) // P0.1: C7 uses offset 0 (overwrites header), C0-C6 use offset 1 (header preserved) static inline __attribute__((always_inline)) void tiny_next_store(void* base, int class_idx, void* next) { size_t off = tiny_next_off(class_idx); #if HAKMEM_TINY_HEADER_CLASSIDX // P2.3: Skip header restoration by default (class_map is now default for class_idx lookup) // ENV: HAKMEM_TINY_RESTORE_HEADER=1 to force header restoration (legacy fallback mode) if (off != 0) { static int g_restore_header = -1; if (__builtin_expect(g_restore_header == -1, 0)) { const char* e = getenv("HAKMEM_TINY_RESTORE_HEADER"); g_restore_header = (e && *e && *e != '0') ? 1 : 0; } 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); } } #endif if (off == 0) { // Aligned access at base (overwrites header for C7). *(void**)base = next; return; } // off != 0: use memcpy for portability / UB-avoidance. uint8_t* p = (uint8_t*)base + off; memcpy(p, &next, sizeof(void*)); } #endif // TINY_NEXTPTR_H