Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(es/minifier): Merge expr_simplifier into pure optimizer #10202

Merged
merged 80 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
27d7c8f
change order
kdy1 Mar 20, 2025
f410b2b
Remove usage of `negate_cost`
kdy1 Mar 20, 2025
665806d
lints
kdy1 Mar 20, 2025
5b529e5
negate_bool_for_expr_stmt
kdy1 Mar 20, 2025
eea5dcf
negate_bool_preserving_semantics
kdy1 Mar 20, 2025
ae7bc57
Remove old code for negating
kdy1 Mar 20, 2025
ed9b0c7
Fix context passed to negate_cost
kdy1 Mar 20, 2025
bfb4318
Improve negate_bool_preserving_semantics
kdy1 Mar 20, 2025
1d4729e
lints
kdy1 Mar 20, 2025
af966c9
perf(es/minifier): Remove `expr_simplifier` call
kdy1 Mar 15, 2025
20580a0
Improve eval_spread_object
kdy1 Mar 20, 2025
badd04c
negate_twice
kdy1 Mar 20, 2025
bd91cb9
Fix
kdy1 Mar 20, 2025
39a32f3
bugfix
kdy1 Mar 20, 2025
55b1e4c
lints
kdy1 Mar 20, 2025
58afd79
changeset
kdy1 Mar 20, 2025
94d431a
fix for rebase
kdy1 Mar 20, 2025
7814bb6
Rename
kdy1 Mar 23, 2025
2713783
trace log
kdy1 Mar 23, 2025
e349c2e
instrument
kdy1 Mar 23, 2025
dc75272
Improve negate_cost
kdy1 Mar 23, 2025
4939ac7
Improve negate
kdy1 Mar 23, 2025
a741802
make_bool_short
kdy1 Mar 23, 2025
45b9848
make_bool_short
kdy1 Mar 23, 2025
fa922f6
Use make_bool_short in more places
kdy1 Mar 23, 2025
b63801b
make_bool_short: Seq expr
kdy1 Mar 23, 2025
f5b3ed8
Update test refs
kdy1 Mar 23, 2025
7ff3e19
Update test refs
kdy1 Mar 23, 2025
0516c56
Improve make_bool_short
kdy1 Mar 23, 2025
7f0867d
Update test refs
kdy1 Mar 23, 2025
7ca49b9
Optimize bools in for stmt
kdy1 Mar 23, 2025
3153c01
Update test refs
kdy1 Mar 23, 2025
ea4ea0f
Update test refs
kdy1 Mar 23, 2025
aba1e6b
Optimize bools in var decl init
kdy1 Mar 23, 2025
993e9ef
make_bool_short: Assign Expr
kdy1 Mar 23, 2025
88e14b6
Update test refs (unverified)
kdy1 Mar 23, 2025
a5574cf
visit_mut_key_value_prop: make_bool_short
kdy1 Mar 23, 2025
01a8df7
Update test refs (unverified)
kdy1 Mar 23, 2025
6fc5079
Call more make_bool_short
kdy1 Mar 23, 2025
a619dfd
Update test refs (unverified)
kdy1 Mar 23, 2025
9b2820d
make_bool_short
kdy1 Mar 23, 2025
d50a636
Update test refs (unverified)
kdy1 Mar 23, 2025
c0f712e
visit_mut_throw_stmt
kdy1 Mar 23, 2025
5a1a59f
Update test refs (unverified)
kdy1 Mar 23, 2025
e22ae66
make_bool_short: Expr::Array
kdy1 Mar 23, 2025
6b6a7da
Update test refs (unverified)
kdy1 Mar 23, 2025
4581740
fix `optimize_expr_in_bool_ctx`
kdy1 Mar 24, 2025
66b5ae1
make_bool_short: `||` and `&&`
kdy1 Mar 24, 2025
511f05c
Update test refs (unverified)
kdy1 Mar 24, 2025
10b6282
bool ctx
kdy1 Mar 24, 2025
8fa9530
fix make_bool_short
kdy1 Mar 24, 2025
aa13772
Update test refs (unverified)
kdy1 Mar 24, 2025
0d6af24
ignore_return_value: Drop numbers
kdy1 Mar 24, 2025
40d37d5
Update test refs (unverified)
kdy1 Mar 24, 2025
a6f8506
visit_mut_for_head
kdy1 Mar 24, 2025
11075d7
Update test refs (unverified)
kdy1 Mar 24, 2025
f580e86
AST API
kdy1 Mar 24, 2025
2d510eb
Remove const
kdy1 Mar 24, 2025
59444af
is_null()
kdy1 Mar 24, 2025
83da23b
Update test refs (unverified)
kdy1 Mar 24, 2025
7d2111a
handle_delete_global
kdy1 Mar 24, 2025
f0f7e56
true?
kdy1 Mar 24, 2025
d20a3fd
Update test refs (unverified)
kdy1 Mar 24, 2025
331edf9
changeset
kdy1 Mar 24, 2025
7ff27cd
in_opt_chain
kdy1 Mar 24, 2025
bc4fa95
Fix optimize_const_cond
kdy1 Mar 24, 2025
606a67a
Update test refs (unverified)
kdy1 Mar 24, 2025
867d54e
eval_member_expr: Respect ctx
kdy1 Mar 24, 2025
ac8b080
Update test refs (unverified)
kdy1 Mar 24, 2025
8777967
visit_mut_with_stmt
kdy1 Mar 24, 2025
bb6bbe0
lint
kdy1 Mar 24, 2025
5717d2a
fixup
kdy1 Mar 24, 2025
395d394
ignore_return_value
kdy1 Mar 24, 2025
e01efd6
Rename & reorder
kdy1 Mar 24, 2025
f21b9de
Make test.sh seq
kdy1 Mar 24, 2025
d2e925f
handle_known_delete
kdy1 Mar 24, 2025
4b1eca0
fix
kdy1 Mar 24, 2025
8ce571c
tests
kdy1 Mar 24, 2025
87ff68e
Update test refs (unverified)
kdy1 Mar 24, 2025
86ae574
negate cost
kdy1 Mar 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/gorgeous-games-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
swc_ecma_transforms_optimization: minor
swc_ecma_minifier: minor
swc_core: minor
swc_ecma_ast: minor
---

