bump_scope/chunk/header.rs
1use core::{cell::Cell, ptr::NonNull};
2
3use crate::{polyfill::non_null, settings::BumpAllocatorSettings};
4
5/// The chunk header that lives at
6/// - the start of the allocation when upwards bumping
7/// - the end of the allocation when downwards bumping
8///
9/// All non-`Cell` fields are immutable.
10#[repr(C, align(16))]
11pub(crate) struct ChunkHeader {
12 pub(crate) pos: Cell<NonNull<u8>>,
13 pub(crate) end: NonNull<u8>,
14
15 pub(crate) prev: Cell<Option<NonNull<Self>>>,
16 pub(crate) next: Cell<Option<NonNull<Self>>>,
17}
18
19/// Wraps a [`ChunkHeader`], making it Sync so it can be used as a static.
20/// The dummy chunk is never mutated, so this is fine.
21struct DummyChunkHeader(ChunkHeader);
22
23unsafe impl Sync for DummyChunkHeader {}
24
25/// We create a dummy chunks with a negative capacity, so all allocations will fail.
26///
27/// The pointers used for `pos` and `end` are chosen to be pointers into the same static dummy chunk.
28///
29/// It's irrelevant where the pointers point to, they just need to:
30/// - be aligned to [`MIN_CHUNK_ALIGN`]
31/// - denote a negative capacity (currently guaranteed to be -16)
32/// - point to some existing object, not a dangling pointer since a dangling pointer could
33/// theoretically be a valid pointer to some other chunk
34macro_rules! dummy_chunk {
35 ($name:ident) => {
36 pub(crate) const fn $name<S: BumpAllocatorSettings>() -> NonNull<ChunkHeader> {
37 static UP_CHUNK: DummyChunkHeader = DummyChunkHeader(ChunkHeader {
38 // SAFETY: Due to `align(16)`, `ChunkHeader`'s size is `>= 16`, so a `byte_add` of 16 is in bounds.
39 // We could also use `.add(1)` here, but we currently guarantee a capacity of -16
40 pos: Cell::new(unsafe { UP_CHUNK_PTR.cast().byte_add(16) }),
41 end: UP_CHUNK_PTR.cast(),
42 prev: Cell::new(None),
43 next: Cell::new(None),
44 });
45
46 static DOWN_CHUNK: DummyChunkHeader = DummyChunkHeader(ChunkHeader {
47 pos: Cell::new(DOWN_CHUNK_PTR.cast()),
48 // SAFETY: Due to `align(16)`, `ChunkHeader`'s size is `>= 16`, so a `byte_add` of 16 is in bounds.
49 // We could also use `.add(1)` here, but we currently guarantee a capacity of -16
50 end: unsafe { DOWN_CHUNK_PTR.cast().byte_add(16) },
51 prev: Cell::new(None),
52 next: Cell::new(None),
53 });
54
55 const UP_CHUNK_PTR: NonNull<ChunkHeader> = non_null::from_ref(&UP_CHUNK.0);
56 const DOWN_CHUNK_PTR: NonNull<ChunkHeader> = non_null::from_ref(&DOWN_CHUNK.0);
57
58 if S::UP { UP_CHUNK_PTR } else { DOWN_CHUNK_PTR }
59 }
60 };
61}
62
63impl ChunkHeader {
64 dummy_chunk!(unallocated);
65 dummy_chunk!(claimed);
66}