From b6333dbcfcc8f25d08a1187704796732366ac9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Mon, 15 Jul 2024 18:53:09 +0900 Subject: [PATCH] feat(allocator): Implement `default` mode (#9242) **Description:** In the default mode, `Box` and `Vec` should work just like them from std. **Related issue:** - This PR is part of /~https://github.com/swc-project/swc/pull/9230 --- .vscode/settings.json | 8 ++++--- crates/swc_allocator/src/alloc.rs | 32 +++++++++++++++++++++------ crates/swc_allocator/src/boxed/mod.rs | 2 ++ crates/swc_allocator/src/lib.rs | 27 +++++++++++++++++++++- crates/swc_allocator/src/vec/mod.rs | 2 ++ 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2998e97898b6..db0001f6ee44 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" ] -} +} \ No newline at end of file diff --git a/crates/swc_allocator/src/alloc.rs b/crates/swc_allocator/src/alloc.rs index 70a5f578a017..91cd4397d0d4 100644 --- a/crates/swc_allocator/src/alloc.rs +++ b/crates/swc_allocator/src/alloc.rs @@ -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 { @@ -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( &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(&self, f: impl FnOnce(allocator_api2::alloc::Global, bool) -> T) -> T { + f(allocator_api2::alloc::Global, false) } } @@ -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, allocator_api2::alloc::AllocError> { self.with_allocator(|a, is_arena_mode| { let ptr = a.allocate(layout)?; @@ -86,6 +96,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { }) } + #[inline] fn allocate_zeroed( &self, layout: Layout, @@ -101,19 +112,23 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { }) } + #[inline] unsafe fn deallocate(&self, ptr: NonNull, 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, @@ -131,6 +146,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { }) } + #[inline] unsafe fn grow_zeroed( &self, ptr: NonNull, @@ -148,6 +164,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { }) } + #[inline] unsafe fn shrink( &self, ptr: NonNull, @@ -165,6 +182,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { }) } + #[inline(always)] fn by_ref(&self) -> &Self where Self: Sized, diff --git a/crates/swc_allocator/src/boxed/mod.rs b/crates/swc_allocator/src/boxed/mod.rs index 7e327f0af657..63b3ce8b681a 100644 --- a/crates/swc_allocator/src/boxed/mod.rs +++ b/crates/swc_allocator/src/boxed/mod.rs @@ -252,12 +252,14 @@ impl BorrowMut for Box { impl Deref for Box { type Target = T; + #[inline(always)] fn deref(&self) -> &T { &self.0 } } impl DerefMut for Box { + #[inline(always)] fn deref_mut(&mut self) -> &mut T { &mut self.0 } diff --git a/crates/swc_allocator/src/lib.rs b/crates/swc_allocator/src/lib.rs index 4f144571264c..5f36f29225df 100644 --- a/crates/swc_allocator/src/lib.rs +++ b/crates/swc_allocator/src/lib.rs @@ -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; @@ -34,5 +58,6 @@ pub mod vec; /// original types. #[derive(Clone, Copy)] pub struct FastAlloc { + #[cfg(feature = "scoped")] alloc: Option<&'static Allocator>, } diff --git a/crates/swc_allocator/src/vec/mod.rs b/crates/swc_allocator/src/vec/mod.rs index a25dd2409387..dfcd2bdf9b98 100644 --- a/crates/swc_allocator/src/vec/mod.rs +++ b/crates/swc_allocator/src/vec/mod.rs @@ -279,12 +279,14 @@ impl Vec { impl Deref for Vec { type Target = allocator_api2::vec::Vec; + #[inline(always)] fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for Vec { + #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }