mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 04:47:03 +03:00
refactor(es/minifier): Merge code for multi-replacer (#4269)
This commit is contained in:
parent
67c8c6debd
commit
434dcf4af7
@ -68,7 +68,7 @@ where
|
|||||||
left.id.span.ctxt
|
left.id.span.ctxt
|
||||||
);
|
);
|
||||||
|
|
||||||
self.lits.insert(left.to_id(), value);
|
self.vars.lits.insert(left.to_id(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Pat::Ident(name) = &mut n.name {
|
if let Pat::Ident(name) = &mut n.name {
|
||||||
|
if self.options.top_retain.contains(&name.id.sym) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If a variable is initialized multiple time, we currently don't do anything
|
// If a variable is initialized multiple time, we currently don't do anything
|
||||||
// smart.
|
// smart.
|
||||||
if !self
|
if !self
|
||||||
|
@ -9,7 +9,10 @@ use swc_ecma_utils::{
|
|||||||
};
|
};
|
||||||
use swc_ecma_visit::VisitMutWith;
|
use swc_ecma_visit::VisitMutWith;
|
||||||
|
|
||||||
use super::{util::MultiReplacer, Optimizer};
|
use super::{
|
||||||
|
util::{MultiReplacer, MultiReplacerMode},
|
||||||
|
Optimizer,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
compress::optimize::{util::Remapper, Ctx},
|
compress::optimize::{util::Remapper, Ctx},
|
||||||
debug::dump,
|
debug::dump,
|
||||||
@ -262,7 +265,7 @@ where
|
|||||||
n.visit_mut_with(&mut MultiReplacer::new(
|
n.visit_mut_with(&mut MultiReplacer::new(
|
||||||
&mut vars,
|
&mut vars,
|
||||||
false,
|
false,
|
||||||
false,
|
MultiReplacerMode::Normal,
|
||||||
&mut self.changed,
|
&mut self.changed,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -437,18 +440,9 @@ where
|
|||||||
exprs.push(arg.expr.take());
|
exprs.push(arg.expr.take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body.visit_mut_with(&mut MultiReplacer::new(
|
if self.vars.inline_with_multi_replacer(body) {
|
||||||
&mut self.simple_functions,
|
self.changed = true;
|
||||||
true,
|
}
|
||||||
true,
|
|
||||||
&mut self.changed,
|
|
||||||
));
|
|
||||||
body.visit_mut_with(&mut MultiReplacer::new(
|
|
||||||
&mut self.vars_for_inlining,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
&mut self.changed,
|
|
||||||
));
|
|
||||||
body.visit_mut_with(&mut Remapper { vars: remap });
|
body.visit_mut_with(&mut Remapper { vars: remap });
|
||||||
exprs.push(body.take());
|
exprs.push(body.take());
|
||||||
|
|
||||||
@ -549,10 +543,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_pending_inline_for(&self, id: &Id) -> bool {
|
|
||||||
self.lits.contains_key(id) || self.vars_for_inlining.contains_key(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_return_arg_simple_enough_for_iife_eval(&self, e: &Expr) -> bool {
|
fn is_return_arg_simple_enough_for_iife_eval(&self, e: &Expr) -> bool {
|
||||||
match e {
|
match e {
|
||||||
Expr::Lit(..) | Expr::Ident(..) => true,
|
Expr::Lit(..) | Expr::Ident(..) => true,
|
||||||
@ -632,7 +622,7 @@ where
|
|||||||
..
|
..
|
||||||
}) => true,
|
}) => true,
|
||||||
Pat::Ident(id) => {
|
Pat::Ident(id) => {
|
||||||
if self.has_pending_inline_for(&id.to_id()) {
|
if self.vars.has_pending_inline_for(&id.to_id()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,18 +719,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.visit_mut_with(&mut MultiReplacer::new(
|
if self.vars.inline_with_multi_replacer(body) {
|
||||||
&mut self.simple_functions,
|
self.changed = true;
|
||||||
true,
|
}
|
||||||
true,
|
|
||||||
&mut self.changed,
|
|
||||||
));
|
|
||||||
body.visit_mut_with(&mut MultiReplacer::new(
|
|
||||||
&mut self.vars_for_inlining,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
&mut self.changed,
|
|
||||||
));
|
|
||||||
body.visit_mut_with(&mut Remapper { vars: remap });
|
body.visit_mut_with(&mut Remapper { vars: remap });
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -47,7 +47,7 @@ where
|
|||||||
|
|
||||||
// We will inline if possible.
|
// We will inline if possible.
|
||||||
if let Pat::Ident(i) = &var.name {
|
if let Pat::Ident(i) = &var.name {
|
||||||
if i.id.sym == *"arguments" {
|
if i.id.sym == js_word!("arguments") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.options.top_retain.contains(&i.id.sym) {
|
if self.options.top_retain.contains(&i.id.sym) {
|
||||||
@ -185,7 +185,7 @@ where
|
|||||||
var.span = var.span.apply_mark(self.marks.non_top_level);
|
var.span = var.span.apply_mark(self.marks.non_top_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lits.insert(i.to_id(), init.take());
|
self.vars.lits.insert(i.to_id(), init.take());
|
||||||
|
|
||||||
var.name.take();
|
var.name.take();
|
||||||
} else if self.options.inline != 0 || self.options.reduce_vars {
|
} else if self.options.inline != 0 || self.options.reduce_vars {
|
||||||
@ -197,7 +197,7 @@ where
|
|||||||
|
|
||||||
self.mode.store(i.to_id(), &*init);
|
self.mode.store(i.to_id(), &*init);
|
||||||
|
|
||||||
self.lits.insert(i.to_id(), init.clone());
|
self.vars.lits.insert(i.to_id(), init.clone());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -294,7 +294,7 @@ where
|
|||||||
i.id
|
i.id
|
||||||
);
|
);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
self.vars_for_inlining.insert(i.to_id(), init.take());
|
self.vars.vars_for_inlining.insert(i.to_id(), init.take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -479,7 +479,7 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.simple_functions.insert(
|
self.vars.simple_functions.insert(
|
||||||
i.to_id(),
|
i.to_id(),
|
||||||
match decl {
|
match decl {
|
||||||
Decl::Fn(f) => Box::new(Expr::Fn(FnExpr {
|
Decl::Fn(f) => Box::new(Expr::Fn(FnExpr {
|
||||||
@ -559,7 +559,7 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.vars_for_inlining.insert(i.to_id(), e);
|
self.vars.vars_for_inlining.insert(i.to_id(), e);
|
||||||
} else {
|
} else {
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
tracing::trace!("inline: [x] Usage: {:?}", usage);
|
tracing::trace!("inline: [x] Usage: {:?}", usage);
|
||||||
@ -573,11 +573,12 @@ where
|
|||||||
if let Expr::Ident(i) = e {
|
if let Expr::Ident(i) = e {
|
||||||
//
|
//
|
||||||
if let Some(value) = self
|
if let Some(value) = self
|
||||||
|
.vars
|
||||||
.lits
|
.lits
|
||||||
.get(&i.to_id())
|
.get(&i.to_id())
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if self.ctx.is_callee {
|
if self.ctx.is_callee {
|
||||||
self.simple_functions.get(&i.to_id())
|
self.vars.simple_functions.get(&i.to_id())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -615,7 +616,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check without cloning
|
// Check without cloning
|
||||||
if let Some(value) = self.vars_for_inlining.get(&i.to_id()) {
|
if let Some(value) = self.vars.vars_for_inlining.get(&i.to_id()) {
|
||||||
if self.ctx.is_exact_lhs_of_assign && !is_valid_for_lhs(value) {
|
if self.ctx.is_exact_lhs_of_assign && !is_valid_for_lhs(value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -627,7 +628,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = self.vars_for_inlining.remove(&i.to_id()) {
|
if let Some(value) = self.vars.vars_for_inlining.remove(&i.to_id()) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
"inline: Replacing '{}{:?}' with an expression",
|
"inline: Replacing '{}{:?}' with an expression",
|
||||||
|
@ -18,7 +18,10 @@ use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith};
|
|||||||
use tracing::{span, Level};
|
use tracing::{span, Level};
|
||||||
use Value::Known;
|
use Value::Known;
|
||||||
|
|
||||||
use self::{unused::PropertyAccessOpts, util::MultiReplacer};
|
use self::{
|
||||||
|
unused::PropertyAccessOpts,
|
||||||
|
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};
|
||||||
use crate::{
|
use crate::{
|
||||||
analyzer::{ProgramData, UsageAnalyzer},
|
analyzer::{ProgramData, UsageAnalyzer},
|
||||||
@ -71,9 +74,7 @@ where
|
|||||||
options,
|
options,
|
||||||
prepend_stmts: Default::default(),
|
prepend_stmts: Default::default(),
|
||||||
append_stmts: Default::default(),
|
append_stmts: Default::default(),
|
||||||
lits: Default::default(),
|
vars: Default::default(),
|
||||||
simple_functions: Default::default(),
|
|
||||||
vars_for_inlining: Default::default(),
|
|
||||||
vars_for_prop_hoisting: Default::default(),
|
vars_for_prop_hoisting: Default::default(),
|
||||||
simple_props: Default::default(),
|
simple_props: Default::default(),
|
||||||
_simple_array_values: Default::default(),
|
_simple_array_values: Default::default(),
|
||||||
@ -192,16 +193,7 @@ struct Optimizer<'a, M> {
|
|||||||
/// Statements appended to the current statement.
|
/// Statements appended to the current statement.
|
||||||
append_stmts: SynthesizedStmts,
|
append_stmts: SynthesizedStmts,
|
||||||
|
|
||||||
/// Cheap to clone.
|
vars: Vars,
|
||||||
///
|
|
||||||
/// Used for inlining.
|
|
||||||
lits: AHashMap<Id, Box<Expr>>,
|
|
||||||
|
|
||||||
/// Used for copying functions.
|
|
||||||
///
|
|
||||||
/// We use this to distinguish [Callee::Expr] from other [Expr]s.
|
|
||||||
simple_functions: FxHashMap<Id, Box<Expr>>,
|
|
||||||
vars_for_inlining: FxHashMap<Id, Box<Expr>>,
|
|
||||||
|
|
||||||
/// Used for `hoist_props`.
|
/// Used for `hoist_props`.
|
||||||
vars_for_prop_hoisting: FxHashMap<Id, Box<Expr>>,
|
vars_for_prop_hoisting: FxHashMap<Id, Box<Expr>>,
|
||||||
@ -228,6 +220,48 @@ struct Optimizer<'a, M> {
|
|||||||
functions: FxHashMap<Id, FnMetadata>,
|
functions: FxHashMap<Id, FnMetadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Vars {
|
||||||
|
/// Cheap to clone.
|
||||||
|
///
|
||||||
|
/// Used for inlining.
|
||||||
|
lits: AHashMap<Id, Box<Expr>>,
|
||||||
|
|
||||||
|
/// Used for copying functions.
|
||||||
|
///
|
||||||
|
/// We use this to distinguish [Callee::Expr] from other [Expr]s.
|
||||||
|
simple_functions: FxHashMap<Id, Box<Expr>>,
|
||||||
|
vars_for_inlining: FxHashMap<Id, Box<Expr>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vars {
|
||||||
|
fn has_pending_inline_for(&self, id: &Id) -> bool {
|
||||||
|
self.lits.contains_key(id) || self.vars_for_inlining.contains_key(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if something is changed.
|
||||||
|
fn inline_with_multi_replacer<N>(&mut self, n: &mut N) -> bool
|
||||||
|
where
|
||||||
|
N: for<'aa> VisitMutWith<MultiReplacer<'aa>>,
|
||||||
|
{
|
||||||
|
let mut changed = false;
|
||||||
|
n.visit_mut_with(&mut MultiReplacer::new(
|
||||||
|
&mut self.simple_functions,
|
||||||
|
true,
|
||||||
|
MultiReplacerMode::OnlyCallee,
|
||||||
|
&mut changed,
|
||||||
|
));
|
||||||
|
n.visit_mut_with(&mut MultiReplacer::new(
|
||||||
|
&mut self.vars_for_inlining,
|
||||||
|
false,
|
||||||
|
MultiReplacerMode::Normal,
|
||||||
|
&mut changed,
|
||||||
|
));
|
||||||
|
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<M> Repeated for Optimizer<'_, M> {
|
impl<M> Repeated for Optimizer<'_, M> {
|
||||||
fn changed(&self) -> bool {
|
fn changed(&self) -> bool {
|
||||||
self.changed
|
self.changed
|
||||||
@ -1935,8 +1969,8 @@ where
|
|||||||
if !self.options.negate_iife {
|
if !self.options.negate_iife {
|
||||||
// I(kdy1) don't know why this check if required, but there are two test cases
|
// I(kdy1) don't know why this check if required, but there are two test cases
|
||||||
// with `options.expressions` as only difference.
|
// with `options.expressions` as only difference.
|
||||||
if !self.options.expr {
|
if !self.options.expr && self.negate_iife_in_cond(&mut n.expr) {
|
||||||
need_ignore_return_value |= self.negate_iife_in_cond(&mut n.expr);
|
need_ignore_return_value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2229,18 +2263,9 @@ where
|
|||||||
};
|
};
|
||||||
self.with_ctx(ctx).handle_stmt_likes(stmts);
|
self.with_ctx(ctx).handle_stmt_likes(stmts);
|
||||||
|
|
||||||
stmts.visit_mut_with(&mut MultiReplacer::new(
|
if self.vars.inline_with_multi_replacer(stmts) {
|
||||||
&mut self.simple_functions,
|
self.changed = true;
|
||||||
true,
|
}
|
||||||
true,
|
|
||||||
&mut self.changed,
|
|
||||||
));
|
|
||||||
stmts.visit_mut_with(&mut MultiReplacer::new(
|
|
||||||
&mut self.vars_for_inlining,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
&mut self.changed,
|
|
||||||
));
|
|
||||||
|
|
||||||
drop_invalid_stmts(stmts);
|
drop_invalid_stmts(stmts);
|
||||||
}
|
}
|
||||||
@ -2313,8 +2338,7 @@ where
|
|||||||
n.visit_mut_children_with(self);
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
if let Prop::Shorthand(i) = n {
|
if let Prop::Shorthand(i) = n {
|
||||||
if self.lits.contains_key(&i.to_id()) || self.vars_for_inlining.contains_key(&i.to_id())
|
if self.vars.has_pending_inline_for(&i.to_id()) {
|
||||||
{
|
|
||||||
let mut e = Box::new(Expr::Ident(i.clone()));
|
let mut e = Box::new(Expr::Ident(i.clone()));
|
||||||
e.visit_mut_with(self);
|
e.visit_mut_with(self);
|
||||||
|
|
||||||
|
@ -190,23 +190,31 @@ pub(crate) struct MultiReplacer<'a> {
|
|||||||
vars: &'a mut FxHashMap<Id, Box<Expr>>,
|
vars: &'a mut FxHashMap<Id, Box<Expr>>,
|
||||||
changed: bool,
|
changed: bool,
|
||||||
clone: bool,
|
clone: bool,
|
||||||
only_callee: bool,
|
mode: MultiReplacerMode,
|
||||||
worked: &'a mut bool,
|
worked: &'a mut bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
||||||
|
pub enum MultiReplacerMode {
|
||||||
|
Normal,
|
||||||
|
OnlyCallee,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> MultiReplacer<'a> {
|
impl<'a> MultiReplacer<'a> {
|
||||||
/// `worked` will be changed to `true` if any replacement is done
|
/// `worked` will be changed to `true` if any replacement is done
|
||||||
pub fn new(
|
pub fn new(
|
||||||
vars: &'a mut FxHashMap<Id, Box<Expr>>,
|
vars: &'a mut FxHashMap<Id, Box<Expr>>,
|
||||||
clone: bool,
|
clone: bool,
|
||||||
only_callee: bool,
|
mode: MultiReplacerMode,
|
||||||
worked: &'a mut bool,
|
worked: &'a mut bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
MultiReplacer {
|
MultiReplacer {
|
||||||
vars,
|
vars,
|
||||||
changed: false,
|
changed: false,
|
||||||
clone,
|
clone,
|
||||||
only_callee,
|
mode,
|
||||||
worked,
|
worked,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,7 +234,7 @@ impl VisitMut for MultiReplacer<'_> {
|
|||||||
fn visit_mut_callee(&mut self, e: &mut Callee) {
|
fn visit_mut_callee(&mut self, e: &mut Callee) {
|
||||||
e.visit_mut_children_with(self);
|
e.visit_mut_children_with(self);
|
||||||
|
|
||||||
if self.only_callee {
|
if matches!(self.mode, MultiReplacerMode::OnlyCallee) {
|
||||||
if let Callee::Expr(e) = e {
|
if let Callee::Expr(e) = e {
|
||||||
if let Expr::Ident(i) = &**e {
|
if let Expr::Ident(i) = &**e {
|
||||||
if let Some(new) = self.var(&i.to_id()) {
|
if let Some(new) = self.var(&i.to_id()) {
|
||||||
@ -244,7 +252,7 @@ impl VisitMut for MultiReplacer<'_> {
|
|||||||
fn visit_mut_expr(&mut self, e: &mut Expr) {
|
fn visit_mut_expr(&mut self, e: &mut Expr) {
|
||||||
e.visit_mut_children_with(self);
|
e.visit_mut_children_with(self);
|
||||||
|
|
||||||
if !self.only_callee {
|
if matches!(self.mode, MultiReplacerMode::Normal) {
|
||||||
if let Expr::Ident(i) = e {
|
if let Expr::Ident(i) = e {
|
||||||
if let Some(new) = self.var(&i.to_id()) {
|
if let Some(new) = self.var(&i.to_id()) {
|
||||||
debug!("multi-replacer: Replaced `{}`", i);
|
debug!("multi-replacer: Replaced `{}`", i);
|
||||||
|
@ -334,7 +334,6 @@ hoist_props/contains_this_2/input.js
|
|||||||
hoist_props/direct_access_1/input.js
|
hoist_props/direct_access_1/input.js
|
||||||
hoist_props/hoist_class/input.js
|
hoist_props/hoist_class/input.js
|
||||||
hoist_props/hoist_class_with_new/input.js
|
hoist_props/hoist_class_with_new/input.js
|
||||||
hoist_props/issue_2473_3/input.js
|
|
||||||
hoist_props/issue_2473_4/input.js
|
hoist_props/issue_2473_4/input.js
|
||||||
hoist_props/issue_2508_1/input.js
|
hoist_props/issue_2508_1/input.js
|
||||||
hoist_props/issue_2508_2/input.js
|
hoist_props/issue_2508_2/input.js
|
||||||
|
@ -629,6 +629,7 @@ hoist_props/issue_2377_3/input.js
|
|||||||
hoist_props/issue_2462/input.js
|
hoist_props/issue_2462/input.js
|
||||||
hoist_props/issue_2473_1/input.js
|
hoist_props/issue_2473_1/input.js
|
||||||
hoist_props/issue_2473_2/input.js
|
hoist_props/issue_2473_2/input.js
|
||||||
|
hoist_props/issue_2473_3/input.js
|
||||||
hoist_props/issue_2508_3/input.js
|
hoist_props/issue_2508_3/input.js
|
||||||
hoist_props/issue_2508_4/input.js
|
hoist_props/issue_2508_4/input.js
|
||||||
hoist_props/issue_3071_1/input.js
|
hoist_props/issue_3071_1/input.js
|
||||||
|
Loading…
Reference in New Issue
Block a user