refactor(es/minifier): Merge code for multi-replacer (#4269)

This commit is contained in:
Donny/강동윤 2022-04-07 17:08:42 +09:00 committed by GitHub
parent 67c8c6debd
commit 434dcf4af7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 95 additions and 77 deletions

View File

@ -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);
} }
} }
} }

View File

@ -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

View File

@ -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 });
{ {

View File

@ -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",

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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