Skip to content

Commit 965dfa4

Browse files
committed
refactor(utils): rework rlsf for const fn compatibility
The support for arbitrary alignment requests has been removed because in Rust CTFE it's impossible to calculate the offset required to align an arbitrary pointer. `<*mut _>::align_offset` returns `usize::MAX` in CTFE[1], which is useless but permitted under its definition. `Tlsf::insert_free_block*` has been changed to require the caller to provide a well-aligned pointer for the same reason. [1]: https://github.com/rust-lang/rust/blob/ecf72996eda4f8af19b0ca7235c6f62e0245a313/library/core/src/ptr/const_ptr.rs#L960-L965
1 parent 054840b commit 965dfa4

File tree

7 files changed

+126
-224
lines changed

7 files changed

+126
-224
lines changed

src/r3_core/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#![feature(const_slice_first_last)]
99
#![feature(const_replace)]
1010
#![feature(const_intrinsic_copy)]
11+
#![feature(const_raw_ptr_comparison)]
12+
#![feature(const_ptr_offset_from)]
1113
#![feature(maybe_uninit_slice)]
1214
#![feature(const_mut_refs)]
1315
#![feature(const_slice_from_raw_parts)]

src/r3_core/src/utils/alloc/rlsf/flex.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use core::{alloc::Layout, debug_assert, ptr::NonNull, unimplemented};
44
use super::{
55
int::BinInteger,
66
utils::{
7-
nonnull_slice_end, nonnull_slice_from_raw_parts, nonnull_slice_len, nonnull_slice_start,
7+
min_usize, nonnull_slice_end, nonnull_slice_from_raw_parts, nonnull_slice_len,
8+
nonnull_slice_start,
89
},
9-
Init, Tlsf, GRANULARITY,
10+
Init, Tlsf, ALIGN, GRANULARITY,
1011
};
1112

1213
/// The trait for dynamic storage allocators that can back [`FlexTlsf`].
@@ -227,17 +228,19 @@ const _: () = if core::mem::size_of::<PoolFtr>() != GRANULARITY / 2 {
227228
const_panic!("bad `PoolFtr` size");
228229
};
229230

231+
const _: () = assert!(core::mem::align_of::<PoolFtr>() <= ALIGN);
232+
230233
impl PoolFtr {
231234
/// Get a pointer to `PoolFtr` for a given allocation.
232235
#[inline]
233236
const fn get_for_alloc(alloc: NonNull<[u8]>, alloc_align: usize) -> *mut Self {
234237
let alloc_end = nonnull_slice_end(alloc);
235-
let mut ptr = alloc_end.wrapping_sub(core::mem::size_of::<Self>());
238+
let ptr = alloc_end.wrapping_sub(core::mem::size_of::<Self>());
239+
236240
// If `alloc_end` is not well-aligned, we need to adjust the location
237-
// of `PoolFtr`
238-
if alloc_align < core::mem::align_of::<Self>() {
239-
ptr = (ptr as usize & !(core::mem::align_of::<Self>() - 1)) as _;
240-
}
241+
// of `PoolFtr`, but that's impossible in CTFE
242+
assert!(alloc_align >= ALIGN);
243+
241244
ptr as _
242245
}
243246
}
@@ -414,7 +417,7 @@ impl<
414417
if is_well_aligned {
415418
self.tlsf.insert_free_block_ptr_aligned(alloc)
416419
} else {
417-
self.tlsf.insert_free_block_ptr(alloc)
420+
panic!("this version of `rlsf` requires `min_align() >= GRANULARITY`");
418421
}
419422
};
420423
let pool_len = if let Some(pool_len) = pool_len {
@@ -546,8 +549,11 @@ impl<
546549
let new_ptr = const_try!(self.allocate(new_layout));
547550

548551
// Move the existing data into the new location
549-
debug_assert!(new_layout.size() >= old_size);
550-
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), old_size);
552+
core::ptr::copy_nonoverlapping(
553+
ptr.as_ptr(),
554+
new_ptr.as_ptr(),
555+
min_usize(old_size, new_layout.size()),
556+
);
551557

552558
// Deallocate the old memory block.
553559
self.deallocate(ptr, new_layout.align());

