Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(es/minifier): Use arena allocator for ProgramData #10068

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/swc_ecma_minifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ concurrent = [
"swc_ecma_transforms_optimization/concurrent",
"rayon",
"indexmap/rayon",
"hashbrown/rayon",
]
debug = ["backtrace", "swc_ecma_transforms_optimization/debug"]
default = ["serde-impl"]
Expand All @@ -35,6 +36,7 @@ trace-ast = []
[dependencies]
arrayvec = { workspace = true }
backtrace = { workspace = true, optional = true }
hashbrown = { workspace = true }
indexmap = { workspace = true }
num-bigint = { workspace = true }
num_cpus = { workspace = true }
Expand Down
18 changes: 11 additions & 7 deletions crates/swc_ecma_minifier/src/compress/hoist_decls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,24 @@ pub(super) struct DeclHoisterConfig {
pub _top_level: bool,
}

pub(super) fn decl_hoister(config: DeclHoisterConfig, data: &ProgramData) -> Hoister {
pub(super) fn decl_hoister<'a, 'alloc>(
config: DeclHoisterConfig,
data: &'a ProgramData<'alloc>,
) -> Hoister<'a, 'alloc> {
Hoister {
config,
changed: false,
data,
}
}

pub(super) struct Hoister<'a> {
pub(super) struct Hoister<'a, 'alloc> {
config: DeclHoisterConfig,
changed: bool,
data: &'a ProgramData,
data: &'a ProgramData<'alloc>,
}

impl Repeated for Hoister<'_> {
impl Repeated for Hoister<'_, '_> {
fn changed(&self) -> bool {
self.changed
}
Expand All @@ -43,11 +46,12 @@ impl Repeated for Hoister<'_> {
}
}

impl Hoister<'_> {
impl<'alloc> Hoister<'_, 'alloc> {
fn handle_stmt_likes<T>(&mut self, stmts: &mut Vec<T>)
where
T: StmtLike + IsModuleItem + ModuleItemExt,
Vec<T>: for<'aa> VisitMutWith<Hoister<'aa>> + VisitWith<UsageAnalyzer<ProgramData>>,
Vec<T>: for<'aa> VisitMutWith<Hoister<'aa, 'alloc>>
+ VisitWith<UsageAnalyzer<'alloc, ProgramData<'alloc>>>,
{
stmts.visit_mut_children_with(self);
let len = stmts.len();
Expand Down Expand Up @@ -279,7 +283,7 @@ impl Hoister<'_> {
}
}

