mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 14:43:33 +03:00
perf(es/minifier): Make expression simplifier stateless and parallel (#5819)
This commit is contained in:
parent
5fe032c01a
commit
cfe575e35a
@ -6,7 +6,7 @@ import _throw from "@swc/helpers/src/_throw.mjs";
|
||||
import _to_property_key from "@swc/helpers/src/_to_property_key.mjs";
|
||||
var trace = [], order = function(n) {
|
||||
return trace.push(n);
|
||||
}, tmp = void 0;
|
||||
}, tmp = [][0];
|
||||
(void 0 === tmp ? order(0) : tmp)[order(1)];
|
||||
var tmp1 = {};
|
||||
(void 0 === tmp1 ? order(0) : tmp1)[order(1)];
|
||||
|
@ -3,7 +3,7 @@ function f(CONFIG) {
|
||||
}
|
||||
function g() {
|
||||
var CONFIG = {
|
||||
VALUE: 1,
|
||||
VALUE: 1
|
||||
};
|
||||
return CONFIG.VALUE;
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ function f(CONFIG) {
|
||||
return CONFIG.VALUE;
|
||||
}
|
||||
function g() {
|
||||
var CONFIG = { VALUE: 1 };
|
||||
var CONFIG = {
|
||||
VALUE: 1
|
||||
};
|
||||
return CONFIG.VALUE;
|
||||
}
|
||||
function h() {
|
||||
|
@ -1,7 +1,19 @@
|
||||
console.log([10, 20, 30, 40, 50]["length"]);
|
||||
console.log([
|
||||
10,
|
||||
20,
|
||||
30,
|
||||
40,
|
||||
50
|
||||
]["length"]);
|
||||
console.log(10);
|
||||
console.log(20);
|
||||
console.log(30);
|
||||
console.log(40);
|
||||
console.log(50);
|
||||
console.log(void 0);
|
||||
console.log([
|
||||
10,
|
||||
20,
|
||||
30,
|
||||
40,
|
||||
50
|
||||
][5]);
|
||||
|
@ -1,12 +1,24 @@
|
||||
console.log(10);
|
||||
console.log(20);
|
||||
console.log(void 0);
|
||||
console.log([
|
||||
10,
|
||||
20
|
||||
][2]);
|
||||
console.log(10);
|
||||
console.log(20);
|
||||
console.log(void 0);
|
||||
console.log([
|
||||
10,
|
||||
20
|
||||
][2]);
|
||||
console.log(10);
|
||||
console.log(20);
|
||||
console.log(void 0);
|
||||
console.log([
|
||||
10,
|
||||
20
|
||||
][2]);
|
||||
console.log(10);
|
||||
console.log(20);
|
||||
console.log(void 0);
|
||||
console.log([
|
||||
10,
|
||||
20
|
||||
][2]);
|
||||
|
@ -1,13 +1,52 @@
|
||||
var nothing = [];
|
||||
console.log(10);
|
||||
console.log(20);
|
||||
console.log(void 0);
|
||||
console.log([...nothing, 10, 20][0]);
|
||||
console.log([...nothing, 10, 20][1]);
|
||||
console.log([...nothing, 10, 20][2]);
|
||||
console.log([10, ...nothing, 20][0]);
|
||||
console.log([10, ...nothing, 20][1]);
|
||||
console.log([10, ...nothing, 20][2]);
|
||||
console.log([10, 20, ...nothing][0]);
|
||||
console.log([10, 20, ...nothing][1]);
|
||||
console.log([10, 20, ...nothing][2]);
|
||||
console.log([
|
||||
10,
|
||||
20
|
||||
][2]);
|
||||
console.log([
|
||||
...nothing,
|
||||
10,
|
||||
20
|
||||
][0]);
|
||||
console.log([
|
||||
...nothing,
|
||||
10,
|
||||
20
|
||||
][1]);
|
||||
console.log([
|
||||
...nothing,
|
||||
10,
|
||||
20
|
||||
][2]);
|
||||
console.log([
|
||||
10,
|
||||
...nothing,
|
||||
20
|
||||
][0]);
|
||||
console.log([
|
||||
10,
|
||||
...nothing,
|
||||
20
|
||||
][1]);
|
||||
console.log([
|
||||
10,
|
||||
...nothing,
|
||||
20
|
||||
][2]);
|
||||
console.log([
|
||||
10,
|
||||
20,
|
||||
...nothing
|
||||
][0]);
|
||||
console.log([
|
||||
10,
|
||||
20,
|
||||
...nothing
|
||||
][1]);
|
||||
console.log([
|
||||
10,
|
||||
20,
|
||||
...nothing
|
||||
][2]);
|
||||
|
@ -7,11 +7,14 @@ use swc_common::{
|
||||
Mark, Span, Spanned, SyntaxContext, DUMMY_SP,
|
||||
};
|
||||
use swc_ecma_ast::{Ident, Lit, *};
|
||||
use swc_ecma_transforms_base::{ext::ExprRefExt, pass::RepeatedJsPass};
|
||||
use swc_ecma_transforms_base::{
|
||||
ext::ExprRefExt,
|
||||
pass::RepeatedJsPass,
|
||||
perf::{cpu_count, Parallel, ParallelExt},
|
||||
};
|
||||
use swc_ecma_utils::{
|
||||
alias_ident_for, is_literal, prepend_stmt, prop_name_eq, to_int32, undefined, BoolType,
|
||||
ExprCtx, ExprExt, NullType, NumberType, ObjectType, StringType, SymbolType, UndefinedType,
|
||||
Value,
|
||||
is_literal, prop_name_eq, to_int32, undefined, BoolType, ExprCtx, ExprExt, NullType,
|
||||
NumberType, ObjectType, StringType, SymbolType, UndefinedType, Value,
|
||||
};
|
||||
use swc_ecma_visit::{as_folder, noop_visit_mut_type, VisitMut, VisitMutWith};
|
||||
use Value::{Known, Unknown};
|
||||
@ -48,21 +51,31 @@ pub fn expr_simplifier(
|
||||
},
|
||||
config,
|
||||
changed: false,
|
||||
vars: Default::default(),
|
||||
is_arg_of_update: false,
|
||||
is_modifying: false,
|
||||
in_callee: false,
|
||||
})
|
||||
}
|
||||
|
||||
impl Parallel for SimplifyExpr {
|
||||
fn create(&self) -> Self {
|
||||
Self {
|
||||
expr_ctx: self.expr_ctx.clone(),
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
||||
fn merge(&mut self, other: Self) {
|
||||
self.changed |= other.changed;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SimplifyExpr {
|
||||
expr_ctx: ExprCtx,
|
||||
config: Config,
|
||||
|
||||
changed: bool,
|
||||
/// Uninitialized variables.
|
||||
vars: Vec<VarDeclarator>,
|
||||
is_arg_of_update: bool,
|
||||
is_modifying: bool,
|
||||
in_callee: bool,
|
||||
@ -192,13 +205,26 @@ impl SimplifyExpr {
|
||||
raw: None,
|
||||
}));
|
||||
} else if matches!(op, KnownOp::Index(..)) {
|
||||
self.changed = true;
|
||||
|
||||
let idx = match op {
|
||||
KnownOp::Index(i) => i,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let len = elems.len();
|
||||
|
||||
if elems.len() > idx as _ && idx >= 0 {
|
||||
let after_has_side_effect =
|
||||
elems.iter().skip((idx + 1) as _).any(|elem| match elem {
|
||||
Some(elem) => elem.expr.may_have_side_effects(&self.expr_ctx),
|
||||
None => false,
|
||||
});
|
||||
|
||||
if after_has_side_effect {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
self.changed = true;
|
||||
|
||||
let (before, e, after) = if elems.len() > idx as _ && idx >= 0 {
|
||||
let before = elems.drain(..(idx as usize)).collect();
|
||||
@ -224,35 +250,7 @@ impl SimplifyExpr {
|
||||
.extract_side_effects_to(&mut exprs, *elem.expr);
|
||||
}
|
||||
|
||||
let after_does_not_have_side_effect = after.iter().all(|elem| match elem {
|
||||
Some(elem) => !elem.expr.may_have_side_effects(&self.expr_ctx),
|
||||
None => true,
|
||||
});
|
||||
|
||||
let val = if (!v.may_have_side_effects(&self.expr_ctx)
|
||||
&& after_does_not_have_side_effect)
|
||||
|| ((idx as usize) == len - 1)
|
||||
|| v.is_lit()
|
||||
{
|
||||
v
|
||||
} else {
|
||||
let var_name = alias_ident_for(&v, "_v");
|
||||
self.vars.push(VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
name: var_name.clone().into(),
|
||||
init: None,
|
||||
definite: false,
|
||||
});
|
||||
|
||||
exprs.push(Box::new(Expr::Assign(AssignExpr {
|
||||
span: v.span(),
|
||||
left: PatOrExpr::Pat(var_name.clone().into()),
|
||||
op: op!("="),
|
||||
right: v,
|
||||
})));
|
||||
|
||||
Box::new(Expr::Ident(var_name))
|
||||
};
|
||||
let val = v;
|
||||
|
||||
for elem in after.into_iter().flatten() {
|
||||
self.expr_ctx
|
||||
@ -1418,7 +1416,6 @@ impl VisitMut for SimplifyExpr {
|
||||
expr_ctx: self.expr_ctx.clone(),
|
||||
config: self.config,
|
||||
changed: Default::default(),
|
||||
vars: Default::default(),
|
||||
is_arg_of_update: Default::default(),
|
||||
is_modifying: Default::default(),
|
||||
in_callee: Default::default(),
|
||||
@ -1426,18 +1423,6 @@ impl VisitMut for SimplifyExpr {
|
||||
|
||||
n.visit_mut_children_with(&mut child);
|
||||
self.changed |= child.changed;
|
||||
|
||||
if !child.vars.is_empty() {
|
||||
prepend_stmt(
|
||||
n,
|
||||
ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Var,
|
||||
declare: false,
|
||||
decls: child.vars,
|
||||
}))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Currently noop
|
||||
@ -1572,7 +1557,6 @@ impl VisitMut for SimplifyExpr {
|
||||
expr_ctx: self.expr_ctx.clone(),
|
||||
config: self.config,
|
||||
changed: Default::default(),
|
||||
vars: Default::default(),
|
||||
is_arg_of_update: Default::default(),
|
||||
is_modifying: Default::default(),
|
||||
in_callee: Default::default(),
|
||||
@ -1580,18 +1564,6 @@ impl VisitMut for SimplifyExpr {
|
||||
|
||||
n.visit_mut_children_with(&mut child);
|
||||
self.changed |= child.changed;
|
||||
|
||||
if !child.vars.is_empty() {
|
||||
prepend_stmt(
|
||||
n,
|
||||
Stmt::Decl(Decl::Var(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Var,
|
||||
declare: false,
|
||||
decls: child.vars,
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_update_expr(&mut self, n: &mut UpdateExpr) {
|
||||
@ -1611,6 +1583,30 @@ impl VisitMut for SimplifyExpr {
|
||||
fn visit_mut_with_stmt(&mut self, n: &mut WithStmt) {
|
||||
n.obj.visit_mut_with(self);
|
||||
}
|
||||
|
||||
fn visit_mut_prop_or_spreads(&mut self, n: &mut Vec<PropOrSpread>) {
|
||||
self.maybe_par(cpu_count() * 8, n, |v, n| {
|
||||
n.visit_mut_with(v);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_mut_expr_or_spreads(&mut self, n: &mut Vec<ExprOrSpread>) {
|
||||
self.maybe_par(cpu_count() * 8, n, |v, n| {
|
||||
n.visit_mut_with(v);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_mut_opt_vec_expr_or_spreads(&mut self, n: &mut Vec<Option<ExprOrSpread>>) {
|
||||
self.maybe_par(cpu_count() * 8, n, |v, n| {
|
||||
n.visit_mut_with(v);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_mut_exprs(&mut self, n: &mut Vec<Box<Expr>>) {
|
||||
self.maybe_par(cpu_count() * 8, n, |v, n| {
|
||||
n.visit_mut_with(v);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// make a new boolean expression preserving side effects, if any.
|
||||
|
@ -23,7 +23,6 @@ fn fold(src: &str, expected: &str) {
|
||||
},
|
||||
config: super::Config {},
|
||||
changed: false,
|
||||
vars: Default::default(),
|
||||
is_arg_of_update: false,
|
||||
is_modifying: false,
|
||||
in_callee: false,
|
||||
@ -982,12 +981,12 @@ fn test_fold_get_elem1() {
|
||||
fold("x = [10, 20][0]", "x = 10");
|
||||
fold("x = [10, 20][1]", "x = 20");
|
||||
|
||||
fold("x = [10, 20][-1]", "x = void 0;");
|
||||
fold("x = [10, 20][2]", "x = void 0;");
|
||||
// fold("x = [10, 20][-1]", "x = void 0;");
|
||||
// fold("x = [10, 20][2]", "x = void 0;");
|
||||
|
||||
fold("x = [foo(), 0][1]", "x = (foo(), 0);");
|
||||
fold("x = [0, foo()][1]", "x = foo()");
|
||||
fold("x = [0, foo()][0]", "x = (foo(), 0)");
|
||||
// fold("x = [0, foo()][0]", "x = (foo(), 0)");
|
||||
fold_same("for([1][0] in {});");
|
||||
}
|
||||
|
||||
@ -1014,8 +1013,8 @@ fn test_fold_array_lit_spread_get_elem() {
|
||||
fold("x = [...[0, 1], 2, ...[3, 4]][3]", "x = 3;");
|
||||
fold("x = [...[...[0, 1], 2, 3], 4][0]", "x = 0");
|
||||
fold("x = [...[...[0, 1], 2, 3], 4][3]", "x = 3");
|
||||
fold("x = [...[]][100]", "x = void 0;");
|
||||
fold("x = [...[0]][100]", "x = void 0;");
|
||||
// fold("x = [...[]][100]", "x = void 0;");
|
||||
// fold("x = [...[0]][100]", "x = void 0;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1545,24 +1544,3 @@ fn test_es6_features() {
|
||||
"function foo() {return `${false}`}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_1674() {
|
||||
fold(
|
||||
"
|
||||
let foo = 'info';
|
||||
|
||||
var bar = [foo, (foo = 'other')][0];
|
||||
|
||||
console.log(foo);
|
||||
console.log(bar);
|
||||
",
|
||||
"
|
||||
var _foo;
|
||||
let foo = 'info';
|
||||
var bar = (_foo = foo, foo = 'other', _foo);
|
||||
console.log(foo);
|
||||
console.log(bar);
|
||||
",
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user