From 7329824b825663c6c51c48dd5ace097da87e2c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Sun, 12 Jan 2025 16:17:23 +0900 Subject: [PATCH] perf(es/minifier): Make the first run of DCE more efficient (#9868) **Description:** We can drop constant branches from precompress pass to make the pass after it faster. --- .changeset/stale-apricots-dream.md | 6 +++ crates/swc_ecma_minifier/src/lib.rs | 7 ++- .../swc_ecma_minifier/src/pass/precompress.rs | 52 +++++++++++++++---- 3 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 .changeset/stale-apricots-dream.md diff --git a/.changeset/stale-apricots-dream.md b/.changeset/stale-apricots-dream.md new file mode 100644 index 000000000000..fe8263c87344 --- /dev/null +++ b/.changeset/stale-apricots-dream.md @@ -0,0 +1,6 @@ +--- +swc_core: minor +swc_ecma_minifier: minor +--- + +perf(es/minifier): Make the first run of DCE more efficient diff --git a/crates/swc_ecma_minifier/src/lib.rs b/crates/swc_ecma_minifier/src/lib.rs index 3078bee95be7..f4d3e2002864 100644 --- a/crates/swc_ecma_minifier/src/lib.rs +++ b/crates/swc_ecma_minifier/src/lib.rs @@ -44,6 +44,7 @@ use swc_common::{comments::Comments, pass::Repeated, sync::Lrc, SourceMap, Synta use swc_ecma_ast::*; use swc_ecma_transforms_optimization::debug_assert_valid; use swc_ecma_usage_analyzer::marks::Marks; +use swc_ecma_utils::ExprCtx; use swc_ecma_visit::VisitMutWith; use swc_timer::timer; @@ -126,7 +127,11 @@ pub fn optimize( if let Some(_options) = &options.compress { let _timer = timer!("precompress"); - n.visit_mut_with(&mut precompress_optimizer()); + n.visit_mut_with(&mut precompress_optimizer(ExprCtx { + unresolved_ctxt: SyntaxContext::empty().apply_mark(marks.unresolved_mark), + is_unresolved_ref_safe: false, + in_strict: false, + })); debug_assert_valid(&n); } diff --git a/crates/swc_ecma_minifier/src/pass/precompress.rs b/crates/swc_ecma_minifier/src/pass/precompress.rs index 00a0af3d700b..ba80636534b1 100644 --- a/crates/swc_ecma_minifier/src/pass/precompress.rs +++ b/crates/swc_ecma_minifier/src/pass/precompress.rs @@ -1,26 +1,50 @@ use std::vec::Vec; +use swc_common::util::take::Take; use swc_ecma_ast::*; use swc_ecma_transforms_base::perf::{Parallel, ParallelExt}; +use swc_ecma_utils::{ExprCtx, ExprExt, Value::Known}; use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith}; -use crate::HEAVY_TASK_PARALLELS; +use crate::CPU_COUNT; /// Optimizer invoked before invoking compressor. /// /// - Remove parens. /// /// TODO: remove completely after #8333 -pub(crate) fn precompress_optimizer<'a>() -> impl 'a + VisitMut { - PrecompressOptimizer {} +pub(crate) fn precompress_optimizer<'a>(expr_ctx: ExprCtx) -> impl 'a + VisitMut { + PrecompressOptimizer { expr_ctx } } #[derive(Debug)] -pub(crate) struct PrecompressOptimizer {} +pub(crate) struct PrecompressOptimizer { + expr_ctx: ExprCtx, +} + +impl PrecompressOptimizer { + /// Drops RHS from `null && foo` + fn optimize_bin_expr(&mut self, n: &mut Expr) { + let Expr::Bin(b) = n else { + return; + }; + + if b.op == op!("&&") && b.left.as_pure_bool(&self.expr_ctx) == Known(false) { + *n = *b.left.take(); + return; + } + + if b.op == op!("||") && b.left.as_pure_bool(&self.expr_ctx) == Known(true) { + *n = *b.left.take(); + } + } +} impl Parallel for PrecompressOptimizer { fn create(&self) -> Self { - Self {} + Self { + expr_ctx: self.expr_ctx.clone(), + } } fn merge(&mut self, _: Self) {} @@ -29,38 +53,44 @@ impl Parallel for PrecompressOptimizer { impl VisitMut for PrecompressOptimizer { noop_visit_mut_type!(); + fn visit_mut_expr(&mut self, n: &mut Expr) { + n.visit_mut_children_with(self); + + self.optimize_bin_expr(n); + } + fn visit_mut_stmts(&mut self, n: &mut Vec) { - self.maybe_par(*HEAVY_TASK_PARALLELS, n, |v, n| { + self.maybe_par(*CPU_COUNT, n, |v, n| { n.visit_mut_with(v); }); } fn visit_mut_module_items(&mut self, n: &mut Vec) { - self.maybe_par(*HEAVY_TASK_PARALLELS, n, |v, n| { + self.maybe_par(*CPU_COUNT, n, |v, n| { n.visit_mut_with(v); }); } fn visit_mut_exprs(&mut self, n: &mut Vec>) { - self.maybe_par(*HEAVY_TASK_PARALLELS, n, |v, n| { + self.maybe_par(*CPU_COUNT, n, |v, n| { n.visit_mut_with(v); }); } fn visit_mut_opt_vec_expr_or_spreads(&mut self, n: &mut Vec>) { - self.maybe_par(*HEAVY_TASK_PARALLELS, n, |v, n| { + self.maybe_par(*CPU_COUNT, n, |v, n| { n.visit_mut_with(v); }); } fn visit_mut_expr_or_spreads(&mut self, n: &mut Vec) { - self.maybe_par(*HEAVY_TASK_PARALLELS, n, |v, n| { + self.maybe_par(*CPU_COUNT, n, |v, n| { n.visit_mut_with(v); }); } fn visit_mut_var_declarators(&mut self, n: &mut Vec) { - self.maybe_par(*HEAVY_TASK_PARALLELS, n, |v, n| { + self.maybe_par(*CPU_COUNT, n, |v, n| { n.visit_mut_with(v); }); }