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