perf(es/minifier): Make expression simplifier stateless and parallel (#5819)

This commit is contained in:
Donny/강동윤 2022-09-11 15:18:44 +09:00 committed by GitHub
parent 5fe032c01a
commit cfe575e35a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 150 additions and 111 deletions

View File

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

View File

@ -3,7 +3,7 @@ function f(CONFIG) {
}
function g() {
var CONFIG = {
VALUE: 1,
VALUE: 1
};
return CONFIG.VALUE;
}

View File

@ -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() {

View File

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

View File

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

View File

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

View File

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

View File

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