Skip to content

Commit

Permalink
feat(es/minifier): Turn Array/Object calls into literals (#4947)
Browse files Browse the repository at this point in the history
  • Loading branch information
Austaras committed Jun 12, 2022
1 parent 461b990 commit 47bdc6a
Show file tree
Hide file tree
Showing 28 changed files with 313 additions and 164 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var A;
!function(A1) {
var beez;
A1.beez2 = Array(), A1.beez = beez;
A1.beez2 = [], A1.beez = beez;
}(A || (A = {}));
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import _class_call_check from "@swc/helpers/lib/_class_call_check.js";
"use strict";
_class_call_check(this, B);
};
A1.beez2 = Array(), A1.beez = beez;
A1.beez2 = [], A1.beez = beez;
}(A || (A = {}));
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ var a1 = [
var a2 = [
,
,
,
].concat(_to_consumable_array(a0), [
"hello"
]);
var a3 = [
,
,
].concat(_to_consumable_array(a0));
var a4 = [
function() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ var a0 = [
[
,
,
,
].concat(_to_consumable_array(a0), [
"hello"
]), [
,
,
].concat(_to_consumable_array(a0)), _to_consumable_array(a0).concat([
,
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ var a1 = [
var a2 = [
,
,
,
].concat(_to_consumable_array(a0), [
"hello"
]);
var a3 = [
,
,
].concat(_to_consumable_array(a0));
var a4 = [
function() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ var a0 = [
], a2 = [
,
,
,
].concat(_to_consumable_array(a0), [
"hello"
]), a3 = [
,
,
].concat(_to_consumable_array(a0));
_to_consumable_array(a0).concat([
,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
function foo(t) {}
foo(1), foo(null), foo(new Object()), foo(1), foo(new Date());
foo(1), foo(null), foo({}), foo(1), foo(new Date());
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
function foo(t) {}
foo(1), foo(null), foo(new Object()), foo(1), foo(new Date());
foo(1), foo(null), foo({}), foo(1), foo(new Date());
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var E, F, x;
function foo(x, a, b) {}
function foo2(x, a, b) {}
foo('', (x)=>'', (x)=>null), foo('', (x)=>'', (x)=>null), foo('', (x)=>'', (x)=>''), foo(null, (x)=>'', (x)=>''), foo(null, (x)=>'', (x)=>''), foo(new Object(), (x)=>'', (x)=>''), function(E) {
foo('', (x)=>'', (x)=>null), foo('', (x)=>'', (x)=>null), foo('', (x)=>'', (x)=>''), foo(null, (x)=>'', (x)=>''), foo(null, (x)=>'', (x)=>''), foo({}, (x)=>'', (x)=>''), function(E) {
E[E.A = 0] = "A";
}(E || (E = {})), function(F) {
F[F.A = 0] = "A";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ foo("", function(x) {
return "";
}, function(x) {
return "";
}), foo(new Object(), function(x) {
}), foo({}, function(x) {
return "";
}, function(x) {
return "";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
runTestCase(function() {
var a = Array(!1, void 0, null, "0", {
toString: function() {
return 0;
}
}, -1.3333333333333, "str", -0, !0, 0, 1, 1, 0, !1, -4 / 3, -4 / 3);
var a = [
!1,
void 0,
null,
"0",
{
toString: function() {
return 0;
}
},
-1.3333333333333,
"str",
-0,
!0,
0,
1,
1,
0,
!1,
-4 / 3,
-4 / 3
];
if (14 === a.indexOf(-4 / 3) && 7 === a.indexOf(0) && 7 === a.indexOf(-0) && 10 === a.indexOf(1)) return !0;
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
runTestCase(function() {
var a = Array(!1, void 0, null, "0", {
toString: function() {
return 0;
}
}, -1.3333333333333, "str", -0, !0, 0, 1, 1, 0, !1, -4 / 3, -4 / 3);
var a = [
!1,
void 0,
null,
"0",
{
toString: function() {
return 0;
}
},
-1.3333333333333,
"str",
-0,
!0,
0,
1,
1,
0,
!1,
-4 / 3,
-4 / 3
];
if (14 === a.indexOf(-4 / 3) && 7 === a.indexOf(0) && 7 === a.indexOf(-0) && 10 === a.indexOf(1)) return !0;
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var r = {
s: new Object()
s: {}
};
r.s && r.s.toFixed();
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var r = {
s: new Object()
s: {}
};
r.s && r.s.toFixed();
3 changes: 2 additions & 1 deletion crates/swc_ecma_ast/src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ add_bitflags!(
/// If the literal is empty, do not add spaces between braces.
NoSpaceIfEmpty: 1 << 18,
SingleElement: 1 << 19,
ForceTrailingComma: 1 << 20,
},
// Optimization.
Values {
CanSkipTrailingComma: 1 << 20
CanSkipTrailingComma: 1 << 21
},
/// Precomputed Formats
Values {
Expand Down
44 changes: 23 additions & 21 deletions crates/swc_ecma_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1835,11 +1835,12 @@ where
srcmap!(node, true);

punct!("[");
self.emit_list(
node.span(),
Some(&node.elems),
ListFormat::ArrayLiteralExpressionElements,
)?;
let mut format = ListFormat::ArrayLiteralExpressionElements;
if let Some(None) = node.elems.last() {
format |= ListFormat::ForceTrailingComma;
}

self.emit_list(node.span(), Some(&node.elems), format)?;
punct!("]");

srcmap!(node, false);
Expand Down Expand Up @@ -2224,25 +2225,26 @@ where
}

// Write a trailing comma, if requested.
let has_trailing_comma = format.contains(ListFormat::AllowTrailingComma) && {
if parent_node.is_dummy() {
false
} else {
match self.cm.span_to_snippet(parent_node) {
Ok(snippet) => {
if snippet.len() < 3 {
false
} else {
let last_char = snippet.chars().last().unwrap();
snippet[..snippet.len() - last_char.len_utf8()]
.trim()
.ends_with(',')
let has_trailing_comma = format.contains(ListFormat::ForceTrailingComma)
|| format.contains(ListFormat::AllowTrailingComma) && {
if parent_node.is_dummy() {
false
} else {
match self.cm.span_to_snippet(parent_node) {
Ok(snippet) => {
if snippet.len() < 3 {
false
} else {
let last_char = snippet.chars().last().unwrap();
snippet[..snippet.len() - last_char.len_utf8()]
.trim()
.ends_with(',')
}
}
_ => false,
}
_ => false,
}
}
};
};

if has_trailing_comma
&& format.contains(ListFormat::CommaDelimited)
Expand Down
100 changes: 0 additions & 100 deletions crates/swc_ecma_minifier/src/compress/optimize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,104 +1101,6 @@ where
Some(e.take())
}

/// `new RegExp("([Sap]+)", "ig")` => `/([Sap]+)/gi`
fn compress_regexp(&mut self, e: &mut Expr) {
let (span, args) = match e {
Expr::New(NewExpr {
span,
callee,
args: Some(args),
..
})
| Expr::Call(CallExpr {
span,
callee: Callee::Expr(callee),
args,
..
}) => match &**callee {
Expr::Ident(Ident {
sym: js_word!("RegExp"),
..
}) => (*span, args),
_ => return,
},
_ => return,
};

if args.is_empty() || args.len() > 2 {
return;
}

// We aborts the method if arguments are not literals.
if args.iter().any(|v| {
v.spread.is_some()
|| match &*v.expr {
Expr::Lit(Lit::Str(s)) => {
if s.value.contains(|c: char| {
// whitelist
!c.is_ascii_alphanumeric()
&& !matches!(c, '%' | '[' | ']' | '(' | ')' | '{' | '}' | '-' | '+')
}) {
return true;
}
if s.value.contains("\\\0") || s.value.contains('/') {
return true;
}

false
}
_ => true,
}
}) {
return;
}

//
let pattern = args[0].expr.take();

let pattern = match *pattern {
Expr::Lit(Lit::Str(s)) => s.value,
_ => {
unreachable!()
}
};

if pattern.is_empty() {
// For some expressions `RegExp()` and `RegExp("")`
// Theoretically we can use `/(?:)/` to achieve shorter code
// But some browsers released in 2015 don't support them yet.
args[0].expr = pattern.into();
return;
}

let flags = args
.get_mut(1)
.map(|v| v.expr.take())
.map(|v| match *v {
Expr::Lit(Lit::Str(s)) => {
assert!(s.value.is_ascii());

let s = s.value.to_string();
let mut bytes = s.into_bytes();
bytes.sort_unstable();

String::from_utf8(bytes).unwrap().into()
}
_ => {
unreachable!()
}
})
.unwrap_or(js_word!(""));

report_change!("Converting call to RegExp into a regexp literal");
self.changed = true;
*e = Expr::Lit(Lit::Regex(Regex {
span,
exp: pattern,
flags,
}))
}

fn merge_var_decls(&mut self, stmts: &mut Vec<Stmt>) {
if !self.options.join_vars && !self.options.hoist_vars {
return;
Expand Down Expand Up @@ -1739,8 +1641,6 @@ where

self.drop_unused_assignments(e);

self.compress_regexp(e);

self.compress_lits(e);

self.compress_typeofs(e);
Expand Down

1 comment on commit 47bdc6a

@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: 47bdc6a Previous: 4ada9c7 Ratio
es/full/minify/libraries/antd 2235061938 ns/iter (± 105091516) 1745453280 ns/iter (± 58952994) 1.28
es/full/minify/libraries/d3 504527423 ns/iter (± 16991159) 407442172 ns/iter (± 3755802) 1.24
es/full/minify/libraries/echarts 2531061772 ns/iter (± 39462706) 2152943471 ns/iter (± 8568491) 1.18
es/full/minify/libraries/jquery 113846076 ns/iter (± 3635881) 89512909 ns/iter (± 469031) 1.27
es/full/minify/libraries/lodash 154855031 ns/iter (± 4645049) 126382077 ns/iter (± 532211) 1.23
es/full/minify/libraries/moment 65932380 ns/iter (± 1936911) 53150632 ns/iter (± 230069) 1.24
es/full/minify/libraries/react 21549302 ns/iter (± 272229) 17347661 ns/iter (± 42503) 1.24
es/full/minify/libraries/terser 806687606 ns/iter (± 17597735) 454959941 ns/iter (± 10831585) 1.77
es/full/minify/libraries/three 651975594 ns/iter (± 14584084) 525007983 ns/iter (± 17035607) 1.24
es/full/minify/libraries/typescript 5079260206 ns/iter (± 98075333) 4146207867 ns/iter (± 19831240) 1.23
es/full/minify/libraries/victory 941964462 ns/iter (± 22537778) 691697202 ns/iter (± 24977075) 1.36
es/full/minify/libraries/vue 175816579 ns/iter (± 6012800) 137557714 ns/iter (± 455153) 1.28
es/full/codegen/es3 40533 ns/iter (± 2932) 34065 ns/iter (± 144) 1.19
es/full/codegen/es5 39185 ns/iter (± 4378) 34109 ns/iter (± 132) 1.15
es/full/codegen/es2015 39262 ns/iter (± 2423) 34071 ns/iter (± 156) 1.15
es/full/codegen/es2016 40213 ns/iter (± 2103) 34059 ns/iter (± 174) 1.18
es/full/codegen/es2017 39024 ns/iter (± 2211) 34059 ns/iter (± 142) 1.15
es/full/codegen/es2018 38607 ns/iter (± 2274) 34057 ns/iter (± 161) 1.13
es/full/codegen/es2019 39686 ns/iter (± 6233) 34058 ns/iter (± 168) 1.17
es/full/codegen/es2020 39066 ns/iter (± 2436) 34062 ns/iter (± 154) 1.15
es/full/all/es3 230884443 ns/iter (± 8727756) 192490250 ns/iter (± 1251552) 1.20
es/full/all/es5 216987610 ns/iter (± 10116972) 180533530 ns/iter (± 1142722) 1.20
es/full/all/es2015 173377804 ns/iter (± 7589751) 145176920 ns/iter (± 1593559) 1.19
es/full/all/es2016 172029008 ns/iter (± 8973086) 144269928 ns/iter (± 1543644) 1.19
es/full/all/es2017 173948916 ns/iter (± 7838835) 143335423 ns/iter (± 1577464) 1.21
es/full/all/es2018 166952935 ns/iter (± 7596005) 142236081 ns/iter (± 1667527) 1.17
es/full/all/es2019 171308393 ns/iter (± 7230027) 142464646 ns/iter (± 2024955) 1.20
es/full/all/es2020 160869539 ns/iter (± 6365861) 136959339 ns/iter (± 1798442) 1.17
es/full/parser 766776 ns/iter (± 55563) 582253 ns/iter (± 52133) 1.32
es/full/base/fixer 41139 ns/iter (± 5221) 28083 ns/iter (± 207) 1.46
es/full/base/resolver_and_hygiene 191361 ns/iter (± 38840) 139761 ns/iter (± 1792) 1.37
serialization of ast node 206 ns/iter (± 11) 180 ns/iter (± 1) 1.14
serialization of serde 200 ns/iter (± 13) 182 ns/iter (± 0) 1.10

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

Please sign in to comment.