Skip to content

Commit 477d0fd

Browse files
committed
refactor(allocator/fixed-size)!: return Result from allocation instead of panicking
1 parent e2537db commit 477d0fd

File tree

2 files changed

+33
-9
lines changed

2 files changed

+33
-9
lines changed

crates/oxc_allocator/src/pool/fixed_size.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::{
2-
alloc::{self, GlobalAlloc, Layout, System},
2+
alloc::{GlobalAlloc, Layout, System},
3+
error::Error,
4+
fmt,
35
mem::{self, ManuallyDrop},
46
ptr::NonNull,
57
sync::{
@@ -15,6 +17,26 @@ use crate::{
1517
generated::fixed_size_constants::{BLOCK_ALIGN, BLOCK_SIZE, RAW_METADATA_SIZE},
1618
};
1719

20+
/// Error returned when a fixed-size allocator cannot be created due to allocation failure.
21+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22+
pub struct AllocError {
23+
/// The layout of the allocation that failed.
24+
pub layout: Layout,
25+
}
26+
27+
impl fmt::Display for AllocError {
28+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29+
write!(
30+
f,
31+
"memory allocation failed for fixed-size allocator: requested {} bytes with {} byte alignment",
32+
self.layout.size(),
33+
self.layout.align()
34+
)
35+
}
36+
}
37+
38+
impl Error for AllocError {}
39+
1840
const TWO_GIB: usize = 1 << 31;
1941
const FOUR_GIB: usize = 1 << 32;
2042

@@ -53,7 +75,7 @@ impl FixedSizeAllocatorPool {
5375
// Protect against IDs wrapping around.
5476
// TODO: Does this work? Do we need it anyway?
5577
assert!(id < u32::MAX, "Created too many allocators");
56-
FixedSizeAllocator::new(id)
78+
FixedSizeAllocator::try_new(id).unwrap()
5779
});
5880

5981
// Unwrap `FixedSizeAllocator`.
@@ -187,9 +209,11 @@ struct FixedSizeAllocator {
187209
}
188210

189211
impl FixedSizeAllocator {
190-
/// Create a new [`FixedSizeAllocator`].
212+
/// Try to create a new [`FixedSizeAllocator`].
213+
///
214+
/// Returns `Err(AllocError)` if memory allocation fails.
191215
#[expect(clippy::items_after_statements)]
192-
fn new(id: u32) -> Self {
216+
fn try_new(id: u32) -> Result<Self, AllocError> {
193217
// Only support little-endian systems. `Allocator::from_raw_parts` includes this same assertion.
194218
// This module is only compiled on 64-bit little-endian systems, so it should be impossible for
195219
// this panic to occur. But we want to make absolutely sure that if there's a mistake elsewhere,
@@ -203,9 +227,7 @@ impl FixedSizeAllocator {
203227
// Allocate block of memory.
204228
// SAFETY: `ALLOC_LAYOUT` does not have zero size.
205229
let alloc_ptr = unsafe { System.alloc(ALLOC_LAYOUT) };
206-
let Some(alloc_ptr) = NonNull::new(alloc_ptr) else {
207-
alloc::handle_alloc_error(ALLOC_LAYOUT);
208-
};
230+
let alloc_ptr = NonNull::new(alloc_ptr).ok_or(AllocError { layout: ALLOC_LAYOUT })?;
209231

210232
// All code in the rest of this function is infallible, so the allocation will always end up
211233
// owned by a `FixedSizeAllocator`, which takes care of freeing the memory correctly on drop
@@ -254,7 +276,7 @@ impl FixedSizeAllocator {
254276
metadata_ptr.write(metadata);
255277
}
256278

257-
Self { allocator }
279+
Ok(Self { allocator })
258280
}
259281

260282
/// Reset this [`FixedSizeAllocator`].

crates/oxc_allocator/src/pool/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ impl AllocatorPool {
6666
///
6767
/// # Panics
6868
///
69-
/// Panics if the underlying mutex is poisoned.
69+
/// * Panics if the underlying mutex is poisoned.
70+
/// * Panics if a new allocator needs to be created but memory allocation fails
71+
/// (only applies to fixed-size allocators).
7072
pub fn get(&self) -> AllocatorGuard<'_> {
7173
let allocator = match &self.0 {
7274
AllocatorPoolInner::Standard(pool) => pool.get(),

0 commit comments

Comments
 (0)