perf(es/minifier): Merge `expr_simplifier` into pure optimizer
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
foo({
bar: function(data, baz) {
!(!(baz ? data.quxA : data.quxB) && !(baz ? data.corgeA : data.corgeB) && (baz ? data.get("waldo") : data.waldo)) && ((baz ? data.quxA : data.quxB) || (baz ? data.get("waldo") : data.waldo) || (baz ? !data.corgeA : !data.corgeB)) || pass();
!(!(baz ? data.quxA : data.quxB) && !(baz ? data.corgeA : data.corgeB) && (baz ? data.get("waldo") : data.waldo)) ? (baz ? data.quxA : data.quxB) || (baz ? data.get("waldo") : data.waldo) || (baz ? !data.corgeA : !data.corgeB) || pass() : pass();
}
});
4 changes: 2 additions & 2 deletions crates/swc/tests/fixture/issues-4xxx/4953/output/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"use strict";
function _default(e, t) {
"use strict";
!function(e) {
(function(e) {
"use strict";
e.vr = function(e, t, r) {
return function() {
return '123';
};
};
}(t);
})(t);
}
Object.defineProperty(exports, "__esModule", {
value: !0
Expand Down
1 change: 0 additions & 1 deletion crates/swc/tests/fixture/issues-7xxx/7750/output/1.js
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
true;
18 changes: 9 additions & 9 deletions crates/swc/tests/libs-size.snapshot.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
| File | Original Size | Compressed Size | Gzipped Size |
| --- | --- | --- | --- |
| antd.js | 6.38 MiB | 2.05 MiB | 444.49 KiB |
| d3.js | 542.74 KiB | 259.02 KiB | 85.06 KiB |
| echarts.js | 3.41 MiB | 971.32 KiB | 313.36 KiB |
| jquery.js | 280.89 KiB | 87.12 KiB | 30.16 KiB |
| antd.js | 6.38 MiB | 2.05 MiB | 444.48 KiB |
| d3.js | 542.74 KiB | 259.01 KiB | 85.06 KiB |
| echarts.js | 3.41 MiB | 971.23 KiB | 313.32 KiB |
| jquery.js | 280.89 KiB | 87.11 KiB | 30.15 KiB |
| lodash.js | 531.35 KiB | 68.18 KiB | 24.52 KiB |
| moment.js | 169.83 KiB | 57.03 KiB | 18.21 KiB |
| react.js | 70.45 KiB | 22.28 KiB | 8.00 KiB |
| terser.js | 1.08 MiB | 444.90 KiB | 120.46 KiB |
| three.js | 1.19 MiB | 627.93 KiB | 154.57 KiB |
| typescript.js | 10.45 MiB | 3.17 MiB | 845.79 KiB |
| victory.js | 2.30 MiB | 689.66 KiB | 153.66 KiB |
| vue.js | 334.13 KiB | 112.95 KiB | 41.68 KiB |
| terser.js | 1.08 MiB | 444.89 KiB | 120.44 KiB |
| three.js | 1.19 MiB | 627.93 KiB | 154.56 KiB |
| typescript.js | 10.45 MiB | 3.17 MiB | 845.82 KiB |
| victory.js | 2.30 MiB | 689.65 KiB | 153.64 KiB |
| vue.js | 334.13 KiB | 112.95 KiB | 41.69 KiB |
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
//// [arrayOfFunctionTypes3.ts]
var a, a2, b2, c2;
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
[
function() {
return 1;
},
function() {}
][0](), new function C() {
][0]();
var a, a2, b2, c2, C = function C() {
_class_call_check(this, C);
}(), a(''), a(1), (0, [
};
new [
C,
C
][0](), a(''), a(1), (0, [
a2,
b2,
c2
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//// [destructuringControlFlow.ts]
import "@swc/helpers/_/_sliced_to_array";
[
"foo"
][1].toUpperCase();
(void 0).toUpperCase();
2 changes: 1 addition & 1 deletion crates/swc/tests/tsc-references/enumBasics.2.minified.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
//// [objectSpreadSetonlyAccessor.ts]
({
...{
set foo (_v){}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function Alert(output) {
CompilerDiagnostics.debug = !1, CompilerDiagnostics.diagnosticWriter = null, CompilerDiagnostics.analysisPass = 0, CompilerDiagnostics.Alert = Alert, CompilerDiagnostics.debugPrint = function(s) {
CompilerDiagnostics.debug && Alert(s);
}, CompilerDiagnostics.assert = function(condition, s) {
CompilerDiagnostics.debug && !condition && Alert(s);
CompilerDiagnostics.debug && (condition || Alert(s));
};
var CompilerDiagnostics1;
export { CompilerDiagnostics1 as CompilerDiagnostics };
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function Alert(output) {
CompilerDiagnostics.debug = !1, CompilerDiagnostics.diagnosticWriter = null, CompilerDiagnostics.analysisPass = 0, CompilerDiagnostics.Alert = Alert, CompilerDiagnostics.debugPrint = function(s) {
CompilerDiagnostics.debug && Alert(s);
}, CompilerDiagnostics.assert = function(condition, s) {
CompilerDiagnostics.debug && !condition && Alert(s);
CompilerDiagnostics.debug && (condition || Alert(s));
}, TypeScript1.NullLogger = /*#__PURE__*/ function() {
function NullLogger() {
_class_call_check(this, NullLogger);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
//// [privateNameComputedPropertyName2.ts]
let getX;
import { _ as _class_private_field_get } from "@swc/helpers/_/_class_private_field_get";
import { _ as _class_private_field_init } from "@swc/helpers/_/_class_private_field_init";
import { _ as _class_private_field_set } from "@swc/helpers/_/_class_private_field_set";
var _x = /*#__PURE__*/ new WeakMap();
console.log(_class_private_field_get(new class {
_() {}
let _tmp = (getX = (a)=>_class_private_field_get(a, _x), "_");
console.log(getX(new class {
[_tmp]() {}
constructor(){
_class_private_field_init(this, _x, {
writable: !0,
value: void 0
}), _class_private_field_set(this, _x, 100);
}
}, _x));
}));
5 changes: 1 addition & 4 deletions crates/swc/tests/tsc-references/typeAliases.2.minified.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,4 @@
import "@swc/helpers/_/_class_call_check";
foo13(x13_1, x13_2), foo13(x13_2, x13_1);
var E, x13_1, x13_2, x, E1 = ((E = E1 || {})[E.x = 10] = "x", E);
f15(10).toLowerCase(), f16(x), [
"1",
!1
][0].toLowerCase();
f15(10).toLowerCase(), f16(x);
41 changes: 20 additions & 21 deletions crates/swc/tests/vercel/full/ms/1/output/index.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,63 @@
import { _ as e } from "@swc/helpers/_/_type_of";
var s = 86400000 * 7;
export default function(c, r) {
export default function(a, c) {
try {
if ("string" == typeof c && c.length > 0) {
var n, t, o, u, i, h = c;
if ((h = String(h)).length > 100) throw Error("Value exceeds the maximum length of 100 characters.");
var m = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(h);
if (!m) return NaN;
var d = parseFloat(m[1]), l = (m[2] || "ms").toLowerCase();
switch(l){
if ("string" == typeof a && a.length > 0) {
var r, n, t, o, u, i = a;
if ((i = String(i)).length > 100) throw Error("Value exceeds the maximum length of 100 characters.");
var h = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(i);
if (!h) return NaN;
var m = parseFloat(h[1]), d = (h[2] || "ms").toLowerCase();
switch(d){
case "years":
case "year":
case "yrs":
case "yr":
case "y":
return 31557600000 * d;
return 31557600000 * m;
case "weeks":
case "week":
case "w":
return d * s;
return 604800000 * m;
case "days":
case "day":
case "d":
return 86400000 * d;
return 86400000 * m;
case "hours":
case "hour":
case "hrs":
case "hr":
case "h":
return 3600000 * d;
return 3600000 * m;
case "minutes":
case "minute":
case "mins":
case "min":
case "m":
return 60000 * d;
return 60000 * m;
case "seconds":
case "second":
case "secs":
case "sec":
case "s":
return 1000 * d;
return 1000 * m;
case "milliseconds":
case "millisecond":
case "msecs":
case "msec":
case "ms":
return d;
return m;
default:
throw Error("The unit ".concat(l, " was matched, but no matching case exists."));
throw Error("The unit ".concat(d, " was matched, but no matching case exists."));
}
}
if ("number" == typeof c && isFinite(c)) {
return (null == r ? void 0 : r.long) ? (t = c, (o = Math.abs(t)) >= 86400000 ? a(t, o, 86400000, "day") : o >= 3600000 ? a(t, o, 3600000, "hour") : o >= 60000 ? a(t, o, 60000, "minute") : o >= 1000 ? a(t, o, 1000, "second") : "".concat(t, " ms")) : (u = c, (i = Math.abs(u)) >= 86400000 ? "".concat(Math.round(u / 86400000), "d") : i >= 3600000 ? "".concat(Math.round(u / 3600000), "h") : i >= 60000 ? "".concat(Math.round(u / 60000), "m") : i >= 1000 ? "".concat(Math.round(u / 1000), "s") : "".concat(u, "ms"));
if ("number" == typeof a && isFinite(a)) {
return (null == c ? void 0 : c.long) ? (n = a, (t = Math.abs(n)) >= 86400000 ? s(n, t, 86400000, "day") : t >= 3600000 ? s(n, t, 3600000, "hour") : t >= 60000 ? s(n, t, 60000, "minute") : t >= 1000 ? s(n, t, 1000, "second") : "".concat(n, " ms")) : (o = a, (u = Math.abs(o)) >= 86400000 ? "".concat(Math.round(o / 86400000), "d") : u >= 3600000 ? "".concat(Math.round(o / 3600000), "h") : u >= 60000 ? "".concat(Math.round(o / 60000), "m") : u >= 1000 ? "".concat(Math.round(o / 1000), "s") : "".concat(o, "ms"));
}
throw Error("Value is not a string or number.");
} catch (s) {
throw Error((void 0 === (n = s) ? "undefined" : e(n)) === "object" && null !== n && "message" in n ? "".concat(s.message, ". value=").concat(JSON.stringify(c)) : "An unknown error has occurred.");
throw Error((void 0 === (r = s) ? "undefined" : e(r)) === "object" && null !== r && "message" in r ? "".concat(s.message, ". value=").concat(JSON.stringify(a)) : "An unknown error has occurred.");
}
}
function a(e, s, a, c) {
function s(e, s, a, c) {
return "".concat(Math.round(e / a), " ").concat(c).concat(s >= 1.5 * a ? "s" : "");
}
4 changes: 4 additions & 0 deletions crates/swc_ecma_ast/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ impl Expr {
.into()
}

pub fn is_null(&self) -> bool {
matches!(self, Expr::Lit(Lit::Null(_)))
}

pub fn leftmost(&self) -> Option<&Ident> {
match self {
Expr::Ident(i) => Some(i),
Expand Down
85 changes: 6 additions & 79 deletions crates/swc_ecma_minifier/src/compress/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
use std::borrow::Cow;
#[cfg(feature = "debug")]
use std::fmt::{self, Debug, Display, Formatter};
#[cfg(feature = "debug")]
use std::thread;
use std::{borrow::Cow, time::Instant};

#[cfg(feature = "pretty_assertions")]
use pretty_assertions::assert_eq;
use swc_common::pass::{CompilerPass, Optional, Repeated};
use swc_common::pass::{CompilerPass, Repeated};
use swc_ecma_ast::*;
use swc_ecma_transforms_optimization::simplify::{expr_simplifier, ExprSimplifierConfig};
use swc_ecma_usage_analyzer::marks::Marks;
use swc_ecma_visit::VisitMutWith;
#[cfg(debug_assertions)]
use swc_ecma_visit::VisitWith;
use swc_ecma_visit::{visit_mut_pass, VisitMutWith};
use swc_timer::timer;
use tracing::debug;

Expand All @@ -26,7 +25,7 @@ use crate::{
mode::Mode,
option::{CompressOptions, MangleOptions},
program_data::analyze,
util::{force_dump_program, now},
util::force_dump_program,
};

mod hoist_decls;
Expand All @@ -43,25 +42,14 @@ pub(crate) fn compressor<'a, M>(
where
M: Mode,
{
let compressor = Compressor {
Compressor {
marks,
options,
mangle_options,
changed: false,
pass: 1,
mode,
};

(
compressor,
Optional {
enabled: options.evaluate || options.side_effects,
visitor: visit_mut_pass(expr_simplifier(
marks.unresolved_mark,
ExprSimplifierConfig {},
)),
},
)
}
}

struct Compressor<'a> {
Expand Down Expand Up @@ -179,56 +167,6 @@ impl Compressor<'_> {
}
}

{
tracing::info!(
"compress: Running expression simplifier (pass = {})",
self.pass
);

let start_time = now();

#[cfg(feature = "debug")]
let start = force_dump_program(n);

let mut visitor = expr_simplifier(self.marks.unresolved_mark, ExprSimplifierConfig {});
n.visit_mut_with(&mut visitor);

self.changed |= visitor.changed();
if visitor.changed() {
debug!("compressor: Simplified expressions");
#[cfg(feature = "debug")]
{
debug!(
"===== Simplified =====\n{start}===== ===== ===== =====\n{}",
force_dump_program(n)
);
}
}

if let Some(start_time) = start_time {
let end_time = Instant::now();

tracing::info!(
"compress: expr_simplifier took {:?} (pass = {})",
end_time - start_time,
self.pass
);
}

#[cfg(feature = "debug")]
if !visitor.changed() {
let simplified = force_dump_program(n);
if start != simplified {
assert_eq!(
DebugUsingDisplay(&start),
DebugUsingDisplay(&simplified),
"Invalid state: expr_simplifier: The code is changed but changed is not \
setted to true",
)
}
}
}

#[cfg(debug_assertions)]
{
n.visit_with(&mut AssertValid);
Expand Down Expand Up @@ -259,14 +197,3 @@ impl Compressor<'_> {
}
}
}

#[cfg(feature = "debug")]
#[derive(PartialEq, Eq)]
struct DebugUsingDisplay<'a>(pub &'a str);

#[cfg(feature = "debug")]
impl Debug for DebugUsingDisplay<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self.0, f)
}
}
Loading
Loading