#![cfg(feature = "alloc-global")]
use std::sync::atomic::{AtomicBool, Ordering};
use sefer_alloc::registry::{bootstrap, heap_slot::STATE_LIVE, HeapRegistry, HeapSlot};
static SERIAL: AtomicBool = AtomicBool::new(false);
struct SerialGuard;
impl SerialGuard {
fn acquire() -> Self {
while SERIAL
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
std::hint::spin_loop();
}
SerialGuard
}
}
impl Drop for SerialGuard {
fn drop(&mut self) {
SERIAL.store(false, Ordering::Release);
}
}
macro_rules! serial {
() => {
let _serial = SerialGuard::acquire();
};
}
fn count_at_entry() -> u32 {
bootstrap::count_for_test()
}
fn drain_abandoned() {
while HeapRegistry::pop_abandoned_segment().is_some() {}
}
fn slot_state(idx: usize) -> u8 {
let reg = bootstrap::ensure();
reg.slots[idx].state.load(Ordering::Acquire)
}
fn slot_generation(idx: usize) -> u32 {
let reg = bootstrap::ensure();
reg.slots[idx].generation.load(Ordering::Acquire)
}
#[test]
fn claim_yields_distinct_live_slots() {
serial!();
let base = count_at_entry();
let a = HeapRegistry::claim();
let b = HeapRegistry::claim();
let c = HeapRegistry::claim();
assert!(
!a.is_null(),
"claim must not return null on a fresh registry"
);
assert!(!b.is_null(), "second claim must not return null");
assert!(!c.is_null(), "third claim must not return null");
assert_ne!(a, b, "claim must hand out DISTINCT slots (a vs b)");
assert_ne!(b, c, "claim must hand out DISTINCT slots (b vs c)");
assert_ne!(a, c, "claim must hand out DISTINCT slots (a vs c)");
let id_a = unsafe { (*a).id() } as usize;
let id_b = unsafe { (*b).id() } as usize;
let id_c = unsafe { (*c).id() } as usize;
assert_eq!(
id_a, base as usize,
"first claim mints the next count index"
);
assert_eq!(id_b, base as usize + 1);
assert_eq!(id_c, base as usize + 2);
assert_eq!(slot_state(id_a), STATE_LIVE, "claimed slot must be LIVE");
assert_eq!(slot_state(id_b), STATE_LIVE);
assert_eq!(slot_state(id_c), STATE_LIVE);
}
#[test]
fn recycle_then_claim_reuses_slot_and_bumps_generation() {
serial!();
let _base = count_at_entry();
let a = HeapRegistry::claim();
assert!(!a.is_null());
let id_a = unsafe { (*a).id() } as usize;
let gen_after_first_claim = slot_generation(id_a);
assert_eq!(
gen_after_first_claim, 1,
"first claim of a fresh slot must produce generation 1 \
(started at 0, bumped once)"
);
unsafe { HeapRegistry::recycle(a) };
assert_ne!(
slot_state(id_a),
STATE_LIVE,
"recycled slot must NOT be LIVE (it is FREE)"
);
let b = HeapRegistry::claim();
assert!(!b.is_null(), "claim after recycle must not return null");
let id_b = unsafe { (*b).id() } as usize;
assert_eq!(
id_b, id_a,
"claim after recycle must reuse the SAME slot (free_slots LIFO)"
);
let gen_after_second_claim = slot_generation(id_b);
assert_eq!(
gen_after_second_claim,
gen_after_first_claim + 1,
"re-claim must BUMP the generation (M8/M9 coherence key)"
);
}
#[test]
fn free_slots_is_lifo() {
serial!();
let _base = count_at_entry();
let a = HeapRegistry::claim();
let b = HeapRegistry::claim();
let id_a = unsafe { (*a).id() } as usize;
let id_b = unsafe { (*b).id() } as usize;
assert_ne!(id_a, id_b);
unsafe { HeapRegistry::recycle(a) };
unsafe { HeapRegistry::recycle(b) };
let c = HeapRegistry::claim();
let d = HeapRegistry::claim();
assert!(!c.is_null() && !d.is_null());
let id_c = unsafe { (*c).id() } as usize;
let id_d = unsafe { (*d).id() } as usize;
assert_eq!(
id_c, id_b,
"LIFO: first re-claim must pop the last recycled (B)"
);
assert_eq!(
id_d, id_a,
"LIFO: second re-claim must pop the earlier recycled (A)"
);
}
#[test]
fn abandon_pop_round_trip() {
serial!();
drain_abandoned();
assert!(
HeapRegistry::pop_abandoned_segment().is_none(),
"pop on an empty abandoned stack must return None"
);
let heap = HeapRegistry::claim();
assert!(!heap.is_null());
let heap_ref: &mut sefer_alloc::registry::HeapCore = unsafe { &mut *heap };
let base = heap_ref
.segment_bases()
.next()
.expect("a fresh heap owns at least its primordial segment");
assert!(!base.is_null(), "segment base must be non-null");
HeapRegistry::push_abandoned_segment(base);
let popped = HeapRegistry::pop_abandoned_segment().expect("pop must return the pushed base");
assert_eq!(
popped, base,
"pop must return the exact base that was pushed (no address truncation)"
);
assert!(
HeapRegistry::pop_abandoned_segment().is_none(),
"after popping the only entry, the stack must be empty"
);
}
#[test]
fn abandoned_head_packing_preserves_high_address() {
use sefer_alloc::registry::bootstrap::*;
const SEGMENT: u64 = 1 << 22; let high = 0x7f_0123_4000_u64;
let base = (high & !(SEGMENT - 1)) as *mut u8;
assert_eq!(
base as u64 % SEGMENT,
0,
"fake base must be SEGMENT-aligned (the packing requires it)"
);
assert!(
(base as u64) > (1u64 << 32),
"fake base must be above 4 GiB to exercise the >4 GiB path"
);
let word = pack_abandoned_head(base, 0x123456);
let (recovered_base, recovered_tag) = unpack_abandoned_head(word);
assert_eq!(
recovered_base, base,
"pack/unpack must preserve the full >4 GiB base (FINDINGS №1 fix)"
);
assert_eq!(recovered_tag, 0x123456, "pack/unpack must preserve the tag");
assert!(
abandoned_head_is_empty(ABANDONED_HEAD_EMPTY),
"the empty sentinel must denote an empty stack"
);
assert!(
!abandoned_head_is_empty(word),
"a packed non-null base must NOT denote an empty stack"
);
}
#[test]
fn abandon_segments_walks_owned_segments() {
serial!();
drain_abandoned();
let a = HeapRegistry::claim();
assert!(!a.is_null());
let heap: &mut sefer_alloc::registry::HeapCore = unsafe { &mut *a };
let layout = core::alloc::Layout::from_size_align(64, 8).unwrap();
let ptr = heap.alloc(layout);
assert!(!ptr.is_null(), "alloc must succeed on a fresh heap");
unsafe { HeapRegistry::abandon_segments(a) };
let popped = HeapRegistry::pop_abandoned_segment();
assert!(
popped.is_some(),
"abandon_segments must push owned segments onto the abandoned stack \
(Phase 12.4: it is a real walk, not a no-op)"
);
while HeapRegistry::pop_abandoned_segment().is_some() {}
}
#[test]
fn bootstrap_is_idempotent() {
serial!();
let count_before_claim = count_at_entry();
let _ = HeapRegistry::claim(); let reg_before = bootstrap::ensure();
let count_before = reg_before.count.load(Ordering::Acquire);
assert_eq!(
count_before,
count_before_claim + 1,
"claim must advance count by exactly 1"
);
let reg_after = bootstrap::ensure();
let count_after = reg_after.count.load(Ordering::Acquire);
assert_eq!(
count_before, count_after,
"a second ensure must not re-initialise the registry (count preserved)"
);
assert!(
std::ptr::eq(reg_before, reg_after),
"ensure must return the SAME &'static Registry on every call"
);
}
#[test]
fn recycle_null_is_noop() {
serial!();
let base = count_at_entry();
unsafe { HeapRegistry::recycle(core::ptr::null_mut()) };
let a = HeapRegistry::claim();
assert!(!a.is_null());
let id_a = unsafe { (*a).id() } as usize;
assert_eq!(
id_a, base as usize,
"after a null recycle, the first real claim mints the next count index"
);
}
#[test]
fn double_recycle_is_safe_noop() {
serial!();
let base = count_at_entry();
let a = HeapRegistry::claim();
let id_a = unsafe { (*a).id() } as usize;
unsafe { HeapRegistry::recycle(a) };
unsafe { HeapRegistry::recycle(a) };
let b = HeapRegistry::claim();
let c = HeapRegistry::claim();
assert!(!b.is_null() && !c.is_null());
let id_b = unsafe { (*b).id() } as usize;
let id_c = unsafe { (*c).id() } as usize;
assert_eq!(
id_b, id_a,
"first re-claim pops the once-pushed recycled slot"
);
assert_ne!(
id_b, id_c,
"second claim must mint a DIFFERENT slot (no phantom duplicate from double-recycle)"
);
assert_eq!(
id_c,
base as usize + 1,
"the second claim after a double-recycle mints the next count index"
);
}
#[test]
fn heap_slot_is_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<HeapSlot>();
}