src/r3_core/src/utils/alloc/rlsf/flex/tests.rs

Lines changed: 14 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use quickcheck_macros::quickcheck;
2-
use std::{fmt, prelude::v1::*};
2+
use std::prelude::v1::*;
33

44
use super::super::{
55
tests::ShadowAllocator,
@@ -107,64 +107,6 @@ unsafe impl<T: FlexSource> FlexSource for TrackingFlexSource<T> {
107107
}
108108
}
109109

110-
/// Continuous-growing flex source
111-
struct CgFlexSource {
112-
pool: Vec<u8>,
113-
allocated: usize,
114-
}
115-
116-
impl fmt::Debug for CgFlexSource {
117-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118-
f.debug_struct("CgFlexSource")
119-
.field("allocated", &self.allocated)
120-
.finish()
121-
}
122-
}
123-
124-
impl TestFlexSource for CgFlexSource {
125-
type Options = u8;
126-
127-
fn new(offset: u8) -> Self {
128-
Self {
129-
pool: std::vec![0u8; 1024 * 32],
130-
allocated: offset as usize,
131-
}
132-
}
133-
}
134-
135-
unsafe impl FlexSource for CgFlexSource {
136-
unsafe fn alloc(&mut self, min_size: usize) -> Option<NonNull<[u8]>> {
137-
let allocated = self.allocated;
138-
let new_allocated = allocated
139-
.checked_add(min_size)
140-
.filter(|&x| x <= self.pool.len())?;
141-
142-
self.allocated = new_allocated;
143-
Some(NonNull::from(&mut self.pool[allocated..new_allocated]))
144-
}
145-
146-
unsafe fn realloc_inplace_grow(
147-
&mut self,
148-
ptr: NonNull<[u8]>,
149-
min_new_len: usize,
150-
) -> Option<usize> {
151-
self.alloc(min_new_len - nonnull_slice_len(ptr))
152-
.map(|s| nonnull_slice_len(s) + nonnull_slice_len(ptr))
153-
}
154-
155-
fn is_contiguous_growable(&self) -> bool {
156-
true
157-
}
158-
159-
fn supports_realloc_inplace_grow(&self) -> bool {
160-
true
161-
}
162-
163-
fn min_align(&self) -> usize {
164-
1
165-
}
166-
}
167-
168110
fn fill_data(p: NonNull<[u8]>) {
169111
use std::mem::MaybeUninit;
170112
let slice = unsafe { &mut *(p.as_ptr() as *mut [MaybeUninit<u8>]) };
@@ -199,62 +141,28 @@ macro_rules! gen_test {
199141
if let Some(ptr) = ptr {
200142
unsafe { tlsf.deallocate(ptr, 1) };
201143
}
202-
}
203-
204-
#[quickcheck]
205-
fn aadaadaraaadr(source_options: <$source as TestFlexSource>::Options) {
206-
let _ = env_logger::builder().is_test(true).try_init();
207-
208-
let mut tlsf = TheTlsf::new(TrackingFlexSource::new(source_options));
209-
210-
log::trace!("tlsf = {:?}", tlsf);
211144

212-
let ptr1 = tlsf.allocate(Layout::from_size_align(20, 16).unwrap());
213-
log::trace!("ptr1 = {:?}", ptr1);
214-
let ptr2 = tlsf.allocate(Layout::from_size_align(21, 1).unwrap());
215-
log::trace!("ptr2 = {:?}", ptr2);
216-
if let Some(ptr1) = ptr1 {
217-
unsafe { tlsf.deallocate(ptr1, 16) };
218-
}
219-
let ptr3 = tlsf.allocate(Layout::from_size_align(0, 32).unwrap());
220-
log::trace!("ptr3 = {:?}", ptr3);
221-
let ptr4 = tlsf.allocate(Layout::from_size_align(10, 8).unwrap());
222-
log::trace!("ptr4 = {:?}", ptr4);
223-
if let Some(ptr2) = ptr2 {
224-
unsafe { tlsf.deallocate(ptr2, 1) };
225-
log::trace!("deallocate(ptr2)");
226-
}
227-
let ptr5 = tlsf.allocate(Layout::from_size_align(12, 8).unwrap());
228-
log::trace!("ptr5 = {:?}", ptr5);
229-
let ptr3 = ptr3.and_then(|ptr3| unsafe {
230-
tlsf.reallocate(ptr3, Layout::from_size_align(0, 32).unwrap())
231-
});
232-
log::trace!("ptr3 = {:?}", ptr3);
233-
let ptr6 = tlsf.allocate(Layout::from_size_align(24, 2).unwrap());
234-
log::trace!("ptr6 = {:?}", ptr6);
235-
let ptr7 = tlsf.allocate(Layout::from_size_align(11, 16).unwrap());
236-
log::trace!("ptr7 = {:?}", ptr7);
237-
let ptr8 = tlsf.allocate(Layout::from_size_align(1, 32).unwrap());
238-
log::trace!("ptr8 = {:?}", ptr8);
239-
if let Some(ptr5) = ptr5 {
240-
unsafe { tlsf.deallocate(ptr5, 8) };
241-
log::trace!("deallocate(ptr5)");
242-
}
243-
let ptr3 = ptr3.and_then(|ptr3| unsafe {
244-
tlsf.reallocate(ptr3, Layout::from_size_align(4, 32).unwrap())
245-
});
246-
log::trace!("ptr3 = {:?}", ptr3);
145+
tlsf.destroy();
247146
}
248147

249148
#[quickcheck]
250149
fn random(source_options: <$source as TestFlexSource>::Options, max_alloc_size: usize, bytecode: Vec<u8>) {
251150
random_inner(source_options, max_alloc_size, bytecode);
252151
}
253152

153+
struct CleanOnDrop(Option<TheTlsf>);
154+
155+
impl Drop for CleanOnDrop {
156+
fn drop(&mut self) {
157+
self.0.take().unwrap().destroy();
158+
}
159+
}
160+
254161
fn random_inner(source_options: <$source as TestFlexSource>::Options, max_alloc_size: usize, bytecode: Vec<u8>) -> Option<()> {
255162
let max_alloc_size = max_alloc_size % 0x10000;
256163

257-
let mut tlsf = TheTlsf::new(TrackingFlexSource::new(source_options));
164+
let mut tlsf = CleanOnDrop(None);
165+
let tlsf = tlsf.0.get_or_insert_with(|| TheTlsf::new(TrackingFlexSource::new(source_options)));
258166
macro_rules! sa {
259167
() => {
260168
unsafe { tlsf.source_mut_unchecked() }.sa
@@ -281,7 +189,8 @@ macro_rules! gen_test {
281189
0,
282190
]);
283191
let len = ((len as u64 * max_alloc_size as u64) >> 24) as usize;
284-
let align = 1 << (it.next()? % 6);
192+
let align = 1 << (it.next()? % (ALIGN.trailing_zeros() as u8 + 1));
193+
assert!(align <= ALIGN);
285194
let layout = Layout::from_size_align(len, align).unwrap();
286195
log::trace!("alloc {:?}", layout);
287196

@@ -382,34 +291,3 @@ gen_test!(tlsf_sys_u64_u8_59_8, SysSource, u64, u64, 59, 8);
382291
gen_test!(tlsf_sys_u64_u8_60_8, SysSource, u64, u64, 60, 8);
383292
gen_test!(tlsf_sys_u64_u8_61_8, SysSource, u64, u64, 61, 8);
384293
gen_test!(tlsf_sys_u64_u8_64_8, SysSource, u64, u64, 64, 8);
385-
386-
gen_test!(tlsf_cg_u8_u8_1_1, CgFlexSource, u8, u8, 1, 1);
387-
gen_test!(tlsf_cg_u8_u8_1_2, CgFlexSource, u8, u8, 1, 2);
388-
gen_test!(tlsf_cg_u8_u8_1_4, CgFlexSource, u8, u8, 1, 4);
389-
gen_test!(tlsf_cg_u8_u8_1_8, CgFlexSource, u8, u8, 1, 8);
390-
gen_test!(tlsf_cg_u8_u8_3_4, CgFlexSource, u8, u8, 3, 4);
391-
gen_test!(tlsf_cg_u8_u8_5_4, CgFlexSource, u8, u8, 5, 4);
392-
gen_test!(tlsf_cg_u8_u8_8_1, CgFlexSource, u8, u8, 8, 1);
393-
gen_test!(tlsf_cg_u8_u8_8_8, CgFlexSource, u8, u8, 8, 8);
394-
gen_test!(tlsf_cg_u16_u8_3_4, CgFlexSource, u16, u8, 3, 4);
395-
gen_test!(tlsf_cg_u16_u8_11_4, CgFlexSource, u16, u8, 11, 4);
396-
gen_test!(tlsf_cg_u16_u8_16_4, CgFlexSource, u16, u8, 16, 4);
397-
gen_test!(tlsf_cg_u16_u16_3_16, CgFlexSource, u16, u16, 3, 16);
398-
gen_test!(tlsf_cg_u16_u16_11_16, CgFlexSource, u16, u16, 11, 16);
399-
gen_test!(tlsf_cg_u16_u16_16_16, CgFlexSource, u16, u16, 16, 16);
400-
gen_test!(tlsf_cg_u16_u32_3_16, CgFlexSource, u16, u32, 3, 16);
401-
gen_test!(tlsf_cg_u16_u32_11_16, CgFlexSource, u16, u32, 11, 16);
402-
gen_test!(tlsf_cg_u16_u32_16_16, CgFlexSource, u16, u32, 16, 16);
403-
gen_test!(tlsf_cg_u16_u32_3_32, CgFlexSource, u16, u32, 3, 32);
404-
gen_test!(tlsf_cg_u16_u32_11_32, CgFlexSource, u16, u32, 11, 32);
405-
gen_test!(tlsf_cg_u16_u32_16_32, CgFlexSource, u16, u32, 16, 32);
406-
gen_test!(tlsf_cg_u32_u32_20_32, CgFlexSource, u32, u32, 20, 32);
407-
gen_test!(tlsf_cg_u32_u32_27_32, CgFlexSource, u32, u32, 27, 32);
408-
gen_test!(tlsf_cg_u32_u32_28_32, CgFlexSource, u32, u32, 28, 32);
409-
gen_test!(tlsf_cg_u32_u32_29_32, CgFlexSource, u32, u32, 29, 32);
410-
gen_test!(tlsf_cg_u32_u32_32_32, CgFlexSource, u32, u32, 32, 32);
411-
gen_test!(tlsf_cg_u64_u8_58_8, CgFlexSource, u64, u64, 58, 8);
412-
gen_test!(tlsf_cg_u64_u8_59_8, CgFlexSource, u64, u64, 59, 8);
413-
gen_test!(tlsf_cg_u64_u8_60_8, CgFlexSource, u64, u64, 60, 8);
414-
gen_test!(tlsf_cg_u64_u8_61_8, CgFlexSource, u64, u64, 61, 8);
415-
gen_test!(tlsf_cg_u64_u8_64_8, CgFlexSource, u64, u64, 64, 8);

src/r3_core/src/utils/alloc/rlsf/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ macro_rules! const_try {
2525
};
2626
}
2727

28-
macro debug_assert_eq($x:expr, $y:expr) {
28+
macro debug_assert_eq($x:expr, $y:expr $(, $($tt:tt)*)?) {
2929
// FIXME: `*assert_eq!` is not usable in `const fn` yet
30-
debug_assert!($x == $y);
30+
debug_assert!($x == $y $(, $($tt)*)?);
3131
}
3232

33-
macro debug_assert_ne($x:expr, $y:expr) {
34-
// FIXME: `*assert_ne!` is not usable in `const fn` yet
35-
debug_assert!($x != $y);
33+
macro debug_assert_eq_ptr($x:expr, $y:expr $(, $($tt:tt)*)?) {
34+
// FIXME: `*assert_eq!` is not usable in `const fn` yet
35+
debug_assert!(!$x.guaranteed_ne($y) $(, $($tt)*)?);
3636
}
3737

3838
use crate::utils::Init;
@@ -43,7 +43,7 @@ mod tlsf;
4343
mod utils;
4444
pub use self::{
4545
flex::*,
46-
tlsf::{Tlsf, GRANULARITY},
46+
tlsf::{Tlsf, ALIGN, GRANULARITY},
4747
utils::nonnull_slice_from_raw_parts,
4848
};
4949

0 commit comments

Comments
 (0)