From a31fb58399cc60ad5052d77b5accd560200a4f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 18 Jul 2024 23:03:58 +0900 Subject: [PATCH] feat(allocator): Feature gate `nightly` via macros (#9274) **Description:** We can make swc faster without dropping support for stable rustc. --- crates/swc_allocator/Cargo.toml | 9 +++-- crates/swc_allocator/src/alloc.rs | 26 ++++--------- crates/swc_allocator/src/lib.rs | 53 +++++++++++++++++++++++++++ crates/swc_common/src/eq.rs | 59 ++++++++++++++++-------------- crates/swc_common/src/pos.rs | 16 ++++---- crates/swc_common/src/util/take.rs | 24 ++++++------ 6 files changed, 120 insertions(+), 67 deletions(-) diff --git a/crates/swc_allocator/Cargo.toml b/crates/swc_allocator/Cargo.toml index 5ee7a7eeb3c5..8831e0ad437a 100644 --- a/crates/swc_allocator/Cargo.toml +++ b/crates/swc_allocator/Cargo.toml @@ -15,16 +15,17 @@ version = "0.1.6" [features] default = ["scoped"] +nightly = [] rkyv = ["dep:rkyv"] -scoped = [] -serde = ["dep:serde", "dep:serde_derive"] +scoped = ["nightly"] +serde = ["dep:serde", "dep:serde_derive", "allocator-api2/serde"] [dependencies] -allocator-api2 = { workspace = true, features = ["serde"] } +allocator-api2 = { workspace = true } bumpalo = { workspace = true, features = [ - "allocator-api2", "boxed", "collections", + "allocator-api2", ] } ptr_meta = { workspace = true } rkyv = { workspace = true, optional = true } diff --git a/crates/swc_allocator/src/alloc.rs b/crates/swc_allocator/src/alloc.rs index 94197fcc5fcd..2b8825695899 100644 --- a/crates/swc_allocator/src/alloc.rs +++ b/crates/swc_allocator/src/alloc.rs @@ -6,7 +6,7 @@ use std::{ ptr::NonNull, }; -use allocator_api2::alloc::Global; +use allocator_api2::alloc::AllocError; use bumpalo::Bump; use crate::FastAlloc; @@ -66,11 +66,11 @@ 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 { + #[cfg(feature = "scoped")] if let Some(arena) = &self.alloc { return f( (&&arena.alloc) as &dyn allocator_api2::alloc::Allocator, @@ -80,13 +80,6 @@ impl FastAlloc { 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) - } } fn mark_ptr_as_arena_mode(ptr: NonNull<[u8]>) -> NonNull<[u8]> { @@ -95,7 +88,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> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { self.with_allocator(|a, is_arena_mode| { let ptr = a.allocate(layout)?; @@ -108,10 +101,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { } #[inline] - fn allocate_zeroed( - &self, - layout: Layout, - ) -> Result, allocator_api2::alloc::AllocError> { + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { self.with_allocator(|a, is_arena_mode| { let ptr = a.allocate_zeroed(layout)?; @@ -131,7 +121,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { return; } - Global.deallocate(ptr, layout) + allocator_api2::alloc::Global.deallocate(ptr, layout) } #[inline] @@ -140,7 +130,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { ptr: NonNull, old_layout: Layout, new_layout: Layout, - ) -> Result, allocator_api2::alloc::AllocError> { + ) -> Result, AllocError> { self.with_allocator(|alloc, is_arena_mode| { let ptr = alloc.grow(ptr, old_layout, new_layout)?; @@ -158,7 +148,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { ptr: NonNull, old_layout: Layout, new_layout: Layout, - ) -> Result, allocator_api2::alloc::AllocError> { + ) -> Result, AllocError> { self.with_allocator(|alloc, is_arena_mode| { let ptr = alloc.grow_zeroed(ptr, old_layout, new_layout)?; @@ -176,7 +166,7 @@ unsafe impl allocator_api2::alloc::Allocator for FastAlloc { ptr: NonNull, old_layout: Layout, new_layout: Layout, - ) -> Result, allocator_api2::alloc::AllocError> { + ) -> Result, AllocError> { self.with_allocator(|alloc, is_arena_mode| { let ptr = alloc.shrink(ptr, old_layout, new_layout)?; diff --git a/crates/swc_allocator/src/lib.rs b/crates/swc_allocator/src/lib.rs index 5fd3f8e57faf..c56bde3c1339 100644 --- a/crates/swc_allocator/src/lib.rs +++ b/crates/swc_allocator/src/lib.rs @@ -27,13 +27,19 @@ #![allow(clippy::needless_doctest_main)] #![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr( + feature = "nightly", + feature(allocator_api, fundamental, with_negative_coherence) +)] #![deny(missing_docs)] #![allow(clippy::derivable_impls)] pub use crate::alloc::Allocator; mod alloc; +#[cfg(feature = "nightly")] pub mod boxed; +#[cfg(feature = "nightly")] pub mod vec; /// Fast allocator, effectively working as a cache. @@ -73,3 +79,50 @@ impl FastAlloc { } } } + +/// This expands to the given tokens if the `nightly` feature is enabled. +#[cfg(feature = "nightly")] +#[macro_export] +macro_rules! nightly_only { + ( + $($item:item)* + ) => { + $( + #[cfg_attr(docsrs, doc(cfg(feature = "nightly")))] + $item + )* + }; +} + +/// This expands to the given tokens if the `nightly` feature is enabled. +#[cfg(not(feature = "nightly"))] +#[macro_export] +macro_rules! nightly_only { + ( + $($item:item)* + ) => {}; +} + +/// Usage: `swc_allocator::Type!(Vec)` or `swc_allocator::Type!(Box)`. +#[macro_export] +macro_rules! Type { + (Box<$($tt:tt)*>) => { + #[cfg(feature = "nightly")] + $crate::boxed::Box<$crate::Type!($($tt)*)> + + #[cfg(not(feature = "nightly"))] + std::boxed::Box<$crate::Type!($($tt)*)> + }; + + (Vec<$($tt:tt)*>) => { + #[cfg(feature = "nightly")] + $crate::vec::Vec<$crate::Type!($($tt)*)> + + #[cfg(not(feature = "nightly"))] + std::vec::Vec<$crate::Type!($($tt)*)> + }; + + ($t:ty) => { + $t + }; +} diff --git a/crates/swc_common/src/eq.rs b/crates/swc_common/src/eq.rs index ffd615011b0b..a8d1c6ea93db 100644 --- a/crates/swc_common/src/eq.rs +++ b/crates/swc_common/src/eq.rs @@ -1,6 +1,7 @@ use std::{cell::RefCell, rc::Rc, sync::Arc}; use num_bigint::BigInt; +use swc_allocator::nightly_only; use crate::{BytePos, Span}; @@ -63,18 +64,20 @@ where } } -impl EqIgnoreSpan for swc_allocator::vec::Vec -where - T: EqIgnoreSpan, -{ - fn eq_ignore_span(&self, other: &Self) -> bool { - self.len() == other.len() - && self - .iter() - .zip(other.iter()) - .all(|(a, b)| a.eq_ignore_span(b)) +nightly_only!( + impl EqIgnoreSpan for swc_allocator::vec::Vec + where + T: EqIgnoreSpan, + { + fn eq_ignore_span(&self, other: &Self) -> bool { + self.len() == other.len() + && self + .iter() + .zip(other.iter()) + .all(|(a, b)| a.eq_ignore_span(b)) + } } -} +); /// Derive with `#[derive(TypeEq)]`. pub trait TypeEq { @@ -185,25 +188,27 @@ macro_rules! deref { deref!(Box, Rc, Arc); -impl EqIgnoreSpan for swc_allocator::boxed::Box -where - N: EqIgnoreSpan, -{ - #[inline] - fn eq_ignore_span(&self, other: &Self) -> bool { - (**self).eq_ignore_span(&**other) +swc_allocator::nightly_only!( + impl EqIgnoreSpan for swc_allocator::boxed::Box + where + N: EqIgnoreSpan, + { + #[inline] + fn eq_ignore_span(&self, other: &Self) -> bool { + (**self).eq_ignore_span(&**other) + } } -} -impl TypeEq for swc_allocator::boxed::Box -where - N: TypeEq, -{ - #[inline] - fn type_eq(&self, other: &Self) -> bool { - (**self).type_eq(&**other) + impl TypeEq for swc_allocator::boxed::Box + where + N: TypeEq, + { + #[inline] + fn type_eq(&self, other: &Self) -> bool { + (**self).type_eq(&**other) + } } -} +); impl<'a, N> EqIgnoreSpan for &'a N where diff --git a/crates/swc_common/src/pos.rs b/crates/swc_common/src/pos.rs index 07196bc52e9c..fbe997d4445f 100644 --- a/crates/swc_common/src/pos.rs +++ b/crates/swc_common/src/pos.rs @@ -191,11 +191,13 @@ where } } -impl Spanned for swc_allocator::boxed::Box -where - T: Spanned, -{ - fn span(&self) -> Span { - self.as_ref().span() +swc_allocator::nightly_only!( + impl Spanned for swc_allocator::boxed::Box + where + T: Spanned, + { + fn span(&self) -> Span { + self.as_ref().span() + } } -} +); diff --git a/crates/swc_common/src/util/take.rs b/crates/swc_common/src/util/take.rs index 376a987940f8..ae0672584321 100644 --- a/crates/swc_common/src/util/take.rs +++ b/crates/swc_common/src/util/take.rs @@ -55,17 +55,19 @@ impl Take for Span { } } -impl Take for swc_allocator::boxed::Box -where - T: Take, -{ - fn dummy() -> Self { - swc_allocator::boxed::Box::new(T::dummy()) +swc_allocator::nightly_only!( + impl Take for swc_allocator::boxed::Box + where + T: Take, + { + fn dummy() -> Self { + swc_allocator::boxed::Box::new(T::dummy()) + } } -} -impl Take for swc_allocator::vec::Vec { - fn dummy() -> Self { - Default::default() + impl Take for swc_allocator::vec::Vec { + fn dummy() -> Self { + Default::default() + } } -} +);