#include #include #include #include "hakmem.h" #include "hakx_front_tiny.h" #include "hakx_l25_tuner.h" // Optional mimalloc backend (weak; library may be absent at link/runtime) void* mi_malloc(size_t size) __attribute__((weak)); void mi_free(void* p) __attribute__((weak)); void* mi_realloc(void* p, size_t newsize) __attribute__((weak)); void* mi_calloc(size_t count, size_t size) __attribute__((weak)); // Phase A: HAKX uses selectable backend (env HAKX_BACKEND=hakmem|mi|sys; default=hakmem). // Front/Back specialization will be layered later. static enum { HAKX_B_HAKMEM=0, HAKX_B_MI=1, HAKX_B_SYS=2 } g_hakx_backend = HAKX_B_HAKMEM; static int g_hakx_env_parsed = 0; static inline void hakx_parse_backend_once(void) { if (g_hakx_env_parsed) return; const char* s = getenv("HAKX_BACKEND"); if (s) { if (strcmp(s, "mi") == 0) g_hakx_backend = HAKX_B_MI; else if (strcmp(s, "sys") == 0) g_hakx_backend = HAKX_B_SYS; else g_hakx_backend = HAKX_B_HAKMEM; } const char* tuner = getenv("HAKX_L25_TUNER"); if (tuner && atoi(tuner) != 0) { hakx_l25_tuner_start(); } g_hakx_env_parsed = 1; } void* hakx_malloc(size_t size) { hakx_parse_backend_once(); switch (g_hakx_backend) { case HAKX_B_MI: return mi_malloc ? mi_malloc(size) : malloc(size); case HAKX_B_SYS: return malloc(size); default: { if (hakx_tiny_can_handle(size)) { void* p = hakx_tiny_alloc(size); if (p) return p; // Tiny miss: fall through } return hak_alloc_at(size, HAK_CALLSITE()); } } } void hakx_free(void* ptr) { hakx_parse_backend_once(); if (!ptr) return; switch (g_hakx_backend) { case HAKX_B_MI: if (mi_free) mi_free(ptr); else free(ptr); break; case HAKX_B_SYS: free(ptr); break; default: if (hakx_tiny_maybe_free(ptr)) break; hak_free_at(ptr, 0, HAK_CALLSITE()); break; } } void* hakx_realloc(void* ptr, size_t new_size) { if (!ptr) return hakx_malloc(new_size); if (new_size == 0) { hakx_free(ptr); return NULL; } hakx_parse_backend_once(); switch (g_hakx_backend) { case HAKX_B_MI: return mi_realloc ? mi_realloc(ptr, new_size) : realloc(ptr, new_size); case HAKX_B_SYS: return realloc(ptr, new_size); default: { void* np = hak_alloc_at(new_size, HAK_CALLSITE()); if (!np) return NULL; memcpy(np, ptr, new_size); hak_free_at(ptr, 0, HAK_CALLSITE()); return np; } } } void* hakx_calloc(size_t n, size_t size) { size_t total; if (__builtin_mul_overflow(n, size, &total)) return NULL; hakx_parse_backend_once(); switch (g_hakx_backend) { case HAKX_B_MI: return mi_calloc ? mi_calloc(n, size) : calloc(n, size); case HAKX_B_SYS: return calloc(n, size); default: { void* p = hak_alloc_at(total, HAK_CALLSITE()); if (p) memset(p, 0, total); return p; } } } size_t hakx_usable_size(void* ptr) { (void)ptr; // Not exposed in public HAKMEM header; return 0 for now. return 0; } void hakx_trim(void) { // Future: call tiny/SS trim once exported; currently no-op }