60 lines
2.0 KiB
C
60 lines
2.0 KiB
C
|
|
// tiny_nextptr.h - Safe load/store for header-aware next pointers
|
|||
|
|
//
|
|||
|
|
// Context:
|
|||
|
|
// - Tiny classes 0–6 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 0–6 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
|