From 84a6702e004cbf1ffad2d50f8042e616331345dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Mon, 6 Jan 2025 18:26:23 +0900 Subject: [PATCH] feat(swc_parallel): Implement basic APIs (#9840) **Description:** Add basic APIs that can be used from other crates to make them parallel. --- .changeset/fifty-birds-cross.md | 5 ++ Cargo.lock | 3 +- crates/swc_parallel/Cargo.toml | 8 ++- crates/swc_parallel/src/lib.rs | 124 ++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 .changeset/fifty-birds-cross.md diff --git a/.changeset/fifty-birds-cross.md b/.changeset/fifty-birds-cross.md new file mode 100644 index 000000000000..b07fca8f17a8 --- /dev/null +++ b/.changeset/fifty-birds-cross.md @@ -0,0 +1,5 @@ +--- +swc_core: patch +--- + +feat(parallel): Implement basic APIs diff --git a/Cargo.lock b/Cargo.lock index c899e0eefd21..fb508e17255d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5925,9 +5925,10 @@ dependencies = [ [[package]] name = "swc_parallel" -version = "0.1.0" +version = "1.0.0" dependencies = [ "chili", + "once_cell", ] [[package]] diff --git a/crates/swc_parallel/Cargo.toml b/crates/swc_parallel/Cargo.toml index cb96549e7b8d..8ffa43e47609 100644 --- a/crates/swc_parallel/Cargo.toml +++ b/crates/swc_parallel/Cargo.toml @@ -6,11 +6,13 @@ include = ["Cargo.toml", "src/**/*.rs"] license = { workspace = true } name = "swc_parallel" repository = { workspace = true } -version = "0.1.0" +version = "1.0.0" [features] +default = ["parallel"] # Make it really parallel -parallel = [] +parallel = ["chili"] [dependencies] -chili = { workspace = true } +chili = { workspace = true, optional = true } +once_cell = { workspace = true } diff --git a/crates/swc_parallel/src/lib.rs b/crates/swc_parallel/src/lib.rs index 8b137891791f..ff60c8fe703f 100644 --- a/crates/swc_parallel/src/lib.rs +++ b/crates/swc_parallel/src/lib.rs @@ -1 +1,125 @@ +use std::{cell::RefCell, mem::transmute}; +#[derive(Default)] +pub struct MaybeScope<'a>(ScopeLike<'a>); + +enum ScopeLike<'a> { + Scope(Scope<'a>), + Global(Option>), +} + +impl Default for ScopeLike<'_> { + fn default() -> Self { + ScopeLike::Global(None) + } +} + +impl<'a> From> for MaybeScope<'a> { + fn from(value: Scope<'a>) -> Self { + MaybeScope(ScopeLike::Scope(value)) + } +} + +impl<'a> MaybeScope<'a> { + pub fn with(&mut self, f: F) -> R + where + F: FnOnce(Scope<'a>) -> R, + { + let scope: &mut chili::Scope = match &mut self.0 { + ScopeLike::Scope(scope) => unsafe { + transmute::<&mut chili::Scope, &mut chili::Scope>(&mut scope.0) + }, + ScopeLike::Global(global_scope) => { + let scope = global_scope.get_or_insert_with(|| chili::Scope::global()); + + unsafe { transmute::<&mut chili::Scope, &mut chili::Scope>(scope) } + } + }; + + let scope = Scope(scope); + + f(scope) + } +} + +#[cfg(not(feature = "parallel"))] +pub struct Scope<'a>(std::marker::PhantomData<&'a ()>); + +#[cfg(feature = "parallel")] +pub struct Scope<'a>(&'a mut chili::Scope<'a>); + +#[inline] +pub fn join(oper_a: A, oper_b: B) -> (RA, RB) +where + A: Send + FnOnce() -> RA, + B: Send + FnOnce() -> RB, + RA: Send, + RB: Send, +{ + thread_local! { + static SCOPE: RefCell>> = Default::default(); + } + + let mut scope = SCOPE.take().unwrap_or_default(); + + let (ra, rb) = join_maybe_scoped( + &mut scope, + |scope| { + let scope = unsafe { transmute::(scope) }; + SCOPE.set(Some(MaybeScope(ScopeLike::Scope(scope)))); + let ret = oper_a(); + SCOPE.set(None); + ret + }, + |scope| { + let scope = unsafe { transmute::(scope) }; + SCOPE.set(Some(MaybeScope(ScopeLike::Scope(scope)))); + let ret = oper_b(); + SCOPE.set(None); + ret + }, + ); + + SCOPE.set(Some(scope)); + + (ra, rb) +} + +#[inline] +pub fn join_maybe_scoped<'a, A, B, RA, RB>( + scope: &mut MaybeScope<'a>, + oper_a: A, + oper_b: B, +) -> (RA, RB) +where + A: Send + FnOnce(Scope<'a>) -> RA, + B: Send + FnOnce(Scope<'a>) -> RB, + RA: Send, + RB: Send, +{ + scope.with(|scope| join_scoped(scope, oper_a, oper_b)) +} + +#[inline] +pub fn join_scoped<'a, A, B, RA, RB>(scope: Scope<'a>, oper_a: A, oper_b: B) -> (RA, RB) +where + A: Send + FnOnce(Scope<'a>) -> RA, + B: Send + FnOnce(Scope<'a>) -> RB, + RA: Send, + RB: Send, +{ + let (ra, rb) = scope.0.join( + |scope| { + let scope = Scope(unsafe { transmute::<&mut chili::Scope, &mut chili::Scope>(scope) }); + + oper_a(scope) + }, + |scope| { + let scope = Scope(unsafe { transmute::<&mut chili::Scope, &mut chili::Scope>(scope) }); + + oper_b(scope) + }, + ); + + (ra, rb) +}