mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 13:51:19 +03:00
perf(es/minifier): Make more things parallel and reduce call stacks (#4915)
This commit is contained in:
parent
925f4d1641
commit
35806385ea
37
Cargo.lock
generated
37
Cargo.lock
generated
@ -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"
|
||||
|
@ -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" }
|
||||
|
@ -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 }
|
||||
|
@ -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<Item = Id>,
|
||||
ids: FxHashSet<Id>,
|
||||
max_num: usize,
|
||||
) -> Result<FxHashSet<Id>, ()> {
|
||||
let mut result = FxHashSet::default();
|
||||
self.expand_infected_inner(ids, max_num, &mut result)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn expand_infected_inner(
|
||||
&self,
|
||||
ids: impl IntoIterator<Item = Id>,
|
||||
max_num: usize,
|
||||
result: &mut FxHashSet<Id>,
|
||||
) -> Result<(), ()> {
|
||||
for id in ids {
|
||||
if !result.insert(id.clone()) {
|
||||
continue;
|
||||
let init =
|
||||
HashSet::with_capacity_and_hasher(max_num, BuildHasherDefault::<FxHasher>::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,
|
||||
|
@ -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<T>: for<'aa> VisitMutWith<Hoister<'aa>> + VisitWith<UsageAnalyzer>,
|
||||
{
|
||||
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<Id> = 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<Id> = 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;
|
||||
|
@ -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<T>: VisitMutWith<Self> + for<'aa> VisitMutWith<hoist_decls::Hoister<'aa>>,
|
||||
{
|
||||
// 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 {
|
||||
|
@ -90,10 +90,13 @@ where
|
||||
{
|
||||
// If a function has a variable named `arguments`, we abort.
|
||||
let data: Vec<Id> = 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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!("&&") {
|
||||
|
@ -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");
|
||||
|
@ -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<M> 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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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},
|
||||
};
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Id, FnMetadata>,
|
||||
@ -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<Stmt>) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -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::<Vec<_>>();
|
||||
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<Mergable>) -> 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<bool, ()> {
|
||||
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!(
|
||||
|
@ -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);
|
||||
|
@ -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::<Vec<_>>();
|
||||
debug!("Dropping {:?}", keys);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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::<T>::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<T> = 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;
|
||||
}
|
||||
|
@ -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..)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -57,14 +57,13 @@ impl Pure<'_> {
|
||||
self.changed = true;
|
||||
|
||||
let mut cur: Option<VarDecl> = None;
|
||||
let mut new = vec![];
|
||||
|
||||
for stmt in stmts.take() {
|
||||
let mut new: Vec<T> = 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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -41,7 +41,8 @@ where
|
||||
N: swc_ecma_codegen::Node + Clone + VisitMutWith<DropSpan> + VisitMutWith<Debugger>,
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
));
|
||||
|
@ -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<usize> = Lazy::new(num_cpus::get);
|
||||
pub(crate) static HEAVY_TASK_PARALLELS: Lazy<usize> = Lazy::new(|| *CPU_COUNT * 8);
|
||||
pub(crate) static LIGHT_TASK_PARALLELS: Lazy<usize> = Lazy::new(|| *CPU_COUNT * 100);
|
||||
|
||||
pub fn optimize(
|
||||
mut m: Module,
|
||||
_cm: Lrc<SourceMap>,
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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)*
|
||||
);
|
||||
|
@ -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(..) => {}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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<Id, JsWord>,
|
||||
@ -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<JsWord, Vec<Id>>) -> 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::<usize>()
|
||||
let children = &self.children;
|
||||
self.data.queue.len()
|
||||
+ maybe_par!(
|
||||
children.iter().map(|v| v.rename_cost()).sum::<usize>(),
|
||||
*crate::LIGHT_TASK_PARALLELS
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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<ModuleItem>) {
|
||||
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 {
|
||||
|
@ -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<ModuleItem>) {
|
||||
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);
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,6 @@ pub(crate) trait ExprOptExt: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn prepend_exprs(&mut self, mut exprs: Vec<Box<Expr>>) {
|
||||
if exprs.is_empty() {
|
||||
return;
|
||||
@ -164,24 +163,20 @@ pub(crate) trait ExprOptExt: Sized {
|
||||
}
|
||||
|
||||
impl ExprOptExt for Box<Expr> {
|
||||
#[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<V> Repeated for Optional<V>
|
||||
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<V> Fold for Optional<V>
|
||||
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<Instant> {
|
||||
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)*)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,30 +1,22 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
pub(crate) fn is_sorted_by<T, F>(mut items: impl Iterator<Item = T>, mut compare: F) -> bool
|
||||
pub(crate) fn is_sorted_by<I, T, F>(mut items: I, mut compare: F) -> bool
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: Copy,
|
||||
F: FnMut(&T, &T) -> Option<Ordering>,
|
||||
{
|
||||
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<T, F, K>(items: impl Iterator<Item = T>, 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()
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -1900,7 +1900,6 @@ pub fn opt_chain_test(
|
||||
}
|
||||
|
||||
/// inject `branch` after directives
|
||||
#[inline(never)]
|
||||
pub fn prepend_stmt<T: StmtLike>(stmts: &mut Vec<T>, stmt: T) {
|
||||
let idx = stmts
|
||||
.iter()
|
||||
|
@ -192,12 +192,10 @@ impl<V> Repeated for Folder<V>
|
||||
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) {}
|
||||
};
|
||||
() => {
|
||||
|
@ -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"] }
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user