impl VisitMut for Hoister<'_> {
impl VisitMut for Hoister<'_, '_> {
noop_visit_mut_type!();

fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
Expand Down
34 changes: 20 additions & 14 deletions crates/swc_ecma_minifier/src/compress/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
use std::fmt::{self, Debug, Display, Formatter};
#[cfg(feature = "debug")]
use std::thread;
use std::{borrow::Cow, fmt::Write, time::Instant};
use std::{borrow::Cow, fmt::Write, mem::transmute, time::Instant};

#[cfg(feature = "pretty_assertions")]
use pretty_assertions::assert_eq;
use swc_allocator::allocators::Arena;
use swc_common::pass::{CompilerPass, Optional, Repeated};
use swc_ecma_ast::*;
use swc_ecma_transforms_optimization::simplify::{
Expand All @@ -23,7 +24,7 @@ use crate::{
debug::{dump, AssertValid},
mode::Mode,
option::{CompressOptions, MangleOptions},
program_data::analyze,
program_data::{analyze, ProgramData},
util::{force_dump_program, now},
};

Expand Down Expand Up @@ -95,7 +96,8 @@ impl Compressor<'_> {
);

if self.options.hoist_vars || self.options.hoist_fns {
let data = analyze(&*n, Some(self.marks));
let arena = Arena::default();
let data = analyze(&arena, &*n, Some(self.marks));

let mut v = decl_hoister(
DeclHoisterConfig {
Expand Down Expand Up @@ -256,23 +258,27 @@ impl Compressor<'_> {
{
let _timer = timer!("apply full optimizer");

let mut data = analyze(&*n, Some(self.marks));
let arena = Arena::default();

let mut data = analyze(&arena, &*n, Some(self.marks));

// TODO: reset_opt_flags
//
// This is swc version of `node.optimize(this);`.

let mut visitor = optimizer(
self.marks,
self.options,
self.mangle_options,
&mut data,
self.mode,
!self.dump_for_infinite_loop.is_empty(),
);
n.visit_mut_with(&mut visitor);
{
let mut visitor = optimizer(
self.marks,
self.options,
self.mangle_options,
unsafe { transmute::<&mut ProgramData, &mut ProgramData>(&mut data) },
self.mode,
!self.dump_for_infinite_loop.is_empty(),
);
n.visit_mut_with(&mut visitor);

self.changed |= visitor.changed();
self.changed |= visitor.changed();
}

// let done = dump(&*n);
// debug!("===== Result =====\n{}", done);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::Optimizer;
use crate::compress::optimize::is_left_access_to_arguments;

/// Methods related to the option `arguments`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
///
/// - `arguments['foo']` => `arguments.foo`
pub(super) fn optimize_str_access_to_arguments(&mut self, e: &mut Expr) {
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/src/compress/optimize/bools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::compress::{optimize::Ctx, util::negate_cost};
use crate::debug::dump;

/// Methods related to the options `bools` and `bool_as_ints`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// **This negates bool**.
///
/// Returns true if it's negated.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{

/// Methods related to the option `conditionals`. All methods are noop if
/// `conditionals` is false.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// Negates the condition of a `if` statement to reduce body size.
pub(super) fn negate_if_stmt(&mut self, stmt: &mut IfStmt) {
let alt = match stmt.alt.as_deref_mut() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use swc_ecma_ast::*;
use super::Optimizer;

/// Methods related to option `dead_code`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// Optimize return value or argument of throw.
///
/// This methods removes some useless assignments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::Optimizer;
use crate::{compress::util::eval_as_number, maybe_par, DISABLE_BUGGY_PASSES};

/// Methods related to the option `evaluate`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// Evaluate expression if possible.
///
/// This method call appropriate methods for each ast types.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{compress::util::is_pure_undefined, util::ExprOptExt};

/// Methods related to the option `if_return`. All methods are noop if
/// `if_return` is false.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
pub(super) fn merge_nested_if(&mut self, s: &mut IfStmt) {
if !self.options.conditionals && !self.options.bools {
return;
Expand Down
6 changes: 3 additions & 3 deletions crates/swc_ecma_minifier/src/compress/optimize/iife.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
};

/// Methods related to the option `negate_iife`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// Negates iife, while ignore return value.
pub(super) fn negate_iife_ignoring_ret(&mut self, e: &mut Expr) {
if !self.options.negate_iife || self.ctx.in_bang_arg || self.ctx.dont_use_negated_iife {
Expand Down Expand Up @@ -112,7 +112,7 @@ impl Optimizer<'_> {
}

/// Methods related to iife.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// # Example
///
/// ## Input
Expand Down Expand Up @@ -964,7 +964,7 @@ impl Optimizer<'_> {
Stmt::Decl(Decl::Var(ref mut var)) => {
for decl in &mut var.decls {
if decl.init.is_some() {
let ids = find_pat_ids(decl);
let ids: Vec<Id> = find_pat_ids(decl);

for id in ids {
if let Some(usage) = self.data.vars.get_mut(&id) {
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/src/compress/optimize/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
};

/// Methods related to option `inline`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// Stores the value of a variable to inline it.
///
/// This method may remove value of initializer. It mean that the value will
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/src/compress/optimize/loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use swc_ecma_utils::{ExprExt, Value::Known};
use crate::compress::{optimize::Optimizer, util::UnreachableHandler};

/// Methods related to the option `loops`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// `for(a;b;c;) break;` => `a;b;`
pub(super) fn optimize_loops_with_break(&mut self, s: &mut Stmt) {
if !self.options.loops {
Expand Down
20 changes: 11 additions & 9 deletions crates/swc_ecma_minifier/src/compress/optimize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ mod unused;
mod util;

/// This pass is similar to `node.optimize` of terser.
pub(super) fn optimizer<'a>(
pub(super) fn optimizer<'a: 'alloc, 'alloc>(
marks: Marks,
options: &'a CompressOptions,
mangle_options: Option<&'a MangleOptions>,
data: &'a mut ProgramData,
data: &'a mut ProgramData<'alloc>,
mode: &'a dyn Mode,
debug_infinite_loop: bool,
) -> impl 'a + VisitMut + Repeated {
) -> impl 'a + 'alloc + VisitMut + Repeated {
assert!(
options.top_retain.iter().all(|s| s.trim() != ""),
"top_retain should not contain empty string"
Expand Down Expand Up @@ -216,7 +216,7 @@ impl Ctx {
}
}

struct Optimizer<'a> {
struct Optimizer<'a, 'alloc> {
marks: Marks,

changed: bool,
Expand All @@ -234,7 +234,7 @@ struct Optimizer<'a> {
///
/// This is calculated multiple time, but only once per one
/// `visit_mut_module`.
data: &'a mut ProgramData,
data: &'a mut ProgramData<'alloc>,
ctx: Ctx,

mode: &'a dyn Mode,
Expand Down Expand Up @@ -317,7 +317,7 @@ impl Vars {
}
}

impl Repeated for Optimizer<'_> {
impl<'alloc> Repeated for Optimizer<'_, 'alloc> {
fn changed(&self) -> bool {
self.changed
}
Expand All @@ -344,7 +344,7 @@ impl From<&Function> for FnMetadata {
}
}

impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
fn may_remove_ident(&self, id: &Ident) -> bool {
if let Some(VarUsageInfo { exported: true, .. }) =
self.data.vars.get(&id.clone().to_id()).map(|v| &**v)
Expand Down Expand Up @@ -431,7 +431,9 @@ impl Optimizer<'_> {
fn handle_stmt_likes<T>(&mut self, stmts: &mut Vec<T>, will_terminate: bool)
where
T: StmtLike + ModuleItemLike + ModuleItemExt + VisitMutWith<Self> + VisitWith<AssertValid>,
Vec<T>: VisitMutWith<Self> + VisitWith<UsageAnalyzer<ProgramData>> + VisitWith<AssertValid>,
Vec<T>: VisitMutWith<Self>
+ VisitWith<UsageAnalyzer<'alloc, ProgramData<'alloc>>>
+ VisitWith<AssertValid>,
{
let mut use_asm = false;
let prepend_stmts = self.prepend_stmts.take();
Expand Down Expand Up @@ -1526,7 +1528,7 @@ impl Optimizer<'_> {
}
}

impl VisitMut for Optimizer<'_> {
impl<'alloc> VisitMut for Optimizer<'_, 'alloc> {
noop_visit_mut_type!();

#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/src/compress/optimize/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
util::{make_bool, ValueExt},
};

impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
///
/// - `'12' === `foo` => '12' == 'foo'`
pub(super) fn optimize_bin_equal(&mut self, e: &mut BinExpr) {
Expand Down
4 changes: 2 additions & 2 deletions crates/swc_ecma_minifier/src/compress/optimize/props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::{unused::PropertyAccessOpts, Optimizer};
use crate::util::deeply_contains_this_expr;

/// Methods related to the option `hoist_props`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
pub(super) fn hoist_props_of_var(
&mut self,
n: &mut VarDeclarator,
Expand Down Expand Up @@ -241,7 +241,7 @@ fn is_expr_fine_for_hoist_props(value: &Expr) -> bool {
}
}

impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// Converts `{ a: 1 }.a` into `1`.
pub(super) fn handle_property_access(&mut self, e: &mut Expr) {
if !self.options.props {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{

/// Methods related to the option `sequences`. All methods are noop if
/// `sequences` is false.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
///
/// # Example
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use swc_ecma_utils::{ExprExt, Value::Known};

use super::Optimizer;

impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
pub(super) fn optimize_expr_in_str_ctx_unsafely(&mut self, e: &mut Expr) {
if !self.options.unsafe_passes {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::Optimizer;
use crate::{compress::util::is_primitive, util::idents_used_by};

/// Methods related to option `switches`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
/// Handle switches in the case where we can know which branch will be
/// taken.
pub(super) fn optimize_const_switches(&mut self, s: &mut Stmt) {
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/src/compress/optimize/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub(crate) struct PropertyAccessOpts {
}

/// Methods related to the option `unused`.
impl Optimizer<'_> {
impl<'alloc> Optimizer<'_, 'alloc> {
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
pub(super) fn drop_unused_var_declarator(
&mut self,
Expand Down
Loading
Loading