Skip to content

Commit

Permalink
feat(allocator): Implement default mode (#9242)
Browse files Browse the repository at this point in the history
**Description:**

In the default mode, `Box<T>` and `Vec<T>` should work just like them from std.

**Related issue:**

 - This PR is part of #9230
  • Loading branch information
kdy1 authored Jul 15, 2024
1 parent b37cdb3 commit b6333db
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 11 deletions.
8 changes: 5 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
// We use this to make IDE faster
"rust-analyzer",
"rkyv-impl",
"debug"
"debug",
"scoped"
],
"rust-analyzer.cargo.features": [
// We use this to make IDE faster
"rust-analyzer",
"rkyv-impl",
"debug"
"debug",
"scoped"
]
}
}
32 changes: 25 additions & 7 deletions crates/swc_allocator/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl Allocator {
impl Default for FastAlloc {
fn default() -> Self {
Self {
#[cfg(feature = "scoped")]
alloc: if let Some(v) = ALLOC.get() {
Some(v)
} else {
Expand All @@ -54,18 +55,26 @@ impl Default for FastAlloc {

impl FastAlloc {
/// `true` is passed to `f` if the box is allocated with a custom allocator.
#[cfg(feature = "scoped")]
fn with_allocator<T>(
&self,
f: impl FnOnce(&dyn allocator_api2::alloc::Allocator, bool) -> T,
) -> T {
if let Some(arena) = &self.alloc {
f(
return f(
(&&arena.alloc) as &dyn allocator_api2::alloc::Allocator,
true,
)
} else {
f(&allocator_api2::alloc::Global, false)
);
}

f(&allocator_api2::alloc::Global, false)
}

/// `true` is passed to `f` if the box is allocated with a custom allocator.
#[cfg(not(feature = "scoped"))]
#[inline(always)]
fn with_allocator<T>(&self, f: impl FnOnce(allocator_api2::alloc::Global, bool) -> T) -> T {
f(allocator_api2::alloc::Global, false)
}
}

Expand All @@ -74,6 +83,7 @@ fn mark_ptr_as_arena_mode(ptr: NonNull<[u8]>) -> NonNull<[u8]> {
}

unsafe impl allocator_api2::alloc::Allocator for FastAlloc {
#[inline]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, allocator_api2::alloc::AllocError> {
self.with_allocator(|a, is_arena_mode| {
let ptr = a.allocate(layout)?;
Expand All @@ -86,6 +96,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc {
})
}

#[inline]
fn allocate_zeroed(
&self,
layout: Layout,
Expand All @@ -101,19 +112,23 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc {
})
}

#[inline]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
#[cfg(feature = "scoped")]
if self.alloc.is_some() {
debug_assert!(
ALLOC.get().is_some(),
"Deallocating a pointer allocated with arena mode with a non-arena mode allocator"
);

self.with_allocator(|alloc, _| alloc.deallocate(ptr, layout))
} else {
Global.deallocate(ptr, layout)
self.with_allocator(|alloc, _| alloc.deallocate(ptr, layout));
return;
}

Global.deallocate(ptr, layout)
}

#[inline]
unsafe fn grow(
&self,
ptr: NonNull<u8>,
Expand All @@ -131,6 +146,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc {
})
}

#[inline]
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
Expand All @@ -148,6 +164,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc {
})
}

#[inline]
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
Expand All @@ -165,6 +182,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc {
})
}

#[inline(always)]
fn by_ref(&self) -> &Self
where
Self: Sized,
Expand Down
2 changes: 2 additions & 0 deletions crates/swc_allocator/src/boxed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,14 @@ impl<T: ?Sized> BorrowMut<T> for Box<T> {
impl<T: ?Sized> Deref for Box<T> {
type Target = T;

#[inline(always)]
fn deref(&self) -> &T {
&self.0
}
}

impl<T: ?Sized> DerefMut for Box<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
Expand Down
27 changes: 26 additions & 1 deletion crates/swc_allocator/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
//! Allocator for swc.
//!
//! API designed after [`oxc_allocator`](/~https://github.com/oxc-project/oxc/tree/725571aad193ec6ba779c820baeb4a7774533ed7/crates/oxc_allocator/src).
//! # Features
//!
//! - `scoped`: Enable `scoped` mode.
//!
//! # Modes
//!
//! ## Default mode
//!
//! In default mode, [crate::boxed::Box] and [crate::vec::Vec] are identical to
//! the original types in [std].
//!
//! ## Scoped mode
//!
//! - You need to enable `scoped` feature to use this mode.
//!
//! In `scoped` mode you can use [FastAlloc] to make [crate::boxed::Box] and
//! [crate::vec::Vec] very fast.
//!
//! In this mode, you need to be careful while using [crate::boxed::Box] and
//! [crate::vec::Vec]. Be sure to use same [Allocator] for allocation and
//! deallocation.
//!
//! Recommened way to use this mode is to wrap the whole operations in
//! a call to [Allocator::scope].
#![allow(clippy::needless_doctest_main)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(missing_docs)]
#![allow(clippy::derivable_impls)]

pub use crate::alloc::Allocator;

Expand Down Expand Up @@ -34,5 +58,6 @@ pub mod vec;
/// original types.
#[derive(Clone, Copy)]
pub struct FastAlloc {
#[cfg(feature = "scoped")]
alloc: Option<&'static Allocator>,
}
2 changes: 2 additions & 0 deletions crates/swc_allocator/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,14 @@ impl<T> Vec<T> {
impl<T> Deref for Vec<T> {
type Target = allocator_api2::vec::Vec<T, FastAlloc>;

#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<T> DerefMut for Vec<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
Expand Down

0 comments on commit b6333db

Please sign in to comment.