diff --git a/Cargo.lock b/Cargo.lock index a80a5ee62b5..e32b0b4d406 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -958,12 +958,6 @@ dependencies = [ "syn", ] -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1549,9 +1543,9 @@ dependencies = [ [[package]] name = "mimalloc-rust" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc30df9dfdb5bb6cb2470de65ca604c3eaa3e5dc2ad02a9a98f567df5844472" +checksum = "6973866e0bc6504c03a16b6817b7e70839cc8a1dbd5d6dab00c65d8034868d8b" dependencies = [ "cty", "mimalloc-rust-sys", @@ -1559,9 +1553,9 @@ dependencies = [ [[package]] name = "mimalloc-rust-sys" -version = "1.7.3-source" +version = "1.7.6-source" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3adc8731262b982f4e0860770dba118305cafe1b2e7ebe95b29b2c2f46a70666" +checksum = "7a50daf45336b979a202a19f53b4b382f2c4bd50f392a8dbdb4c6c56ba5dfa64" dependencies = [ "cc", "cty", @@ -3407,6 +3401,7 @@ dependencies = [ "backtrace", "criterion", "indexmap", + "num_cpus", "once_cell", "parking_lot", "pretty_assertions", @@ -4023,7 +4018,6 @@ name = "swc_node_base" version = "0.5.5" dependencies = [ "mimalloc-rust", - "tikv-jemallocator", ] [[package]] @@ -4339,27 +4333,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tikv-jemalloc-sys" -version = "0.4.3+5.2.1-patched.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1792ccb507d955b46af42c123ea8863668fae24d03721e40cad6a41773dbb49" -dependencies = [ - "cc", - "fs_extra", - "libc", -] - -[[package]] -name = "tikv-jemallocator" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b7bcecfafe4998587d636f9ae9d55eb9d0499877b88757767c346875067098" -dependencies = [ - "libc", - "tikv-jemalloc-sys", -] - [[package]] name = "time" version = "0.1.43" diff --git a/Cargo.toml b/Cargo.toml index 1812d382823..7562d53239a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ members = [ ] [profile.release] -codegen-units = 1 +lto = true # We use CARGO_PROFILE_RELEASE_LTO for production builds # lto = "fat" @@ -32,7 +32,7 @@ codegen-units = 1 # opt-level = 'z' [profile.bench] -codegen-units = 1 +lto = true debug = true # Without this, printing diff consumes more than a minute. @@ -44,5 +44,5 @@ opt-level = 3 opt-level = 3 [patch.crates-io] -cranelift-codegen = {git = "https://github.com/kdy1/wasmtime", branch = "tls"} -cranelift-entity = {git = "https://github.com/kdy1/wasmtime", branch = "tls"} +cranelift-codegen = { git = "https://github.com/kdy1/wasmtime", branch = "tls" } +cranelift-entity = { git = "https://github.com/kdy1/wasmtime", branch = "tls" } diff --git a/crates/swc_ecma_minifier/Cargo.toml b/crates/swc_ecma_minifier/Cargo.toml index b51b24e7685..ac15dfab439 100644 --- a/crates/swc_ecma_minifier/Cargo.toml +++ b/crates/swc_ecma_minifier/Cargo.toml @@ -25,6 +25,7 @@ ahash = "0.7.6" arrayvec = "0.7.2" backtrace = { version = "0.3.61", optional = true } indexmap = "1.7.0" +num_cpus = "1.13.1" once_cell = "1.10.0" parking_lot = "0.12.0" pretty_assertions = { version = "1.1", optional = true } diff --git a/crates/swc_ecma_minifier/src/analyzer/mod.rs b/crates/swc_ecma_minifier/src/analyzer/mod.rs index c7d2c8850d7..211d1d79616 100644 --- a/crates/swc_ecma_minifier/src/analyzer/mod.rs +++ b/crates/swc_ecma_minifier/src/analyzer/mod.rs @@ -1,4 +1,6 @@ -use rustc_hash::{FxHashMap, FxHashSet}; +use std::{collections::HashSet, hash::BuildHasherDefault}; + +use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; use swc_atoms::{js_word, JsWord}; use swc_common::{collections::AHashSet, SyntaxContext}; use swc_ecma_ast::*; @@ -163,35 +165,41 @@ pub(crate) struct ProgramData { impl ProgramData { pub(crate) fn expand_infected( &self, - ids: impl IntoIterator, + ids: FxHashSet, max_num: usize, ) -> Result, ()> { - let mut result = FxHashSet::default(); - self.expand_infected_inner(ids, max_num, &mut result)?; - Ok(result) - } - - fn expand_infected_inner( - &self, - ids: impl IntoIterator, - max_num: usize, - result: &mut FxHashSet, - ) -> Result<(), ()> { - for id in ids { - if !result.insert(id.clone()) { - continue; + let init = + HashSet::with_capacity_and_hasher(max_num, BuildHasherDefault::::default()); + ids.into_iter().try_fold(init, |mut res, id| { + let mut ids = Vec::with_capacity(max_num); + ids.push(id); + let mut ranges = vec![0..1usize]; + loop { + let range = ranges.remove(0); + for index in range { + let iid = ids.get(index).unwrap(); + if !res.insert(iid.clone()) { + continue; + } + if res.len() >= max_num { + return Err(()); + } + if let Some(info) = self.vars.get(iid) { + let infects = &info.infects; + if !infects.is_empty() { + let old_len = ids.len(); + ids.extend_from_slice(infects.as_slice()); + let new_len = ids.len(); + ranges.push(old_len..new_len); + } + } + } + if ranges.is_empty() { + break; + } } - if result.len() >= max_num { - return Err(()); - } - - if let Some(info) = self.vars.get(&id) { - let ids = info.infects.clone(); - self.expand_infected_inner(ids, max_num, result)?; - } - } - - Ok(()) + Ok(res) + }) } pub(crate) fn contains_unresolved(&self, e: &Expr) -> bool { @@ -633,7 +641,8 @@ where e.visit_children_with(&mut *self.with_ctx(ctx)); if let Expr::Ident(i) = e { - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { // debug!( // "Usage: `{}``; update = {:?}, assign_lhs = {:?} ", // i, diff --git a/crates/swc_ecma_minifier/src/compress/hoist_decls.rs b/crates/swc_ecma_minifier/src/compress/hoist_decls.rs index 229ed5eb8d7..9e6a0bf631a 100644 --- a/crates/swc_ecma_minifier/src/compress/hoist_decls.rs +++ b/crates/swc_ecma_minifier/src/compress/hoist_decls.rs @@ -1,3 +1,4 @@ +use rayon::prelude::*; use swc_common::{collections::AHashSet, pass::Repeated, util::take::Take, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_utils::{find_pat_ids, StmtLike}; @@ -6,7 +7,7 @@ use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith}; use super::util::drop_invalid_stmts; use crate::{ analyzer::{ProgramData, UsageAnalyzer}, - util::{is_hoisted_var_decl_without_init, sort::is_sorted_by_key, IsModuleItem, ModuleItemExt}, + util::{is_hoisted_var_decl_without_init, sort::is_sorted_by, IsModuleItem, ModuleItemExt}, }; pub(super) struct DeclHoisterConfig { @@ -46,33 +47,43 @@ impl Hoister<'_> { Vec: for<'aa> VisitMutWith> + VisitWith, { stmts.visit_mut_children_with(self); + let len = stmts.len(); + let should_hoist = !is_sorted_by( + stmts.iter().map(|stmt| match stmt.as_stmt() { + Some(stmt) => match stmt { + Stmt::Decl(Decl::Fn(..)) if self.config.hoist_fns => 1, + Stmt::Decl(Decl::Var(var)) if self.config.hoist_vars => { + let ids: Vec = find_pat_ids(&var.decls); - let should_hoist = !is_sorted_by_key(stmts.iter(), |stmt| match stmt.as_stmt() { - Some(stmt) => match stmt { - Stmt::Decl(Decl::Fn(..)) if self.config.hoist_fns => 1, - Stmt::Decl(Decl::Var(var)) if self.config.hoist_vars => { - let ids: Vec = find_pat_ids(&var.decls); - - if ids.iter().any(|id| { - self.data - .vars - .get(id) - .map(|v| !v.used_above_decl) - .unwrap_or(false) - }) { - 2 - } else { - 3 + if ids.iter().any(|id| { + self.data + .vars + .get(id) + .map(|v| !v.used_above_decl) + .unwrap_or(false) + }) { + 2 + } else { + 3 + } } - } - _ => 3, - }, - None => 3, - }) || (self.config.hoist_vars - && stmts.windows(2).any(|stmts| { - is_hoisted_var_decl_without_init(&stmts[0]) - && is_hoisted_var_decl_without_init(&stmts[1]) - })); + _ => 3, + }, + None => 3, + }), + PartialOrd::partial_cmp, + ) || (self.config.hoist_vars + && if len >= *crate::LIGHT_TASK_PARALLELS { + stmts.par_chunks(2).any(|stmts| { + is_hoisted_var_decl_without_init(&stmts[0]) + && is_hoisted_var_decl_without_init(&stmts[1]) + }) + } else { + stmts.windows(2).any(|stmts| { + is_hoisted_var_decl_without_init(&stmts[0]) + && is_hoisted_var_decl_without_init(&stmts[1]) + }) + }); if !should_hoist { return; diff --git a/crates/swc_ecma_minifier/src/compress/mod.rs b/crates/swc_ecma_minifier/src/compress/mod.rs index 6ee0b33379c..38a83895509 100644 --- a/crates/swc_ecma_minifier/src/compress/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/mod.rs @@ -1,8 +1,9 @@ +#[cfg(feature = "debug")] +use std::thread; use std::{ borrow::Cow, fmt, fmt::{Debug, Display, Formatter, Write}, - thread, time::Instant, }; @@ -31,6 +32,7 @@ use crate::{ compress::hoist_decls::decl_hoister, debug::{dump, AssertValid}, marks::Marks, + maybe_par, mode::Mode, option::CompressOptions, util::{now, unit::CompileUnit, Optional}, @@ -107,14 +109,17 @@ where Vec: VisitMutWith + for<'aa> VisitMutWith>, { // Skip if `use asm` exists. - if stmts.iter().any(|stmt| match stmt.as_stmt() { - Some(Stmt::Expr(stmt)) => match &*stmt.expr { - // TODO improve check, directives can contain escaped characters - Expr::Lit(Lit::Str(Str { value, .. })) => &**value == "use asm", + if maybe_par!( + stmts.iter().any(|stmt| match stmt.as_stmt() { + Some(Stmt::Expr(stmt)) => match &*stmt.expr { + // TODO improve check, directives can contain escaped characters + Expr::Lit(Lit::Str(Str { value, .. })) => &**value == "use asm", + _ => false, + }, _ => false, - }, - _ => false, - }) { + }), + *crate::LIGHT_TASK_PARALLELS + ) { return; } @@ -262,12 +267,11 @@ where } } - let start = if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + let start = { let start = n.dump(); debug!("===== Start =====\n{}", start); start - } else { - String::new() }; { @@ -284,7 +288,8 @@ where self.changed |= visitor.changed(); if visitor.changed() { debug!("compressor: Simplified expressions"); - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { debug!("===== Simplified =====\n{}", dump(&*n, false)); } } @@ -299,7 +304,8 @@ where ); } - if cfg!(feature = "debug") && !visitor.changed() { + #[cfg(feature = "debug")] + if !visitor.changed() { let simplified = n.dump(); if start != simplified { assert_eq!( @@ -322,6 +328,7 @@ where PureOptimizerConfig { enable_join_vars: self.pass > 1, force_str_for_tpl: M::force_str_for_tpl(), + #[cfg(feature = "debug")] debug_infinite_loop: self.pass >= 20, }, ); @@ -329,13 +336,15 @@ where self.changed |= visitor.changed(); - if cfg!(feature = "debug") && visitor.changed() { + #[cfg(feature = "debug")] + if visitor.changed() { let src = n.dump(); debug!("===== After pure =====\n{}\n{}", start, src); } } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { n.visit_with(&mut AssertValid); } @@ -364,11 +373,8 @@ where } if self.options.conditionals || self.options.dead_code { - let start = if cfg!(feature = "debug") { - dump(&*n, false) - } else { - "".into() - }; + #[cfg(feature = "debug")] + let start = dump(&*n, false); let start_time = now(); @@ -385,7 +391,8 @@ where ); } - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { let simplified = dump(&*n, false); if start != simplified { diff --git a/crates/swc_ecma_minifier/src/compress/optimize/arguments.rs b/crates/swc_ecma_minifier/src/compress/optimize/arguments.rs index 43468da47d9..984169b0bf5 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/arguments.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/arguments.rs @@ -90,10 +90,13 @@ where { // If a function has a variable named `arguments`, we abort. let data: Vec = find_pat_ids(&f.body); - for id in &data { + if data.iter().any(|id| { if id.0 == js_word!("arguments") { - return; + return true; } + false + }) { + return; } } diff --git a/crates/swc_ecma_minifier/src/compress/optimize/bools.rs b/crates/swc_ecma_minifier/src/compress/optimize/bools.rs index 1e203dce855..de554befdb9 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/bools.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/bools.rs @@ -7,9 +7,10 @@ use swc_ecma_utils::{ }; use super::Optimizer; +#[cfg(feature = "debug")] +use crate::debug::dump; use crate::{ compress::{optimize::Ctx, util::negate_cost}, - debug::dump, mode::Mode, }; @@ -67,6 +68,7 @@ where "bools: Negating: (!a && !b) => !(a || b) (because both expression are good for \ negation)", ); + #[cfg(feature = "debug")] let start = dump(&*e, false); e.op = if e.op == op!("&&") { diff --git a/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs b/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs index ea93a828a04..e0252c3b972 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs @@ -504,7 +504,7 @@ where let mut args = vec![]; if cons.args.as_ref().map(|v| v.len()).unwrap_or(0) == 1 { - args.push(ExprOrSpread { + args = vec![ExprOrSpread { spread: None, expr: Box::new(Expr::Cond(CondExpr { span: DUMMY_SP, @@ -512,7 +512,7 @@ where cons: cons.args.as_mut().unwrap()[0].expr.take(), alt: alt.args.as_mut().unwrap()[0].expr.take(), })), - }); + }]; } report_change!( @@ -715,10 +715,8 @@ where return; } // - - let mut new_stmts = vec![]; - - for stmt in stmts.take() { + let mut new_stmts = Vec::with_capacity(stmts.len() * 2); + stmts.take().into_iter().for_each(|stmt| { match stmt.try_into_stmt() { Ok(stmt) => match stmt { Stmt::If(IfStmt { @@ -753,7 +751,7 @@ where }, Err(stmt) => new_stmts.push(stmt), } - } + }); self.changed = true; report_change!("conditionals: Dropped useless `else` token"); diff --git a/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs b/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs index dc2c732b6a8..276f8c40340 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs @@ -6,7 +6,7 @@ use swc_ecma_ast::*; use swc_ecma_utils::{undefined, ExprExt, Value::Known}; use super::Optimizer; -use crate::{compress::util::eval_as_number, mode::Mode, DISABLE_BUGGY_PASSES}; +use crate::{compress::util::eval_as_number, maybe_par, mode::Mode, DISABLE_BUGGY_PASSES}; /// Methods related to the option `evaluate`. impl Optimizer<'_, M> @@ -399,12 +399,12 @@ where match (ln.classify(), rn.classify()) { (FpCategory::Zero, FpCategory::Zero) => { // If a variable named `NaN` is in scope, don't convert e into NaN. - if self - .data - .vars - .iter() - .any(|(name, v)| v.declared && name.0 == js_word!("NaN")) - { + let data = &self.data.vars; + if maybe_par!( + data.iter() + .any(|(name, v)| v.declared && name.0 == js_word!("NaN")), + *crate::LIGHT_TASK_PARALLELS + ) { return; } diff --git a/crates/swc_ecma_minifier/src/compress/optimize/if_return.rs b/crates/swc_ecma_minifier/src/compress/optimize/if_return.rs index 4ef0addb5f6..29b4849f76f 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/if_return.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/if_return.rs @@ -4,7 +4,9 @@ use swc_ecma_utils::{undefined, StmtExt, StmtLike}; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; use super::Optimizer; -use crate::{compress::util::is_pure_undefined, debug::dump, mode::Mode, util::ExprOptExt}; +#[cfg(feature = "debug")] +use crate::debug::dump; +use crate::{compress::util::is_pure_undefined, mode::Mode, util::ExprOptExt}; /// Methods related to the option `if_return`. All methods are noop if /// `if_return` is false. diff --git a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs index 368576b9779..aefa49a458f 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs @@ -13,9 +13,10 @@ use super::{ util::{MultiReplacer, MultiReplacerMode}, Optimizer, }; +#[cfg(feature = "debug")] +use crate::debug::dump; use crate::{ compress::optimize::{util::Remapper, Ctx}, - debug::dump, mode::Mode, util::{idents_captured_by, idents_used_by, make_number}, }; diff --git a/crates/swc_ecma_minifier/src/compress/optimize/inline.rs b/crates/swc_ecma_minifier/src/compress/optimize/inline.rs index 667d26cdfb7..bc4172c7739 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/inline.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/inline.rs @@ -6,7 +6,6 @@ use swc_ecma_utils::{find_pat_ids, ExprExt, IdentUsageFinder}; use super::Optimizer; use crate::{ compress::optimize::util::{class_has_side_effect, is_valid_for_lhs}, - debug::dump, mode::Mode, util::{idents_captured_by, idents_used_by, idents_used_by_ignoring_nested}, }; @@ -32,7 +31,7 @@ where trace_op!( "inline: store_var_for_inlining({}, should_preserve = {:?})", - dump(&var.name, false), + crate::debug::dump(&var.name, false), should_preserve ); @@ -66,7 +65,7 @@ where if should_preserve && usage.var_kind != Some(VarDeclKind::Const) { log_abort!( "inline: [x] Preserving non-const variable `{}` because it's top-level", - dump(&var.name, false) + crate::debug::dump(&var.name, false) ); return; } @@ -606,6 +605,7 @@ where } self.changed = true; + #[cfg(feature = "debug")] match &decl { Decl::Class(c) => { report_change!( @@ -711,7 +711,7 @@ where *e = *value; - log_abort!("inline: [Change] {}", dump(&*e, false)) + log_abort!("inline: [Change] {}", crate::debug::dump(&*e, false)) } } } diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs index a4b38254514..9deddc01695 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs @@ -14,6 +14,7 @@ use swc_ecma_utils::{ Type, Value, }; use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith}; +#[cfg(feature = "debug")] use tracing::{debug, span, Level}; use Value::Known; @@ -22,11 +23,14 @@ use self::{ util::{MultiReplacer, MultiReplacerMode}, }; use super::util::{drop_invalid_stmts, is_fine_for_if_cons}; +#[cfg(feature = "debug")] +use crate::debug::dump; use crate::{ analyzer::{ProgramData, UsageAnalyzer}, compress::util::is_pure_undefined, - debug::{dump, AssertValid}, + debug::AssertValid, marks::Marks, + maybe_par, mode::Mode, option::CompressOptions, util::{ @@ -224,6 +228,7 @@ struct Optimizer<'a, M> { mode: &'a M, + #[allow(unused)] debug_infinite_loop: bool, functions: FxHashMap, @@ -351,10 +356,12 @@ where // Don't set in_strict for directive itself. stmt.visit_mut_with(self); } else { - stmt.visit_mut_with(&mut *self.with_ctx(child_ctx)); + let child_optimizer = &mut *self.with_ctx(child_ctx); + stmt.visit_mut_with(child_optimizer); } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmt.visit_with(&mut AssertValid); } @@ -379,43 +386,50 @@ where self.ctx.in_asm |= use_asm; - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.reorder_stmts(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.merge_sequences_in_stmts(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.merge_similar_ifs(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.make_sequences(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.drop_else_token(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.break_assignments_in_seqs(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } @@ -978,6 +992,7 @@ where span, left, right, + #[cfg(feature = "debug")] op, .. }) => { @@ -1194,11 +1209,11 @@ where } if let Stmt::Block(block) = &mut bs.stmts[0] { - if block - .stmts - .iter() - .all(|stmt| !matches!(stmt, Stmt::Decl(..))) - { + let stmts = &block.stmts; + if maybe_par!( + stmts.iter().all(|stmt| !matches!(stmt, Stmt::Decl(..))), + *crate::LIGHT_TASK_PARALLELS + ) { report_change!("optimizer: Removing nested block"); self.changed = true; bs.stmts = block.stmts.take(); @@ -1540,7 +1555,12 @@ where #[cfg_attr(feature = "debug", tracing::instrument(skip_all))] fn visit_mut_decl(&mut self, decl: &mut Decl) { - decl.visit_mut_children_with(self); + match decl { + Decl::Class(class_decl) => self.visit_mut_class(&mut class_decl.class), + Decl::Fn(fn_decl) => self.visit_mut_fn_decl(fn_decl), + Decl::Var(var_decl) => self.visit_mut_var_decl(var_decl), + _ => decl.visit_mut_children_with(self), + }; self.drop_unused_decl(decl); self.store_typeofs(decl); @@ -1682,7 +1702,7 @@ where } #[cfg(feature = "trace-ast")] - debug!("Output: {}", dump(e, true)); + tracing::debug!("Output: {}", dump(e, true)); } #[cfg_attr(feature = "debug", tracing::instrument(skip_all))] @@ -1770,7 +1790,8 @@ where } } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { n.visit_with(&mut AssertValid); } } @@ -1903,7 +1924,8 @@ where if let Some(body) = n.body.as_mut() { // Bypass block scope handler. body.visit_mut_children_with(optimizer); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { body.visit_with(&mut AssertValid); } } @@ -1925,7 +1947,8 @@ where drop_invalid_stmts(&mut body.stmts); } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { n.visit_with(&mut AssertValid); } } @@ -2107,7 +2130,8 @@ where } } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { n.visit_with(&mut AssertValid); } } @@ -2189,7 +2213,8 @@ where let old_prepend = self.prepend_stmts.take(); let old_append = self.append_stmts.take(); - let _tracing = if cfg!(feature = "debug") && self.debug_infinite_loop { + #[cfg(feature = "debug")] + let _tracing = if self.debug_infinite_loop { let text = dump(&*s, false); if text.lines().count() < 10 { @@ -2228,7 +2253,8 @@ where _ => {} } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { s.visit_with(&mut AssertValid); } } @@ -2274,7 +2300,8 @@ where .collect(), }); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { s.visit_with(&mut AssertValid); } } @@ -2284,7 +2311,8 @@ where let len = self.prepend_stmts.len(); - if cfg!(feature = "debug") && self.debug_infinite_loop { + #[cfg(feature = "debug")] + if self.debug_infinite_loop { let text = dump(&*s, false); if text.lines().count() < 10 { @@ -2343,7 +2371,8 @@ where debug_assert_eq!(self.prepend_stmts.len(), len); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { s.visit_with(&mut AssertValid); } @@ -2369,7 +2398,8 @@ where debug_assert_eq!(self.prepend_stmts.len(), len); - if cfg!(feature = "debug") && self.debug_infinite_loop { + #[cfg(feature = "debug")] + if self.debug_infinite_loop { let text = dump(&*s, false); if text.lines().count() < 10 { @@ -2379,7 +2409,8 @@ where debug_assert_eq!(self.prepend_stmts.len(), len); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { s.visit_with(&mut AssertValid); } @@ -2388,15 +2419,18 @@ where fn visit_mut_stmts(&mut self, stmts: &mut Vec) { // Skip if `use asm` exists. - if stmts.iter().any(|stmt| match stmt.as_stmt() { - Some(Stmt::Expr(stmt)) => match &*stmt.expr { - Expr::Lit(Lit::Str(Str { raw, .. })) => { - matches!(raw, Some(value) if value == "\"use asm\"" || value == "'use asm'") - } + if maybe_par!( + stmts.iter().any(|stmt| match stmt.as_stmt() { + Some(Stmt::Expr(stmt)) => match &*stmt.expr { + Expr::Lit(Lit::Str(Str { raw, .. })) => { + matches!(raw, Some(value) if value == "\"use asm\"" || value == "'use asm'") + } + _ => false, + }, _ => false, - }, - _ => false, - }) { + }), + *crate::LIGHT_TASK_PARALLELS + ) { return; } @@ -2420,7 +2454,8 @@ where } } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } } diff --git a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs index 249b355c8a1..72fdeeb7e9a 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs @@ -10,16 +10,18 @@ use swc_ecma_utils::{ StmtLike, }; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; +#[cfg(feature = "debug")] use tracing::{span, Level}; use super::{is_pure_undefined, Optimizer}; +#[cfg(feature = "debug")] +use crate::debug::dump; use crate::{ alias::{collect_infects_from, AliasConfig}, compress::{ optimize::{unused::PropertyAccessOpts, util::replace_id_with_expr}, util::{is_directive, is_ident_used_by, replace_expr}, }, - debug::dump, mode::Mode, option::CompressOptions, util::{idents_used_by, idents_used_by_ignoring_nested, ExprOptExt, ModuleItemExt}, @@ -641,7 +643,8 @@ where exprs.push(buf); - let _tracing = if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + let _tracing = { let buf_len = exprs.iter().map(|v| v.len()).collect::>(); Some( tracing::span!( @@ -651,8 +654,6 @@ where ) .entered(), ) - } else { - None }; for mut exprs in exprs { @@ -711,7 +712,8 @@ where pub(super) fn merge_sequences_in_seq_expr(&mut self, e: &mut SeqExpr) { self.normalize_sequences(e); - let _tracing = if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + let _tracing = { let e_str = dump(&*e, false); Some( @@ -722,8 +724,6 @@ where ) .entered(), ) - } else { - None }; if !self.options.sequences() && !e.span.has_mark(self.marks.synthesized_seq) { @@ -752,13 +752,12 @@ where /// TODO(kdy1): Check for side effects and call merge_sequential_expr more /// if expressions between a and b are side-effect-free. fn merge_sequences_in_exprs(&mut self, exprs: &mut Vec) -> Result<(), ()> { - let _tracing = if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + let _tracing = { Some( tracing::span!(Level::TRACE, "merge_sequences_in_exprs", len = exprs.len()) .entered(), ) - } else { - None }; for idx in 0..exprs.len() { @@ -1207,7 +1206,8 @@ where /// /// Returns [Err] iff we should stop checking. fn merge_sequential_expr(&mut self, a: &mut Mergable, b: &mut Expr) -> Result { - let _tracing = if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + let _tracing = { let b_str = dump(&*b, false); let a_id = a.id(); @@ -1220,8 +1220,6 @@ where ) .entered(), ) - } else { - None }; match a { @@ -1578,6 +1576,7 @@ where _ => {} } + #[cfg(feature = "debug")] match a { Mergable::Var(a) => { trace_op!( diff --git a/crates/swc_ecma_minifier/src/compress/optimize/unused.rs b/crates/swc_ecma_minifier/src/compress/optimize/unused.rs index 2c42dfbe44d..ee82c34e8ed 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/unused.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/unused.rs @@ -4,11 +4,12 @@ use swc_ecma_ast::*; use swc_ecma_utils::contains_ident_ref; use super::Optimizer; +#[cfg(feature = "debug")] +use crate::debug::dump; use crate::{ compress::{ optimize::util::class_has_side_effect, util::is_global_var_with_pure_property_access, }, - debug::dump, mode::Mode, option::PureGetterOption, }; @@ -55,6 +56,7 @@ where } } + #[cfg(debug_assertions)] let had_init = var.init.is_some(); match &mut var.init { @@ -88,7 +90,8 @@ where return; } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { if let Some(VarDeclKind::Const | VarDeclKind::Let) = self.ctx.var_kind { if had_init && var.init.is_none() { unreachable!("const/let variable without initializer: {:#?}", var); diff --git a/crates/swc_ecma_minifier/src/compress/optimize/util.rs b/crates/swc_ecma_minifier/src/compress/optimize/util.rs index 6eac9a68fa0..d2b384d6611 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/util.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/util.rs @@ -34,9 +34,9 @@ where } /// RAII guard to change context temporarically - #[inline] pub(super) fn with_ctx(&mut self, ctx: Ctx) -> WithCtx<'_, 'b, M> { - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { let scope_ctxt = ctx.scope; if self.ctx.scope != scope_ctxt { self.data.scopes.get(&scope_ctxt).expect("scope not found"); @@ -250,7 +250,8 @@ impl VisitMut for MultiReplacer<'_> { items.visit_mut_children_with(self); if !self.changed { - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { let keys = self.vars.iter().map(|(k, _)| k.clone()).collect::>(); debug!("Dropping {:?}", keys); } diff --git a/crates/swc_ecma_minifier/src/compress/pure/bools.rs b/crates/swc_ecma_minifier/src/compress/pure/bools.rs index bdcdf620790..8642cfcd80d 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/bools.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/bools.rs @@ -164,6 +164,7 @@ impl Pure<'_> { let can_remove = if *op == op!("&&") { rb } else { !rb }; if can_remove { + #[allow(clippy::if_same_then_else)] if *op == op!("&&") { report_change!("booleans: Compressing `!foo && true` as `!foo`"); } else { diff --git a/crates/swc_ecma_minifier/src/compress/pure/conds.rs b/crates/swc_ecma_minifier/src/compress/pure/conds.rs index a24368e364b..92a91d14731 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/conds.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/conds.rs @@ -5,7 +5,9 @@ use swc_ecma_ast::*; use swc_ecma_utils::{ExprExt, Type, Value}; use super::Pure; -use crate::{compress::util::negate_cost, debug::dump, util::make_bool}; +#[cfg(feature = "debug")] +use crate::debug::dump; +use crate::{compress::util::negate_cost, util::make_bool}; impl Pure<'_> { /// @@ -130,6 +132,7 @@ impl Pure<'_> { } report_change!("conditionals: `a ? foo : bar` => `!a ? bar : foo` (considered cost)"); + #[cfg(feature = "debug")] let start_str = dump(&*cond, false); self.negate(&mut cond.test, true, false); diff --git a/crates/swc_ecma_minifier/src/compress/pure/ctx.rs b/crates/swc_ecma_minifier/src/compress/pure/ctx.rs index 4b97c027cdd..068cca300c4 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/ctx.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/ctx.rs @@ -29,7 +29,6 @@ pub(super) struct Ctx { impl<'b> Pure<'b> { /// RAII guard to change context temporarically - #[inline] pub(super) fn with_ctx(&mut self, ctx: Ctx) -> WithCtx<'_, 'b> { let orig_ctx = self.ctx; self.ctx = ctx; diff --git a/crates/swc_ecma_minifier/src/compress/pure/dead_code.rs b/crates/swc_ecma_minifier/src/compress/pure/dead_code.rs index 2ae492434c8..f9035893bbd 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/dead_code.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/dead_code.rs @@ -1,10 +1,11 @@ +use rayon::prelude::*; use swc_common::{util::take::Take, EqIgnoreSpan, Spanned, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_utils::{extract_var_ids, ExprExt, StmtExt, StmtLike, Value}; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; use super::Pure; -use crate::{compress::util::is_fine_for_if_cons, util::ModuleItemExt}; +use crate::{compress::util::is_fine_for_if_cons, maybe_par, util::ModuleItemExt}; /// Methods related to option `dead_code`. impl Pure<'_> { @@ -229,29 +230,34 @@ impl Pure<'_> { report_change!("Dropping statements after a control keyword"); - let mut new_stmts = Vec::with_capacity(stmts.len()); - let mut decls = vec![]; - let mut hoisted_fns = vec![]; + let stmts_len = stmts.len(); // Hoist function and `var` declarations above return. - stmts - .iter_mut() - .skip(idx + 1) - .for_each(|stmt| match stmt.take().try_into_stmt() { - Ok(Stmt::Decl(Decl::Fn(f))) => { - hoisted_fns.push(Stmt::Decl(Decl::Fn(f)).into()); - } - Ok(t) => { - let ids = extract_var_ids(&t).into_iter().map(|i| VarDeclarator { - span: i.span, - name: i.into(), - init: None, - definite: false, - }); - decls.extend(ids); - } - Err(item) => new_stmts.push(item), - }); + let (decls, hoisted_fns, mut new_stmts) = stmts.iter_mut().skip(idx + 1).fold( + ( + Vec::with_capacity(stmts_len), + Vec::::with_capacity(stmts_len), + Vec::with_capacity(stmts_len), + ), + |(mut decls, mut hoisted_fns, mut new_stmts), stmt| { + match stmt.take().try_into_stmt() { + Ok(Stmt::Decl(Decl::Fn(f))) => { + hoisted_fns.push(Stmt::Decl(Decl::Fn(f)).into()); + } + Ok(t) => { + let ids = extract_var_ids(&t).into_iter().map(|i| VarDeclarator { + span: i.span, + name: i.into(), + init: None, + definite: false, + }); + decls.extend(ids); + } + Err(item) => new_stmts.push(item), + }; + (decls, hoisted_fns, new_stmts) + }, + ); if !decls.is_empty() { new_stmts.push( @@ -380,34 +386,58 @@ impl Pure<'_> { T: StmtLike, { fn is_ok(b: &BlockStmt) -> bool { - b.stmts.iter().all(is_fine_for_if_cons) + maybe_par!( + b.stmts.iter().all(is_fine_for_if_cons), + *crate::LIGHT_TASK_PARALLELS + ) } - if stmts - .iter() - .all(|stmt| !matches!(stmt.as_stmt(), Some(Stmt::Block(b)) if is_ok(b))) - { + if maybe_par!( + stmts + .iter() + .all(|stmt| !matches!(stmt.as_stmt(), Some(Stmt::Block(b)) if is_ok(b))), + *crate::LIGHT_TASK_PARALLELS + ) { return; } self.changed = true; report_change!("Dropping useless block"); - let mut new = vec![]; - for stmt in stmts.take() { - match stmt.try_into_stmt() { - Ok(v) => match v { - Stmt::Block(v) if is_ok(&v) => { - new.extend(v.stmts.into_iter().map(T::from_stmt)); - } - _ => new.push(T::from_stmt(v)), - }, - Err(v) => { - new.push(v); - } - } - } + let old_stmts = stmts.take(); + let new: Vec = if old_stmts.len() >= *crate::LIGHT_TASK_PARALLELS { + old_stmts + .into_par_iter() + .flat_map(|stmt| match stmt.try_into_stmt() { + Ok(v) => match v { + Stmt::Block(v) if is_ok(&v) => { + let stmts = v.stmts; + maybe_par!( + stmts.into_iter().map(T::from_stmt).collect(), + *crate::LIGHT_TASK_PARALLELS + ) + } + _ => vec![T::from_stmt(v)], + }, + Err(v) => vec![v], + }) + .collect() + } else { + let mut new = Vec::with_capacity(old_stmts.len() * 2); + old_stmts + .into_iter() + .for_each(|stmt| match stmt.try_into_stmt() { + Ok(v) => match v { + Stmt::Block(v) if is_ok(&v) => { + new.extend(v.stmts.into_iter().map(T::from_stmt)); + } + _ => new.push(T::from_stmt(v)), + }, + Err(v) => new.push(v), + }); + new + }; *stmts = new; } @@ -437,20 +467,24 @@ impl Pure<'_> { return; } - if !stmts.iter().any(|stmt| match stmt.as_stmt() { - Some(Stmt::If(s)) => s.test.cast_to_bool(&self.expr_ctx).1.is_known(), - _ => false, - }) { + if !maybe_par!( + stmts.iter().any(|stmt| match stmt.as_stmt() { + Some(Stmt::If(s)) => s.test.cast_to_bool(&self.expr_ctx).1.is_known(), + _ => false, + }), + *crate::LIGHT_TASK_PARALLELS + ) { return; } self.changed = true; report_change!("dead_code: Removing dead codes"); - let mut new = vec![]; - - for stmt in stmts.take() { - match stmt.try_into_stmt() { + let mut new = Vec::with_capacity(stmts.len()); + stmts + .take() + .into_iter() + .for_each(|stmt| match stmt.try_into_stmt() { Ok(stmt) => match stmt { Stmt::If(mut s) => { if let Value::Known(v) = s.test.cast_to_bool(&self.expr_ctx).1 { @@ -462,14 +496,16 @@ impl Pure<'_> { if v { if let Some(alt) = s.alt.take() { - var_ids.extend(alt.extract_var_ids().into_iter().map(|name| { - VarDeclarator { + var_ids = alt + .extract_var_ids() + .into_iter() + .map(|name| VarDeclarator { span: DUMMY_SP, name: Pat::Ident(name.into()), init: None, definite: Default::default(), - } - })); + }) + .collect(); } if !var_ids.is_empty() { new.push(T::from_stmt(Stmt::Decl(Decl::Var(VarDecl { @@ -481,14 +517,17 @@ impl Pure<'_> { } new.push(T::from_stmt(*s.cons.take())); } else { - var_ids.extend(s.cons.extract_var_ids().into_iter().map(|name| { - VarDeclarator { + var_ids = s + .cons + .extract_var_ids() + .into_iter() + .map(|name| VarDeclarator { span: DUMMY_SP, name: Pat::Ident(name.into()), init: None, definite: Default::default(), - } - })); + }) + .collect(); if !var_ids.is_empty() { new.push(T::from_stmt(Stmt::Decl(Decl::Var(VarDecl { span: DUMMY_SP, @@ -502,14 +541,13 @@ impl Pure<'_> { } } } else { - new.push(T::from_stmt(Stmt::If(s))) + new.push(T::from_stmt(Stmt::If(s))); } } _ => new.push(T::from_stmt(stmt)), }, Err(stmt) => new.push(stmt), - } - } + }); *stmts = new; } diff --git a/crates/swc_ecma_minifier/src/compress/pure/if_return.rs b/crates/swc_ecma_minifier/src/compress/pure/if_return.rs index d9b75e02413..6c7f7d15824 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/if_return.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/if_return.rs @@ -85,8 +85,8 @@ impl Pure<'_> { "if_return: Negating `foo` in `if (foo) return; bar()` to make it `if (!foo) bar()`" ); - let mut new = vec![]; - let mut fn_decls = vec![]; + let mut new = Vec::with_capacity(stmts.len()); + let mut fn_decls = Vec::with_capacity(stmts.len()); new.extend(stmts.drain(..pos_of_if)); let cons = stmts .drain(1..) diff --git a/crates/swc_ecma_minifier/src/compress/pure/misc.rs b/crates/swc_ecma_minifier/src/compress/pure/misc.rs index a916b4309ec..e1821c50428 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/misc.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/misc.rs @@ -647,7 +647,6 @@ impl Pure<'_> { })) } - #[inline(never)] pub(super) fn ignore_return_value(&mut self, e: &mut Expr, opts: DropOpts) { self.optimize_expr_in_bool_ctx(e, true); diff --git a/crates/swc_ecma_minifier/src/compress/pure/mod.rs b/crates/swc_ecma_minifier/src/compress/pure/mod.rs index 75bafd74d8d..e804a4eac44 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/mod.rs @@ -5,16 +5,15 @@ use swc_common::{pass::Repeated, util::take::Take, SyntaxContext, DUMMY_SP, GLOB use swc_ecma_ast::*; use swc_ecma_utils::{undefined, ExprCtx}; use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith}; +#[cfg(feature = "debug")] use tracing::{debug, span, Level}; use self::{ctx::Ctx, misc::DropOpts}; +#[cfg(feature = "debug")] +use crate::debug::dump; use crate::{ - analyzer::ProgramData, - debug::{dump, AssertValid}, - marks::Marks, - option::CompressOptions, - util::ModuleItemExt, - MAX_PAR_DEPTH, + analyzer::ProgramData, debug::AssertValid, marks::Marks, maybe_par, option::CompressOptions, + util::ModuleItemExt, MAX_PAR_DEPTH, }; mod arrows; @@ -40,6 +39,8 @@ pub(crate) struct PureOptimizerConfig { pub enable_join_vars: bool, pub force_str_for_tpl: bool, + + #[cfg(feature = "debug")] pub debug_infinite_loop: bool, } @@ -101,32 +102,37 @@ impl Pure<'_> { { self.remove_dead_branch(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.drop_unreachable_stmts(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.drop_useless_blocks(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } self.collapse_vars_without_init(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } if self.config.enable_join_vars { self.join_vars(stmts); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { stmts.visit_with(&mut AssertValid); } } @@ -174,29 +180,50 @@ impl Pure<'_> { self.changed |= v.changed; } } else { - GLOBALS.with(|globals| { - let changed = nodes - .par_iter_mut() - .map(|node| { - GLOBALS.set(globals, || { - let mut v = Pure { - expr_ctx: self.expr_ctx.clone(), - ctx: Ctx { - par_depth: self.ctx.par_depth + 1, - ..self.ctx - }, - changed: false, - ..*self - }; - node.visit_mut_with(&mut v); + let mut changed = false; + if nodes.len() >= *crate::HEAVY_TASK_PARALLELS { + GLOBALS.with(|globals| { + changed = nodes + .par_iter_mut() + .map(|node| { + GLOBALS.set(globals, || { + let mut v = Pure { + expr_ctx: self.expr_ctx.clone(), + ctx: Ctx { + par_depth: self.ctx.par_depth + 1, + ..self.ctx + }, + changed: false, + ..*self + }; + node.visit_mut_with(&mut v); - v.changed + v.changed + }) }) - }) - .reduce(|| false, |a, b| a || b); + .reduce(|| false, |a, b| a || b); + }) + } else { + changed = nodes + .iter_mut() + .map(|node| { + let mut v = Pure { + expr_ctx: self.expr_ctx.clone(), + ctx: Ctx { + par_depth: self.ctx.par_depth + 1, + ..self.ctx + }, + changed: false, + ..*self + }; + node.visit_mut_with(&mut v); - self.changed |= changed; - }); + v.changed + }) + .reduce(|a, b| a || b) + .unwrap_or(false); + } + self.changed |= changed; } } } @@ -217,7 +244,8 @@ impl VisitMut for Pure<'_> { } fn visit_mut_bin_expr(&mut self, e: &mut BinExpr) { - e.visit_mut_children_with(self); + self.visit_mut_expr(&mut e.left); + self.visit_mut_expr(&mut e.right); self.compress_cmp_with_long_op(e); @@ -545,7 +573,8 @@ impl VisitMut for Pure<'_> { self.optimize_arrow_method_prop(p); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { p.visit_with(&mut AssertValid); } } @@ -570,7 +599,11 @@ impl VisitMut for Pure<'_> { fn visit_mut_seq_expr(&mut self, e: &mut SeqExpr) { e.visit_mut_children_with(self); - if e.exprs.iter().any(|e| e.is_seq()) { + let exprs = &e.exprs; + if maybe_par!( + exprs.iter().any(|e| e.is_seq()), + *crate::LIGHT_TASK_PARALLELS + ) { let mut exprs = vec![]; for e in e.exprs.take() { @@ -620,13 +653,15 @@ impl VisitMut for Pure<'_> { e.exprs.retain(|e| !e.is_invalid()); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { e.visit_with(&mut AssertValid); } } fn visit_mut_stmt(&mut self, s: &mut Stmt) { - let _tracing = if cfg!(feature = "debug") && self.config.debug_infinite_loop { + #[cfg(feature = "debug")] + let _tracing = if self.config.debug_infinite_loop { let text = dump(&*s, false); if text.lines().count() < 10 { @@ -649,7 +684,8 @@ impl VisitMut for Pure<'_> { s.visit_mut_children_with(&mut *self.with_ctx(ctx)); } - if cfg!(feature = "debug") && self.config.debug_infinite_loop { + #[cfg(feature = "debug")] + if self.config.debug_infinite_loop { let text = dump(&*s, false); if text.lines().count() < 10 { @@ -683,7 +719,8 @@ impl VisitMut for Pure<'_> { } } - if cfg!(feature = "debug") && self.config.debug_infinite_loop { + #[cfg(feature = "debug")] + if self.config.debug_infinite_loop { let text = dump(&*s, false); if text.lines().count() < 10 { @@ -691,7 +728,8 @@ impl VisitMut for Pure<'_> { } } - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { s.visit_with(&mut AssertValid); } } @@ -717,7 +755,8 @@ impl VisitMut for Pure<'_> { items.retain(|s| !matches!(s, Stmt::Empty(..))); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { items.visit_with(&mut AssertValid); } } diff --git a/crates/swc_ecma_minifier/src/compress/pure/vars.rs b/crates/swc_ecma_minifier/src/compress/pure/vars.rs index c6e1c026613..d6bf0944c22 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/vars.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/vars.rs @@ -57,14 +57,13 @@ impl Pure<'_> { self.changed = true; let mut cur: Option = None; - let mut new = vec![]; - for stmt in stmts.take() { + let mut new: Vec = Vec::with_capacity(stmts.len() * 2 + 1); + stmts.take().into_iter().for_each(|stmt| { match stmt.try_into_stmt() { Ok(stmt) => { if is_directive(&stmt) { - new.push(T::from_stmt(stmt)); - continue; + return new.push(T::from_stmt(stmt)); } match stmt { @@ -73,11 +72,10 @@ impl Pure<'_> { v.decls.extend(var.decls); } _ => { - new.extend( - cur.take().map(Decl::Var).map(Stmt::Decl).map(T::from_stmt), - ); - - cur = Some(var) + if let Some(s) = cur.take().map(|c| Stmt::Decl(Decl::Var(c))) { + new.push(T::from_stmt(s)); + } + cur = Some(var); } }, Stmt::For(mut stmt) => match &mut stmt.init { @@ -86,22 +84,23 @@ impl Pure<'_> { kind: VarDeclKind::Var, .. }, - )) => match &mut cur { - Some(cur) if cur.kind == var.kind => { - // Merge - cur.decls.append(&mut var.decls); - var.decls = cur.decls.take(); + )) => { + match &mut cur { + Some(cur) if cur.kind == var.kind => { + // Merge + cur.decls.append(&mut var.decls); + var.decls = cur.decls.take(); - new.push(T::from_stmt(Stmt::For(stmt))) + new.push(T::from_stmt(Stmt::For(stmt))); + } + _ => { + if let Some(s) = cur.take() { + new.push(T::from_stmt(Stmt::Decl(Decl::Var(s)))); + } + new.push(T::from_stmt(Stmt::For(stmt))); + } } - _ => { - new.extend( - cur.take().map(Decl::Var).map(Stmt::Decl).map(T::from_stmt), - ); - - new.push(T::from_stmt(Stmt::For(stmt))) - } - }, + } None if cur .as_ref() .map(|v| v.kind == VarDeclKind::Var) @@ -112,32 +111,35 @@ impl Pure<'_> { .and_then(|v| if v.decls.is_empty() { None } else { Some(v) }) .map(VarDeclOrExpr::VarDecl); - new.push(T::from_stmt(Stmt::For(stmt))) + new.push(T::from_stmt(Stmt::For(stmt))); } _ => { - new.extend( - cur.take().map(Decl::Var).map(Stmt::Decl).map(T::from_stmt), - ); - - new.push(T::from_stmt(Stmt::For(stmt))) + if let Some(s) = cur.take() { + new.push(T::from_stmt(Stmt::Decl(Decl::Var(s)))); + } + new.push(T::from_stmt(Stmt::For(stmt))); } }, _ => { - new.extend(cur.take().map(Decl::Var).map(Stmt::Decl).map(T::from_stmt)); - - new.push(T::from_stmt(stmt)) + if let Some(s) = cur.take() { + new.push(T::from_stmt(Stmt::Decl(Decl::Var(s)))); + } + new.push(T::from_stmt(stmt)); } } } Err(item) => { - new.extend(cur.take().map(Decl::Var).map(Stmt::Decl).map(T::from_stmt)); - + if let Some(s) = cur.take() { + new.push(T::from_stmt(Stmt::Decl(Decl::Var(s)))); + } new.push(item); } } - } + }); - new.extend(cur.take().map(Decl::Var).map(Stmt::Decl).map(T::from_stmt)); + if let Some(s) = cur.take() { + new.push(T::from_stmt(Stmt::Decl(Decl::Var(s)))); + } drop_invalid_stmts(&mut new); @@ -160,11 +162,10 @@ impl Pure<'_> { } { + let mut need_work = false; let mut found_vars_without_init = false; let mut found_other = false; - let mut need_work = false; - - for stmt in &*stmts { + let if_need_work = stmts.iter().any(|stmt| { match stmt.as_stmt() { Some(Stmt::Decl(Decl::Var( v @ VarDecl { @@ -172,7 +173,9 @@ impl Pure<'_> { .. }, ))) => { - if v.decls.iter().all(|v| v.init.is_none()) { + if !(found_other && found_vars_without_init) + && v.decls.iter().all(|v| v.init.is_none()) + { if found_other { need_work = true; } @@ -198,12 +201,13 @@ impl Pure<'_> { found_other = true; } } - } + need_work + }); // Check for nested variable declartions. let mut v = VarWithOutInitCounter::default(); stmts.visit_with(&mut v); - if !need_work && !v.need_work { + if !if_need_work && !v.need_work { return; } } @@ -372,15 +376,15 @@ impl VisitMut for VarMover { let has_init = d.iter().any(|v| v.init.is_some()); if has_init { - let mut new = vec![]; + let mut new = Vec::with_capacity(d.len()); - for v in d.take() { + d.take().into_iter().for_each(|v| { if v.init.is_some() { new.push(v) } else { self.vars.push(v) } - } + }); *d = new; } @@ -391,13 +395,13 @@ impl VisitMut for VarMover { new.append(&mut self.vars); } - for v in d.take() { + d.take().into_iter().for_each(|v| { if v.init.is_some() { new.push(v) } else { self.vars.push(v) } - } + }); *d = new; } diff --git a/crates/swc_ecma_minifier/src/compress/util/mod.rs b/crates/swc_ecma_minifier/src/compress/util/mod.rs index d3a481e744e..b41303d3d0b 100644 --- a/crates/swc_ecma_minifier/src/compress/util/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/util/mod.rs @@ -3,15 +3,19 @@ use std::f64; use swc_atoms::js_word; use swc_common::{util::take::Take, DUMMY_SP}; use swc_ecma_ast::*; +#[cfg(feature = "debug")] use swc_ecma_transforms_base::fixer::fixer; use swc_ecma_utils::{ExprCtx, ExprExt, IdentUsageFinder, Value}; +#[cfg(feature = "debug")] +use swc_ecma_visit::{as_folder, FoldWith}; use swc_ecma_visit::{ - as_folder, noop_visit_mut_type, noop_visit_type, FoldWith, Visit, VisitMut, VisitMutWith, - VisitWith, + noop_visit_mut_type, noop_visit_type, Visit, VisitMut, VisitMutWith, VisitWith, }; use unicode_id::UnicodeID; -use crate::{debug::dump, util::ModuleItemExt}; +#[cfg(feature = "debug")] +use crate::debug::dump; +use crate::util::ModuleItemExt; #[cfg(test)] mod tests; @@ -40,6 +44,7 @@ fn negate_inner( in_bool_ctx: bool, is_ret_val_ignored: bool, ) -> bool { + #[cfg(feature = "debug")] let start_str = dump(&*e, false); match e { @@ -225,7 +230,8 @@ pub(crate) fn is_ok_to_negate_rhs(expr_ctx: &ExprCtx, rhs: &Expr) -> bool { return true; } - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { tracing::warn!( "unimplemented: is_ok_to_negate_rhs: `{}`", dump(&*rhs, false) @@ -239,6 +245,7 @@ pub(crate) fn is_ok_to_negate_rhs(expr_ctx: &ExprCtx, rhs: &Expr) -> bool { /// A negative value means that it's efficient to negate the expression. #[cfg_attr(feature = "debug", tracing::instrument(skip(e)))] +#[allow(clippy::let_and_return)] pub(crate) fn negate_cost( expr_ctx: &ExprCtx, e: &Expr, @@ -359,7 +366,8 @@ pub(crate) fn negate_cost( })(); // Print more info while testing negate_cost - if cfg!(test) { + #[cfg(test)] + { trace_op!( "negation cost of `{}` = {}", dump(&e.clone().fold_with(&mut as_folder(fixer(None))), true), diff --git a/crates/swc_ecma_minifier/src/debug.rs b/crates/swc_ecma_minifier/src/debug.rs index 2891c013789..447d3c061dc 100644 --- a/crates/swc_ecma_minifier/src/debug.rs +++ b/crates/swc_ecma_minifier/src/debug.rs @@ -41,7 +41,8 @@ where N: swc_ecma_codegen::Node + Clone + VisitMutWith + VisitMutWith, { if !force { - if !cfg!(feature = "debug") { + #[cfg(not(feature = "debug"))] + { return String::new(); } } @@ -71,7 +72,8 @@ where /// If the cargo feature `debug` is disabled or the environment variable /// `SWC_RUN` is not `1`, this function is noop. pub(crate) fn invoke(module: &Module) { - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { module.visit_with(&mut AssertValid); } diff --git a/crates/swc_ecma_minifier/src/eval.rs b/crates/swc_ecma_minifier/src/eval.rs index 63845598fa2..3d090552e3c 100644 --- a/crates/swc_ecma_minifier/src/eval.rs +++ b/crates/swc_ecma_minifier/src/eval.rs @@ -239,6 +239,7 @@ impl Evaluator { PureOptimizerConfig { enable_join_vars: false, force_str_for_tpl: Eval::force_str_for_tpl(), + #[cfg(feature = "debug")] debug_infinite_loop: false, }, )); diff --git a/crates/swc_ecma_minifier/src/lib.rs b/crates/swc_ecma_minifier/src/lib.rs index 5bf1204f0b8..888aeb7536e 100644 --- a/crates/swc_ecma_minifier/src/lib.rs +++ b/crates/swc_ecma_minifier/src/lib.rs @@ -28,6 +28,7 @@ use compress::{pure_optimizer, PureOptimizerConfig}; use mode::Mode; +use once_cell::sync::Lazy; use swc_common::{comments::Comments, pass::Repeat, sync::Lrc, SourceMap, GLOBALS}; use swc_ecma_ast::Module; use swc_ecma_visit::{FoldWith, VisitMutWith}; @@ -67,7 +68,10 @@ mod util; const DISABLE_BUGGY_PASSES: bool = true; const MAX_PAR_DEPTH: u8 = 3; -#[inline] +pub(crate) static CPU_COUNT: Lazy = Lazy::new(num_cpus::get); +pub(crate) static HEAVY_TASK_PARALLELS: Lazy = Lazy::new(|| *CPU_COUNT * 8); +pub(crate) static LIGHT_TASK_PARALLELS: Lazy = Lazy::new(|| *CPU_COUNT * 100); + pub fn optimize( mut m: Module, _cm: Lrc, @@ -163,6 +167,7 @@ pub fn optimize( PureOptimizerConfig { force_str_for_tpl: Minification::force_str_for_tpl(), enable_join_vars: true, + #[cfg(feature = "debug")] debug_infinite_loop: false, }, ))); @@ -194,9 +199,6 @@ pub fn optimize( if let Some(ref mut t) = timings { t.section("hygiene"); - } - - if let Some(ref mut t) = timings { t.end_section(); } diff --git a/crates/swc_ecma_minifier/src/macros.rs b/crates/swc_ecma_minifier/src/macros.rs index be5d07fc522..8ab7d0b5de8 100644 --- a/crates/swc_ecma_minifier/src/macros.rs +++ b/crates/swc_ecma_minifier/src/macros.rs @@ -1,6 +1,7 @@ /// Used when something is modified. macro_rules! report_change { ($($tt:tt)+) => {{ + #[cfg(feature = "debug")] tracing::debug!( kind = "change", $($tt)* @@ -11,7 +12,8 @@ macro_rules! report_change { /// Used when a function decided to give up. macro_rules! log_abort { ($($tt:tt)+) => {{ - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { tracing::trace!( kind = "abort", $($tt)* @@ -22,7 +24,8 @@ macro_rules! log_abort { macro_rules! dump_change_detail { ($($tt:tt)+) => {{ - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { tracing::trace!( kind = "detail", $($tt)* @@ -33,7 +36,8 @@ macro_rules! dump_change_detail { macro_rules! trace_op { ($($tt:tt)+) => {{ - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { tracing::trace!( $($tt)* ); diff --git a/crates/swc_ecma_minifier/src/pass/global_defs.rs b/crates/swc_ecma_minifier/src/pass/global_defs.rs index 6632c7e27e5..062ab4a8dda 100644 --- a/crates/swc_ecma_minifier/src/pass/global_defs.rs +++ b/crates/swc_ecma_minifier/src/pass/global_defs.rs @@ -79,7 +79,6 @@ impl VisitMut for GlobalDefs { n.visit_mut_children_with(self); } - #[inline] fn visit_mut_update_expr(&mut self, e: &mut UpdateExpr) { match &mut *e.arg { Expr::Ident(..) => {} diff --git a/crates/swc_ecma_minifier/src/pass/mangle_names/analyzer/mod.rs b/crates/swc_ecma_minifier/src/pass/mangle_names/analyzer/mod.rs index 6439ac2d1ab..0e46164cfa3 100644 --- a/crates/swc_ecma_minifier/src/pass/mangle_names/analyzer/mod.rs +++ b/crates/swc_ecma_minifier/src/pass/mangle_names/analyzer/mod.rs @@ -3,6 +3,7 @@ use swc_atoms::JsWord; use swc_common::collections::AHashMap; use swc_ecma_ast::*; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; +#[cfg(feature = "debug")] use tracing::trace; use self::scope::Scope; @@ -47,17 +48,18 @@ impl Analyzer { } fn add_decl(&mut self, id: Id) { - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { trace!("add_decl({:?})", id); } self.scope.add_decl(&id); } fn add_usage(&mut self, id: Id) { - if cfg!(feature = "debug") { + #[cfg(feature = "debug")] + { trace!("add_usage({:?})", id); } - self.scope.add_usage(&id); } diff --git a/crates/swc_ecma_minifier/src/pass/mangle_names/analyzer/scope.rs b/crates/swc_ecma_minifier/src/pass/mangle_names/analyzer/scope.rs index 25550206fc6..b9705c53310 100644 --- a/crates/swc_ecma_minifier/src/pass/mangle_names/analyzer/scope.rs +++ b/crates/swc_ecma_minifier/src/pass/mangle_names/analyzer/scope.rs @@ -6,9 +6,10 @@ use rustc_hash::{FxHashMap, FxHashSet}; use swc_atoms::{js_word, JsWord}; use swc_common::{collections::AHashMap, util::take::Take}; use swc_ecma_ast::Id; +#[cfg(debug_assertions)] use tracing::debug; -use crate::util::base54; +use crate::{maybe_par, util::base54}; #[derive(Debug, Default)] pub(crate) struct Scope { @@ -128,7 +129,6 @@ impl Scope { } } - #[inline(never)] fn rename_one_scope( &self, to: &mut AHashMap, @@ -158,7 +158,8 @@ impl Scope { } if self.can_rename(&id, &sym, cloned_reverse) { - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { debug!("mangle: `{}{:?}` -> {}", id.0, id.1, sym); } @@ -173,7 +174,6 @@ impl Scope { } } - #[inline(never)] fn can_rename(&self, id: &Id, symbol: &JsWord, reverse: &FxHashMap>) -> bool { // We can optimize this // We only need to check the current scope and parents (ignoring `a` generated @@ -194,6 +194,11 @@ impl Scope { } pub fn rename_cost(&self) -> usize { - self.data.queue.len() + self.children.iter().map(|v| v.rename_cost()).sum::() + let children = &self.children; + self.data.queue.len() + + maybe_par!( + children.iter().map(|v| v.rename_cost()).sum::(), + *crate::LIGHT_TASK_PARALLELS + ) } } diff --git a/crates/swc_ecma_minifier/src/pass/merge_exports.rs b/crates/swc_ecma_minifier/src/pass/merge_exports.rs index 7fdf50927b8..6b9958083bf 100644 --- a/crates/swc_ecma_minifier/src/pass/merge_exports.rs +++ b/crates/swc_ecma_minifier/src/pass/merge_exports.rs @@ -2,6 +2,8 @@ use swc_common::{util::take::Take, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; +use crate::maybe_par; + /// /// - merge exports pub(crate) fn merge_exports() -> impl VisitMut { @@ -17,9 +19,12 @@ impl VisitMut for Merger { noop_visit_mut_type!(); fn visit_mut_module_items(&mut self, stmts: &mut Vec) { - let was_module = stmts - .iter() - .any(|s| matches!(s, ModuleItem::ModuleDecl(..))); + let was_module = maybe_par!( + stmts + .iter() + .any(|s| matches!(s, ModuleItem::ModuleDecl(..))), + *crate::LIGHT_TASK_PARALLELS + ); // Fast-path if !was_module { diff --git a/crates/swc_ecma_minifier/src/pass/postcompress.rs b/crates/swc_ecma_minifier/src/pass/postcompress.rs index 9b40179c2e7..5593aade1be 100644 --- a/crates/swc_ecma_minifier/src/pass/postcompress.rs +++ b/crates/swc_ecma_minifier/src/pass/postcompress.rs @@ -1,7 +1,7 @@ use swc_ecma_ast::*; use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; -use crate::option::CompressOptions; +use crate::{maybe_par, option::CompressOptions}; pub fn postcompress_optimizer(options: &CompressOptions) -> impl '_ + VisitMut { PostcompressOptimizer { @@ -38,9 +38,12 @@ impl VisitMut for PostcompressOptimizer<'_> { } fn visit_mut_module_items(&mut self, nodes: &mut Vec) { - self.ctx.is_module = nodes - .iter() - .any(|s| matches!(s, ModuleItem::ModuleDecl(..))); + self.ctx.is_module = maybe_par!( + nodes + .iter() + .any(|s| matches!(s, ModuleItem::ModuleDecl(..))), + *crate::LIGHT_TASK_PARALLELS + ); self.ctx.is_top_level = true; nodes.visit_mut_children_with(self); diff --git a/crates/swc_ecma_minifier/src/pass/precompress.rs b/crates/swc_ecma_minifier/src/pass/precompress.rs index 3074c262434..ab27302dda4 100644 --- a/crates/swc_ecma_minifier/src/pass/precompress.rs +++ b/crates/swc_ecma_minifier/src/pass/precompress.rs @@ -6,6 +6,7 @@ use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith}; use crate::{ analyzer::{analyze, ProgramData, UsageAnalyzer}, marks::Marks, + maybe_par, option::CompressOptions, util::ModuleItemExt, }; @@ -24,7 +25,7 @@ pub(crate) fn precompress_optimizer(options: &CompressOptions, marks: Marks) -> } #[derive(Debug)] -struct PrecompressOptimizer<'a> { +pub(crate) struct PrecompressOptimizer<'a> { options: &'a CompressOptions, marks: Marks, @@ -50,9 +51,12 @@ impl PrecompressOptimizer<'_> { } if self.data.is_none() { - let has_decl = stmts - .iter() - .any(|stmt| matches!(stmt.as_module_decl(), Ok(..) | Err(Stmt::Decl(..)))); + let has_decl = maybe_par!( + stmts + .iter() + .any(|stmt| matches!(stmt.as_module_decl(), Ok(..) | Err(Stmt::Decl(..)))), + *crate::LIGHT_TASK_PARALLELS + ); if has_decl { let data = Some(analyze(&*stmts, Some(self.marks))); @@ -66,8 +70,7 @@ impl PrecompressOptimizer<'_> { }); return; } - - for stmt in stmts { + stmts.iter_mut().for_each(|stmt| { stmt.visit_mut_with(&mut PrecompressOptimizer { options: self.options, marks: self.marks, @@ -75,7 +78,7 @@ impl PrecompressOptimizer<'_> { fn_decl_count: Default::default(), ctx: self.ctx, }) - } + }); } } } diff --git a/crates/swc_ecma_minifier/src/util/mod.rs b/crates/swc_ecma_minifier/src/util/mod.rs index faec857d67e..f14ae7b7628 100644 --- a/crates/swc_ecma_minifier/src/util/mod.rs +++ b/crates/swc_ecma_minifier/src/util/mod.rs @@ -139,7 +139,6 @@ pub(crate) trait ExprOptExt: Sized { } } - #[inline] fn prepend_exprs(&mut self, mut exprs: Vec>) { if exprs.is_empty() { return; @@ -164,24 +163,20 @@ pub(crate) trait ExprOptExt: Sized { } impl ExprOptExt for Box { - #[inline] fn as_expr(&self) -> &Expr { self } - #[inline] fn as_mut(&mut self) -> &mut Expr { self } } impl ExprOptExt for Expr { - #[inline] fn as_expr(&self) -> &Expr { self } - #[inline] fn as_mut(&mut self) -> &mut Expr { self } @@ -279,14 +274,12 @@ pub(crate) trait IsModuleItem { } impl IsModuleItem for Stmt { - #[inline] fn is_module_item() -> bool { false } } impl IsModuleItem for ModuleItem { - #[inline] fn is_module_item() -> bool { true } @@ -315,7 +308,6 @@ impl Repeated for Optional where V: Repeated, { - #[inline] fn changed(&self) -> bool { if self.enabled { return false; @@ -324,7 +316,6 @@ where self.visitor.changed() } - #[inline] fn reset(&mut self) { if self.enabled { return; @@ -347,7 +338,6 @@ impl Fold for Optional where V: Fold, { - #[inline(always)] fn fold_module(&mut self, module: Module) -> Module { if !self.enabled { return module; @@ -548,9 +538,12 @@ pub(crate) fn can_end_conditionally(s: &Stmt) -> bool { } pub fn now() -> Option { - if cfg!(target_arch = "wasm32") { + #[cfg(target_arch = "wasm32")] + { None - } else { + } + #[cfg(not(target_arch = "wasm32"))] + { Some(Instant::now()) } } @@ -592,3 +585,97 @@ impl Visit for EvalFinder { } } } + +#[macro_export(local_inner_macros)] +#[allow(clippy::crate_in_macro_def)] +macro_rules! maybe_par { + ($prefix:ident.$name:ident.iter().$operator:ident($($rest:expr)*), $threshold:expr) => { + if $prefix.$name.len() >= $threshold { + use rayon::prelude::*; + $prefix.$name.par_iter().$operator($($rest)*) + } else { + $prefix.$name.iter().$operator($($rest)*) + } + }; + + ($prefix:ident.$name:ident.into_iter().$operator:ident($($rest:expr)*), $threshold:expr) => { + if $prefix.$name.len() >= $threshold { + use rayon::prelude::*; + $prefix.$name.into_par_iter().$operator($($rest)*) + } else { + $prefix.$name.into_iter().$operator($($rest)*) + } + }; + + ($name:ident.iter().$operator:ident($($rest:expr)*), $threshold:expr) => { + if $name.len() >= $threshold { + use rayon::prelude::*; + $name.par_iter().$operator($($rest)*) + } else { + $name.iter().$operator($($rest)*) + } + }; + + ($name:ident.into_iter().$operator:ident($($rest:expr)*), $threshold:expr) => { + if $name.len() >= $threshold { + use rayon::prelude::*; + $name.into_par_iter().$operator($($rest)*) + } else { + $name.into_iter().$operator($($rest)*) + } + }; + + ($name:ident.iter_mut().$operator:ident($($rest:expr)*), $threshold:expr) => { + if $name.len() >= $threshold { + use rayon::prelude::*; + $name.par_iter_mut().$operator($($rest)*) + } else { + $name.iter_mut().$operator($($rest)*) + } + }; + + ($name:ident.iter().$operator:ident($($rest:expr)*).$operator2:ident($($rest2:expr)*), $threshold:expr) => { + if $name.len() >= $threshold { + use rayon::prelude::*; + $name.par_iter().$operator($($rest)*).$operator2($($rest2)*) + } else { + $name.iter().$operator($($rest)*).$operator2($($rest2)*) + } + }; + + ($name:ident.into_iter().$operator:ident($($rest:expr)*).$operator2:ident($($rest2:expr)*), $threshold:expr) => { + if $name.len() >= $threshold { + use rayon::prelude::*; + $name.into_par_iter().$operator($($rest)*).$operator2($($rest2)*) + } else { + $name.into_iter().$operator($($rest)*).$operator2($($rest2)*) + } + }; + + ($name:ident.iter_mut().$operator:ident($($rest:expr)*).$operator2:ident($($rest2:expr)*), $threshold:expr) => { + if $name.len() >= $threshold { + use rayon::prelude::*; + $name.par_iter_mut().$operator($($rest)*).$operator2($($rest2)*) + } else { + $name.iter_mut().$operator($($rest)*).$operator2($($rest2)*) + } + }; + + ($name:ident.iter().$operator:ident($($rest:expr)*).$operator2:ident::<$t:ty>($($rest2:expr)*), $threshold:expr) => { + if $name.len() >= $threshold { + use rayon::prelude::*; + $name.par_iter().$operator($($rest)*).$operator2::<$t>($($rest2)*) + } else { + $name.iter().$operator($($rest)*).$operator2::<$t>($($rest2)*) + } + }; + + ($name:ident.iter().$operator:ident($($rest:expr)*).$operator2:ident($($rest2:expr)*).$operator3:ident($($rest3:expr)*), $threshold:expr) => { + if $name.len() >= $threshold { + use rayon::prelude::*; + $name.par_iter().$operator($($rest)*).$operator2($($rest2)*).$operator3($($rest3)*) + } else { + $name.iter().$operator($($rest)*).$operator2($($rest2)*).$operator3($($rest3)*) + } + }; +} diff --git a/crates/swc_ecma_minifier/src/util/sort.rs b/crates/swc_ecma_minifier/src/util/sort.rs index 11b999d3cb8..80aea6d87c7 100644 --- a/crates/swc_ecma_minifier/src/util/sort.rs +++ b/crates/swc_ecma_minifier/src/util/sort.rs @@ -1,30 +1,22 @@ use std::cmp::Ordering; -pub(crate) fn is_sorted_by(mut items: impl Iterator, mut compare: F) -> bool +pub(crate) fn is_sorted_by(mut items: I, mut compare: F) -> bool where + I: Iterator, T: Copy, F: FnMut(&T, &T) -> Option, { - let mut last = match items.next() { + let last = match items.next() { Some(e) => e, None => return true, }; - for curr in items { - if let Some(Ordering::Greater) | None = compare(&last, &curr) { - return false; - } - last = curr; - } - - true -} - -pub(crate) fn is_sorted_by_key(items: impl Iterator, key: F) -> bool -where - T: Copy, - F: FnMut(T) -> K, - K: Copy + PartialOrd, -{ - is_sorted_by(items.map(key), PartialOrd::partial_cmp) + items + .try_fold(last, |last, curr| { + if let Some(Ordering::Greater) | None = compare(&last, &curr) { + return Err(()); + } + Ok(curr) + }) + .is_ok() } diff --git a/crates/swc_ecma_minifier/src/util/unit.rs b/crates/swc_ecma_minifier/src/util/unit.rs index 3e3d93e2525..03966dce7ba 100644 --- a/crates/swc_ecma_minifier/src/util/unit.rs +++ b/crates/swc_ecma_minifier/src/util/unit.rs @@ -4,9 +4,13 @@ use swc_common::Mark; use swc_ecma_ast::*; use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene}; use swc_ecma_utils::DropSpan; -use swc_ecma_visit::{as_folder, FoldWith, VisitMut, VisitMutWith, VisitWith}; +#[cfg(debug_assertions)] +use swc_ecma_visit::VisitWith; +use swc_ecma_visit::{as_folder, FoldWith, VisitMut, VisitMutWith}; -use crate::debug::{dump, AssertValid}; +use crate::debug::dump; +#[cfg(debug_assertions)] +use crate::debug::AssertValid; /// Indicates a unit of minifaction. pub(crate) trait CompileUnit: @@ -19,11 +23,14 @@ pub(crate) trait CompileUnit: fn is_module() -> bool; fn dump(&self) -> String { - if !cfg!(feature = "debug") { - return String::new(); + #[cfg(feature = "debug")] + { + self.force_dump() + } + #[cfg(not(feature = "debug"))] + { + String::new() } - - self.force_dump() } fn force_dump(&self) -> String; @@ -90,7 +97,8 @@ impl CompileUnit for FnExpr { V: VisitMut, { self.visit_mut_with(&mut *visitor); - if cfg!(debug_assertions) { + #[cfg(debug_assertions)] + { self.visit_with(&mut AssertValid); } } diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index 532022d2172..3322610ce64 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -1900,7 +1900,6 @@ pub fn opt_chain_test( } /// inject `branch` after directives -#[inline(never)] pub fn prepend_stmt(stmts: &mut Vec, stmt: T) { let idx = stmts .iter() diff --git a/crates/swc_ecma_visit/src/lib.rs b/crates/swc_ecma_visit/src/lib.rs index dd675f59773..7981bbd690a 100644 --- a/crates/swc_ecma_visit/src/lib.rs +++ b/crates/swc_ecma_visit/src/lib.rs @@ -192,12 +192,10 @@ impl Repeated for Folder where V: Repeated + VisitMut, { - #[inline(always)] fn changed(&self) -> bool { self.0.changed() } - #[inline(always)] fn reset(&mut self) { self.0.reset(); } @@ -214,7 +212,6 @@ where macro_rules! delegate { ($name:ident, $T:ty) => { - #[inline(always)] fn $name(&mut self, n: &mut $T) { n.visit_mut_with(&mut self.0); } @@ -249,7 +246,6 @@ where macro_rules! method { ($name:ident, $T:ty) => { - #[inline(always)] fn $name(&mut self, mut n: $T) -> $T { n.visit_mut_with(&mut self.0); n @@ -295,7 +291,6 @@ where #[macro_export] macro_rules! noop_fold_type { ($name:ident, $N:tt) => { - #[inline] fn $name(&mut self, node: $crate::swc_ecma_ast::$N) -> $crate::swc_ecma_ast::$N { node } @@ -372,7 +367,6 @@ macro_rules! noop_fold_type { #[macro_export] macro_rules! noop_visit_type { ($name:ident, $N:tt) => { - #[inline] fn $name(&mut self, _: &$crate::swc_ecma_ast::$N) {} }; () => { @@ -434,7 +428,6 @@ macro_rules! noop_visit_type { #[macro_export] macro_rules! noop_visit_mut_type { ($name:ident, $N:ident) => { - #[inline] fn $name(&mut self, _: &mut $crate::swc_ecma_ast::$N) {} }; () => { diff --git a/crates/swc_node_base/Cargo.toml b/crates/swc_node_base/Cargo.toml index 8dd68b8ddac..34558ef56c3 100644 --- a/crates/swc_node_base/Cargo.toml +++ b/crates/swc_node_base/Cargo.toml @@ -14,7 +14,7 @@ bench = false [dependencies] [target.'cfg(not(target_os = "linux"))'.dependencies] -mimalloc-rust = { version = "0.1" } +mimalloc-rust = { version = "0.2" } -[target.'cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies] -tikv-jemallocator = { version = "0.4", features = ["disable_initial_exec_tls"] } +[target.'cfg(all(target_os = "linux", not(all(target_env = "musl", target_arch = "aarch64"))))'.dependencies] +mimalloc-rust = { version = "0.2", features = ["local-dynamic-tls"] } diff --git a/crates/swc_node_base/src/lib.rs b/crates/swc_node_base/src/lib.rs index f853ce8a5c1..45b8321ba0d 100644 --- a/crates/swc_node_base/src/lib.rs +++ b/crates/swc_node_base/src/lib.rs @@ -2,14 +2,9 @@ //! //! The swc crates related to the node binding should depend on this crate. -#[cfg(not(target_os = "linux"))] -#[global_allocator] -static GLOBAL: mimalloc_rust::GlobalMiMalloc = mimalloc_rust::GlobalMiMalloc; - #[cfg(all( - target_os = "linux", - target_env = "gnu", - any(target_arch = "x86_64", target_arch = "aarch64") + not(all(target_os = "linux", target_env = "musl", target_arch = "aarch64")), + not(debug_assertions) ))] #[global_allocator] -static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +static ALLOC: mimalloc_rust::GlobalMiMalloc = mimalloc_rust::GlobalMiMalloc;