Files
hakmem/core/tiny_nextptr.h

60 lines
2.0 KiB
C
Raw Normal View History

// tiny_nextptr.h - Safe load/store for header-aware next pointers
//
// Context:
// - Tiny classes 06 place a 1-byte header immediately before the user pointer
// - Freelist "next" is stored inside the block at an offset that depends on class
// - Many hot paths currently cast to void** at base+1, which is unaligned and UB in C
//
// This header centralizes the offset calculation and uses memcpy-based loads/stores
// to avoid undefined behavior from unaligned pointer access. Compilers will optimize
// these to efficient byte moves on x86_64 while remaining standards-compliant.
#ifndef TINY_NEXTPTR_H
#define TINY_NEXTPTR_H
#include <stdint.h>
#include <string.h>
#include "hakmem_build_flags.h"
// Compute freelist next-pointer offset within a block for the given class.
// - Class 7 (1024B) is headerless → next at offset 0 (block base)
// - Classes 06 have 1-byte header → next at offset 1
static inline __attribute__((always_inline)) size_t tiny_next_off(int class_idx) {
#if HAKMEM_TINY_HEADER_CLASSIDX
return (class_idx == 7) ? 0 : 1;
#else
(void)class_idx;
return 0;
#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 HAKMEM_TINY_HEADER_CLASSIDX
if (__builtin_expect(off != 0, 0)) {
void* next = NULL;
const uint8_t* p = (const uint8_t*)base + off;
memcpy(&next, p, sizeof(void*));
return next;
}
#endif
// Either headers are disabled, or this class uses offset 0 (aligned)
return *(void* const*)base;
}
// Safe store of next pointer into a block base
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
if (__builtin_expect(off != 0, 0)) {
uint8_t* p = (uint8_t*)base + off;
memcpy(p, &next, sizeof(void*));
return;
}
#endif
*(void**)base = next;
}
#endif // TINY_NEXTPTR_H