175 lines
4.7 KiB
C
175 lines
4.7 KiB
C
|
|
// tiny_geometry_box.h - Pointer Geometry Calculation Box
|
||
|
|
// Purpose: Unified pointer arithmetic for BASE/USER/SuperSlab/slab_idx conversions
|
||
|
|
// License: MIT
|
||
|
|
// Date: 2025-11-30
|
||
|
|
//
|
||
|
|
// Box Theory Principles:
|
||
|
|
// - Single Responsibility: Pointer/offset calculation only
|
||
|
|
// - Clear Contract: Input(ptr/ss/slab_idx) → Output(conversion result)
|
||
|
|
// - Observable: Debug builds validate all range checks
|
||
|
|
// - Composable: Used by all allocation/free paths
|
||
|
|
//
|
||
|
|
// Background:
|
||
|
|
// Phase 9-3 analysis revealed pointer arithmetic duplication across codebase:
|
||
|
|
// - BASE ↔ USER conversion scattered in 40+ locations
|
||
|
|
// - ptr → SuperSlab lookup duplicated in 20+ files
|
||
|
|
// - slab_idx calculation implemented inconsistently
|
||
|
|
//
|
||
|
|
// Solution:
|
||
|
|
// Unified API for all pointer geometry operations with single source of truth
|
||
|
|
|
||
|
|
#ifndef HAKMEM_TINY_GEOMETRY_BOX_H
|
||
|
|
#define HAKMEM_TINY_GEOMETRY_BOX_H
|
||
|
|
|
||
|
|
#include "../hakmem_tiny_superslab_internal.h"
|
||
|
|
#include "../hakmem_super_registry.h"
|
||
|
|
#include "../superslab/superslab_inline.h"
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
|
||
|
|
// ========== BASE ↔ USER Pointer Conversion ==========
|
||
|
|
//
|
||
|
|
// BASE pointer: Points to block start (where header is stored for C1-C6)
|
||
|
|
// USER pointer: Points to usable memory (BASE + header_size)
|
||
|
|
//
|
||
|
|
// Class 0 (16B): header_size = 0 (no header)
|
||
|
|
// Class 1-6: header_size = 1 byte
|
||
|
|
// Class 7 (C7): header_size = 0 (no header, uses offset 0 for next)
|
||
|
|
|
||
|
|
// Convert USER pointer → BASE pointer
|
||
|
|
static inline void* BASE_FROM_USER(int class_idx, void* user_ptr)
|
||
|
|
{
|
||
|
|
if (!user_ptr) return NULL;
|
||
|
|
|
||
|
|
// Class 0 and C7: no header, USER == BASE
|
||
|
|
if (class_idx == 0 || class_idx == 7) {
|
||
|
|
return user_ptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Class 1-6: header is 1 byte before user pointer
|
||
|
|
return (void*)((uint8_t*)user_ptr - 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Convert BASE pointer → USER pointer
|
||
|
|
static inline void* USER_FROM_BASE(int class_idx, void* base_ptr)
|
||
|
|
{
|
||
|
|
if (!base_ptr) return NULL;
|
||
|
|
|
||
|
|
// Class 0 and C7: no header, BASE == USER
|
||
|
|
if (class_idx == 0 || class_idx == 7) {
|
||
|
|
return base_ptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Class 1-6: user pointer is 1 byte after base
|
||
|
|
return (void*)((uint8_t*)base_ptr + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== SuperSlab Lookup ==========
|
||
|
|
//
|
||
|
|
// Find which SuperSlab a pointer belongs to (uses existing hash table)
|
||
|
|
|
||
|
|
static inline SuperSlab* SS_FROM_PTR(void* ptr)
|
||
|
|
{
|
||
|
|
if (!ptr) return NULL;
|
||
|
|
|
||
|
|
// Use existing registry-based lookup (safe, crash-free)
|
||
|
|
return hak_super_lookup(ptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== Slab Index Lookup ==========
|
||
|
|
//
|
||
|
|
// Find which slab index within a SuperSlab a pointer belongs to
|
||
|
|
|
||
|
|
static inline int SLAB_IDX_FROM_PTR(SuperSlab* ss, void* ptr)
|
||
|
|
{
|
||
|
|
if (!ss || !ptr) return -1;
|
||
|
|
|
||
|
|
// Delegate to existing slab_index_for() function
|
||
|
|
// (defined in superslab_inline.h)
|
||
|
|
return slab_index_for(ss, ptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== Slab Data Offset Calculation ==========
|
||
|
|
//
|
||
|
|
// Calculate data offset for a slab index within SuperSlab
|
||
|
|
|
||
|
|
static inline size_t SLAB_DATA_OFFSET(SuperSlab* ss, int slab_idx)
|
||
|
|
{
|
||
|
|
if (!ss || slab_idx < 0) return 0;
|
||
|
|
|
||
|
|
// Use existing geometry helper
|
||
|
|
extern size_t ss_slab_data_offset(SuperSlab* ss, int slab_idx);
|
||
|
|
return ss_slab_data_offset(ss, slab_idx);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== Block Stride Calculation ==========
|
||
|
|
//
|
||
|
|
// Get block stride (total size including header) for a class
|
||
|
|
|
||
|
|
static inline size_t BLOCK_STRIDE(int class_idx)
|
||
|
|
{
|
||
|
|
extern const size_t g_tiny_class_sizes[TINY_NUM_CLASSES];
|
||
|
|
|
||
|
|
if (class_idx < 0 || class_idx >= TINY_NUM_CLASSES) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return g_tiny_class_sizes[class_idx];
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== Debug Range Validation ==========
|
||
|
|
|
||
|
|
#if !HAKMEM_BUILD_RELEASE
|
||
|
|
static inline bool VALIDATE_PTR_RANGE(void* ptr, const char* context)
|
||
|
|
{
|
||
|
|
if (!ptr) return false;
|
||
|
|
|
||
|
|
uintptr_t addr = (uintptr_t)ptr;
|
||
|
|
|
||
|
|
// Check for NULL-ish and canonical address range
|
||
|
|
if (addr < 4096 || addr > 0x00007fffffffffffULL) {
|
||
|
|
fprintf(stderr, "[GEOMETRY_INVALID_PTR] context=%s ptr=%p\n",
|
||
|
|
context ? context : "(null)", ptr);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
#define VALIDATE_PTR_RANGE(ptr, context) (1)
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// ========== Combined Lookup Helpers ==========
|
||
|
|
//
|
||
|
|
// Common pattern: ptr → (SuperSlab, slab_idx, meta)
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
SuperSlab* ss;
|
||
|
|
int slab_idx;
|
||
|
|
TinySlabMeta* meta;
|
||
|
|
} PtrGeometry;
|
||
|
|
|
||
|
|
static inline PtrGeometry PTR_CLASSIFY(void* ptr)
|
||
|
|
{
|
||
|
|
PtrGeometry result = {NULL, -1, NULL};
|
||
|
|
|
||
|
|
if (!VALIDATE_PTR_RANGE(ptr, "PTR_CLASSIFY")) {
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
result.ss = SS_FROM_PTR(ptr);
|
||
|
|
if (!result.ss) {
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
result.slab_idx = SLAB_IDX_FROM_PTR(result.ss, ptr);
|
||
|
|
if (result.slab_idx < 0) {
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
result.meta = &result.ss->slabs[result.slab_idx];
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif // HAKMEM_TINY_GEOMETRY_BOX_H
|