Skip to content

Commit

Permalink
feat(es/minifier): Make sequential inliner self-repeat (#6168)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdy1 committed Oct 18, 2022
1 parent 25df5b3 commit 3f0fcf4
Show file tree
Hide file tree
Showing 22 changed files with 335 additions and 279 deletions.
@@ -1,4 +1,7 @@
//// [computedPropertyNames12_ES5.ts]
var a;
import _class_call_check from "@swc/helpers/src/_class_call_check.mjs";
"hello ".concat(a, " bye");
var n, a, _ref = (void 0) + n;
(function C() {
"use strict";
_class_call_check(this, C), this[n] = n, this[_ref] = 2, this["hello bye"] = 0;
})["hello ".concat(a, " bye")] = 0;
254 changes: 133 additions & 121 deletions crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
Expand Up @@ -771,166 +771,178 @@ where
)
};

for idx in 0..exprs.len() {
for j in idx..exprs.len() {
let (a1, a2) = exprs.split_at_mut(idx);
loop {
let mut did_work = false;

if a1.is_empty() || a2.is_empty() {
break;
}

let a = a1.last_mut().unwrap();
for idx in 0..exprs.len() {
for j in idx..exprs.len() {
let (a1, a2) = exprs.split_at_mut(idx);

if self.options.unused && self.options.sequences() {
if let (Mergable::Var(av), Mergable::Var(bv)) = (&mut *a, &mut a2[j - idx]) {
// We try dropping variable assignments first.
if a1.is_empty() || a2.is_empty() {
break;
}

// Currently, we only drop variable declarations if they have the same name.
if let (Pat::Ident(an), Pat::Ident(bn)) = (&av.name, &bv.name) {
if an.to_id() == bn.to_id() {
// We need to preserve side effect of `av.init`
let a = a1.last_mut().unwrap();

match bv.init.as_deref_mut() {
Some(b_init) => {
if IdentUsageFinder::find(&an.to_id(), b_init) {
log_abort!(
"We can't duplicated binding because initializer \
uses the previous declaration of the variable"
);
break;
}
if self.options.unused && self.options.sequences() {
if let (Mergable::Var(av), Mergable::Var(bv)) = (&mut *a, &mut a2[j - idx])
{
// We try dropping variable assignments first.

// Currently, we only drop variable declarations if they have the same
// name.
if let (Pat::Ident(an), Pat::Ident(bn)) = (&av.name, &bv.name) {
if an.to_id() == bn.to_id() {
// We need to preserve side effect of `av.init`

match bv.init.as_deref_mut() {
Some(b_init) => {
if IdentUsageFinder::find(&an.to_id(), b_init) {
log_abort!(
"We can't duplicated binding because \
initializer uses the previous declaration of \
the variable"
);
break;
}

if let Some(a_init) = av.init.take() {
let b_seq = b_init.force_seq();
b_seq.exprs.insert(0, a_init);
if let Some(a_init) = av.init.take() {
let b_seq = b_init.force_seq();
b_seq.exprs.insert(0, a_init);

self.changed = true;
report_change!(
"Moving initializer sequentially as they have \
a same name"
);
av.name.take();
continue;
} else {
self.changed = true;
report_change!(
"Dropping the previous var declaration of {} \
which does not have an initializer",
an.id
);
av.name.take();
continue;
}
}
None => {
// As variable name is same, we can move initializer

// Th code below
//
// var a = 5;
// var a;
//
// console.log(a)
//
// prints 5
bv.init = av.init.take();
self.changed = true;
report_change!(
"Moving initializer sequentially as they have a \
same name"
);
av.name.take();
continue;
} else {
self.changed = true;
report_change!(
"Dropping the previous var declaration of {} \
which does not have an initializer",
an.id
"Moving initializer to the next variable \
declaration as they have the same name"
);
av.name.take();
continue;
}
}
None => {
// As variable name is same, we can move initializer

// Th code below
//
// var a = 5;
// var a;
//
// console.log(a)
//
// prints 5
bv.init = av.init.take();
self.changed = true;
report_change!(
"Moving initializer to the next variable declaration \
as they have the same name"
);
av.name.take();
continue;
}
}
}
}
}
}

// Merge sequentially
// Merge sequentially

if self.merge_sequential_expr(
a,
match &mut a2[j - idx] {
Mergable::Var(b) => match b.init.as_deref_mut() {
Some(v) => v,
None => continue,
if self.merge_sequential_expr(
a,
match &mut a2[j - idx] {
Mergable::Var(b) => match b.init.as_deref_mut() {
Some(v) => v,
None => continue,
},
Mergable::Expr(e) => e,
},
Mergable::Expr(e) => e,
},
)? {
break;
}
)? {
did_work = true;
break;
}

// This logic is required to handle
//
// var b;
// (function () {
// function f() {
// a++;
// }
// f();
// var c = f();
// var a = void 0;
// c || (b = a);
// })();
// console.log(b);
//
//
// at the code above, c cannot be shifted to `c` in `c || (b = a)`
//
// This logic is required to handle
//
// var b;
// (function () {
// function f() {
// a++;
// }
// f();
// var c = f();
// var a = void 0;
// c || (b = a);
// })();
// console.log(b);
//
//
// at the code above, c cannot be shifted to `c` in `c || (b = a)`
//

match a {
Mergable::Var(VarDeclarator {
init: Some(init), ..
}) => {
if !self.is_skippable_for_seq(None, init) {
break;
}
}
Mergable::Expr(Expr::Assign(a)) => {
if let Some(a) = a.left.as_expr() {
if !self.is_skippable_for_seq(None, a) {
match a {
Mergable::Var(VarDeclarator {
init: Some(init), ..
}) => {
if !self.is_skippable_for_seq(None, init) {
break;
}
}
Mergable::Expr(Expr::Assign(a)) => {
if let Some(a) = a.left.as_expr() {
if !self.is_skippable_for_seq(None, a) {
break;
}
}

if !self.is_skippable_for_seq(None, &a.right) {
break;
if !self.is_skippable_for_seq(None, &a.right) {
break;
}
}
_ => {}
}
_ => {}
}

match &a2[j - idx] {
Mergable::Var(e2) => {
if let Some(e2) = &e2.init {
if !self.is_skippable_for_seq(Some(a), e2) {
break;
match &a2[j - idx] {
Mergable::Var(e2) => {
if let Some(e2) = &e2.init {
if !self.is_skippable_for_seq(Some(a), e2) {
break;
}
}
}

if let Some(id) = a1.last_mut().unwrap().id() {
if IdentUsageFinder::find(&id, &**e2) {
break;
if let Some(id) = a1.last_mut().unwrap().id() {
if IdentUsageFinder::find(&id, &**e2) {
break;
}
}
}
}
Mergable::Expr(e2) => {
if !self.is_skippable_for_seq(Some(a), e2) {
break;
}

if let Some(id) = a1.last_mut().unwrap().id() {
// TODO(kdy1): Optimize
if IdentUsageFinder::find(&id, &**e2) {
Mergable::Expr(e2) => {
if !self.is_skippable_for_seq(Some(a), e2) {
break;
}

if let Some(id) = a1.last_mut().unwrap().id() {
// TODO(kdy1): Optimize
if IdentUsageFinder::find(&id, &**e2) {
break;
}
}
}
}
}
}

if !did_work {
break;
}
}

Ok(())
Expand Down

1 comment on commit 3f0fcf4

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 3f0fcf4 Previous: 6e2e2ad Ratio
es/full/minify/libraries/antd 1872606370 ns/iter (± 28814422) 1867527037 ns/iter (± 18549169) 1.00
es/full/minify/libraries/d3 408818375 ns/iter (± 10365027) 425940894 ns/iter (± 19088614) 0.96
es/full/minify/libraries/echarts 1556083030 ns/iter (± 22452526) 1524438878 ns/iter (± 22565698) 1.02
es/full/minify/libraries/jquery 107438676 ns/iter (± 2610596) 107901458 ns/iter (± 15189026) 1.00
es/full/minify/libraries/lodash 122351057 ns/iter (± 4167578) 111339115 ns/iter (± 1283262) 1.10
es/full/minify/libraries/moment 63166251 ns/iter (± 4496728) 57658064 ns/iter (± 3177173) 1.10
es/full/minify/libraries/react 20288172 ns/iter (± 729913) 20154312 ns/iter (± 997548) 1.01
es/full/minify/libraries/terser 332961845 ns/iter (± 10489824) 312676082 ns/iter (± 14360050) 1.06
es/full/minify/libraries/three 573051503 ns/iter (± 15863437) 590028892 ns/iter (± 20425854) 0.97
es/full/minify/libraries/typescript 3506839155 ns/iter (± 38760004) 3527185352 ns/iter (± 92581466) 0.99
es/full/minify/libraries/victory 839784095 ns/iter (± 15155773) 833600869 ns/iter (± 48473470) 1.01
es/full/minify/libraries/vue 162744039 ns/iter (± 6795135) 149825384 ns/iter (± 17341198) 1.09
es/full/codegen/es3 33584 ns/iter (± 506) 34039 ns/iter (± 1787) 0.99
es/full/codegen/es5 33710 ns/iter (± 1386) 33348 ns/iter (± 752) 1.01
es/full/codegen/es2015 33584 ns/iter (± 298) 33275 ns/iter (± 559) 1.01
es/full/codegen/es2016 33479 ns/iter (± 1150) 33415 ns/iter (± 1058) 1.00
es/full/codegen/es2017 33574 ns/iter (± 1183) 33362 ns/iter (± 1378) 1.01
es/full/codegen/es2018 33680 ns/iter (± 1368) 33703 ns/iter (± 2654) 1.00
es/full/codegen/es2019 33555 ns/iter (± 627) 33406 ns/iter (± 1448) 1.00
es/full/codegen/es2020 33595 ns/iter (± 1748) 33418 ns/iter (± 1468) 1.01
es/full/all/es3 198952312 ns/iter (± 8206483) 208254443 ns/iter (± 15742664) 0.96
es/full/all/es5 187669861 ns/iter (± 8284866) 195992163 ns/iter (± 17770594) 0.96
es/full/all/es2015 148323910 ns/iter (± 5887815) 147754942 ns/iter (± 11669687) 1.00
es/full/all/es2016 148222332 ns/iter (± 5369974) 155161830 ns/iter (± 26631717) 0.96
es/full/all/es2017 147072768 ns/iter (± 4128915) 160814865 ns/iter (± 17115620) 0.91
es/full/all/es2018 145123540 ns/iter (± 6881844) 163264313 ns/iter (± 14662707) 0.89
es/full/all/es2019 145823732 ns/iter (± 7411974) 144823174 ns/iter (± 8820540) 1.01
es/full/all/es2020 139857363 ns/iter (± 5458051) 149347533 ns/iter (± 15199440) 0.94
es/full/parser 739990 ns/iter (± 26113) 757933 ns/iter (± 112367) 0.98
es/full/base/fixer 26922 ns/iter (± 528) 27167 ns/iter (± 2468) 0.99
es/full/base/resolver_and_hygiene 93381 ns/iter (± 2434) 96355 ns/iter (± 5805) 0.97
serialization of ast node 208 ns/iter (± 1) 208 ns/iter (± 11) 1
serialization of serde 209 ns/iter (± 3) 212 ns/iter (± 16) 0.99

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.