Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(allocator): Implement default mode #9242

Merged
merged 7 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading