improve compression of undefined, NaN & Infinitiy
- migrate transformation logic from `OutputStream` to `Compressor` - always turn `undefined` into `void 0` (unless `unsafe`) - always keep `NaN` except when avoiding local variable redefinition - introduce `keep_infinity` to suppress `1/0` transform, except when avoiding local variable redefinition supersedes #1723 fixes #1730
This commit is contained in:
parent
da0273e805
commit
e58fddce42
|
|
@ -443,6 +443,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
||||||
integer argument larger than 1 to further reduce code size in some cases.
|
integer argument larger than 1 to further reduce code size in some cases.
|
||||||
Note: raising the number of passes will increase uglify compress time.
|
Note: raising the number of passes will increase uglify compress time.
|
||||||
|
|
||||||
|
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
|
||||||
|
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||||
|
|
||||||
### The `unsafe` option
|
### The `unsafe` option
|
||||||
|
|
||||||
It enables some transformations that *might* break code logic in certain
|
It enables some transformations that *might* break code logic in certain
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ function Compressor(options, false_by_default) {
|
||||||
join_vars : !false_by_default,
|
join_vars : !false_by_default,
|
||||||
keep_fargs : true,
|
keep_fargs : true,
|
||||||
keep_fnames : false,
|
keep_fnames : false,
|
||||||
|
keep_infinity : false,
|
||||||
loops : !false_by_default,
|
loops : !false_by_default,
|
||||||
negate_iife : !false_by_default,
|
negate_iife : !false_by_default,
|
||||||
passes : 1,
|
passes : 1,
|
||||||
|
|
@ -3528,7 +3529,9 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Infinity, function(self, compressor){
|
OPT(AST_Infinity, function(self, compressor){
|
||||||
return make_node(AST_Binary, self, {
|
var retain = compressor.option("keep_infinity")
|
||||||
|
&& !compressor.find_parent(AST_Scope).find_variable("Infinity");
|
||||||
|
return retain ? self : make_node(AST_Binary, self, {
|
||||||
operator: "/",
|
operator: "/",
|
||||||
left: make_node(AST_Number, self, {
|
left: make_node(AST_Number, self, {
|
||||||
value: 1
|
value: 1
|
||||||
|
|
@ -3540,7 +3543,7 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_NaN, function(self, compressor){
|
OPT(AST_NaN, function(self, compressor){
|
||||||
return make_node(AST_Binary, self, {
|
return compressor.find_parent(AST_Scope).find_variable("NaN") ? make_node(AST_Binary, self, {
|
||||||
operator: "/",
|
operator: "/",
|
||||||
left: make_node(AST_Number, self, {
|
left: make_node(AST_Number, self, {
|
||||||
value: 0
|
value: 0
|
||||||
|
|
@ -3548,7 +3551,7 @@ merge(Compressor.prototype, {
|
||||||
right: make_node(AST_Number, self, {
|
right: make_node(AST_Number, self, {
|
||||||
value: 0
|
value: 0
|
||||||
})
|
})
|
||||||
});
|
}) : self;
|
||||||
});
|
});
|
||||||
|
|
||||||
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
||||||
|
|
|
||||||
|
|
@ -840,8 +840,8 @@ equality_conditionals_false: {
|
||||||
f(0, true, 0),
|
f(0, true, 0),
|
||||||
f(1, 2, 3),
|
f(1, 2, 3),
|
||||||
f(1, null, 3),
|
f(1, null, 3),
|
||||||
f(0/0),
|
f(NaN),
|
||||||
f(0/0, "foo");
|
f(NaN, "foo");
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
@ -888,8 +888,8 @@ equality_conditionals_true: {
|
||||||
f(0, true, 0),
|
f(0, true, 0),
|
||||||
f(1, 2, 3),
|
f(1, 2, 3),
|
||||||
f(1, null, 3),
|
f(1, null, 3),
|
||||||
f(0/0),
|
f(NaN),
|
||||||
f(0/0, "foo");
|
f(NaN, "foo");
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ and: {
|
||||||
a = 7;
|
a = 7;
|
||||||
|
|
||||||
a = false;
|
a = false;
|
||||||
a = 0/0;
|
a = NaN;
|
||||||
a = 0;
|
a = 0;
|
||||||
a = void 0;
|
a = void 0;
|
||||||
a = null;
|
a = null;
|
||||||
|
|
@ -67,7 +67,7 @@ and: {
|
||||||
a = 6 << condition && -4.5;
|
a = 6 << condition && -4.5;
|
||||||
|
|
||||||
a = condition && false;
|
a = condition && false;
|
||||||
a = console.log("b") && 0/0;
|
a = console.log("b") && NaN;
|
||||||
a = console.log("c") && 0;
|
a = console.log("c") && 0;
|
||||||
a = 2 * condition && void 0;
|
a = 2 * condition && void 0;
|
||||||
a = condition + 3 && null;
|
a = condition + 3 && null;
|
||||||
|
|
@ -149,7 +149,7 @@ or: {
|
||||||
a = 6 << condition || -4.5;
|
a = 6 << condition || -4.5;
|
||||||
|
|
||||||
a = condition || false;
|
a = condition || false;
|
||||||
a = console.log("b") || 0/0;
|
a = console.log("b") || NaN;
|
||||||
a = console.log("c") || 0;
|
a = console.log("c") || 0;
|
||||||
a = 2 * condition || void 0;
|
a = 2 * condition || void 0;
|
||||||
a = condition + 3 || null;
|
a = condition + 3 || null;
|
||||||
|
|
@ -533,7 +533,7 @@ unsafe_array: {
|
||||||
[1, 2, 3, a][0] + 1,
|
[1, 2, 3, a][0] + 1,
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
0/0,
|
NaN,
|
||||||
"1,21",
|
"1,21",
|
||||||
5,
|
5,
|
||||||
(void 0)[1] + 1
|
(void 0)[1] + 1
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,7 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
sequences: false,
|
sequences: false,
|
||||||
|
keep_infinity: false,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var f = console.log;
|
var f = console.log;
|
||||||
|
|
@ -224,10 +225,73 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
|
||||||
};
|
};
|
||||||
if (o) {
|
if (o) {
|
||||||
f(void 0, void 0);
|
f(void 0, void 0);
|
||||||
f(0/0, 0/0);
|
f(NaN, NaN);
|
||||||
f(1/0, 1/0);
|
f(1/0, 1/0);
|
||||||
f(-1/0, -1/0);
|
f(-1/0, -1/0);
|
||||||
f(0/0, 0/0);
|
f(NaN, NaN);
|
||||||
|
}
|
||||||
|
with (o) {
|
||||||
|
f(undefined, void 0);
|
||||||
|
f(NaN, 0/0);
|
||||||
|
f(Infinity, 1/0);
|
||||||
|
f(-Infinity, -1/0);
|
||||||
|
f(9 + undefined, 9 + void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
assorted_Infinity_NaN_undefined_in_with_scope_keep_infinity: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
evaluate: true,
|
||||||
|
dead_code: true,
|
||||||
|
conditionals: true,
|
||||||
|
comparisons: true,
|
||||||
|
booleans: true,
|
||||||
|
hoist_funs: true,
|
||||||
|
keep_fargs: true,
|
||||||
|
if_return: true,
|
||||||
|
join_vars: true,
|
||||||
|
cascade: true,
|
||||||
|
side_effects: true,
|
||||||
|
sequences: false,
|
||||||
|
keep_infinity: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var f = console.log;
|
||||||
|
var o = {
|
||||||
|
undefined : 3,
|
||||||
|
NaN : 4,
|
||||||
|
Infinity : 5,
|
||||||
|
};
|
||||||
|
if (o) {
|
||||||
|
f(undefined, void 0);
|
||||||
|
f(NaN, 0/0);
|
||||||
|
f(Infinity, 1/0);
|
||||||
|
f(-Infinity, -(1/0));
|
||||||
|
f(2 + 7 + undefined, 2 + 7 + void 0);
|
||||||
|
}
|
||||||
|
with (o) {
|
||||||
|
f(undefined, void 0);
|
||||||
|
f(NaN, 0/0);
|
||||||
|
f(Infinity, 1/0);
|
||||||
|
f(-Infinity, -(1/0));
|
||||||
|
f(2 + 7 + undefined, 2 + 7 + void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var f = console.log, o = {
|
||||||
|
undefined : 3,
|
||||||
|
NaN : 4,
|
||||||
|
Infinity : 5
|
||||||
|
};
|
||||||
|
if (o) {
|
||||||
|
f(void 0, void 0);
|
||||||
|
f(NaN, NaN);
|
||||||
|
f(Infinity, 1/0);
|
||||||
|
f(-Infinity, -1/0);
|
||||||
|
f(NaN, NaN);
|
||||||
}
|
}
|
||||||
with (o) {
|
with (o) {
|
||||||
f(undefined, void 0);
|
f(undefined, void 0);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ NaN_and_Infinity_must_have_parens: {
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(1/0).toString();
|
(1/0).toString();
|
||||||
(0/0).toString();
|
NaN.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,6 +24,36 @@ NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NaN_and_Infinity_must_have_parens_evaluate: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(123456789 / 0).toString();
|
||||||
|
(+"foo").toString();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(1/0).toString();
|
||||||
|
NaN.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined_evaluate: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var Infinity, NaN;
|
||||||
|
(123456789 / 0).toString();
|
||||||
|
(+"foo").toString();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var Infinity, NaN;
|
||||||
|
(1/0).toString();
|
||||||
|
(0/0).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
beautify_off_1: {
|
beautify_off_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ unary_binary_parenthesis: {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var v = [ 0, 1, 0/0, 1/0, null, void 0, true, false, "", "foo", /foo/ ];
|
var v = [ 0, 1, NaN, 1/0, null, void 0, true, false, "", "foo", /foo/ ];
|
||||||
v.forEach(function(x) {
|
v.forEach(function(x) {
|
||||||
v.forEach(function(y) {
|
v.forEach(function(y) {
|
||||||
console.log(
|
console.log(
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ sub_properties: {
|
||||||
a[3.14] = 3;
|
a[3.14] = 3;
|
||||||
a.if = 4;
|
a.if = 4;
|
||||||
a["foo bar"] = 5;
|
a["foo bar"] = 5;
|
||||||
a[0/0] = 6;
|
a[NaN] = 6;
|
||||||
a[null] = 7;
|
a[null] = 7;
|
||||||
a[void 0] = 8;
|
a[void 0] = 8;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user