[Pkg-javascript-commits] [uglifyjs] 223/491: perform `reduce_vars` on safe literals (#2351)
Jonas Smedegaard
dr at jones.dk
Wed Feb 14 19:51:38 UTC 2018
This is an automated email from the git hooks/post-receive script.
js pushed a commit to annotated tag debian/3.3.10-1
in repository uglifyjs.
commit b810e2f8da4bfd42a8876b64d067e83dfd340aa1
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date: Mon Oct 9 12:25:06 2017 +0800
perform `reduce_vars` on safe literals (#2351)
- constant expression
- single reference
- same scope
- not across loop body
---
lib/compress.js | 63 +++++++++++---
test/compress/collapse_vars.js | 40 ++++++---
test/compress/drop-unused.js | 12 +--
test/compress/evaluate.js | 14 ++-
test/compress/reduce_vars.js | 193 ++++++++++++++++++++++++++++++++++++++++-
5 files changed, 286 insertions(+), 36 deletions(-)
diff --git a/lib/compress.js b/lib/compress.js
index 33b4ef0..c3876f9 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -297,6 +297,8 @@ merge(Compressor.prototype, {
if (node instanceof AST_SymbolRef) d.references.push(node);
d.fixed = false;
});
+ var in_loop = null;
+ var loop_ids = Object.create(null);
var tw = new TreeWalker(function(node, descend) {
node._squeezed = false;
node._optimized = false;
@@ -307,7 +309,7 @@ merge(Compressor.prototype, {
var d = node.definition();
d.references.push(node);
if (d.fixed === undefined || !safe_to_read(d)
- || is_modified(node, 0, is_immutable(node.fixed_value()))) {
+ || is_modified(node, 0, is_immutable(node))) {
d.fixed = false;
} else {
var parent = tw.parent();
@@ -329,6 +331,7 @@ merge(Compressor.prototype, {
d.fixed = function() {
return node.value;
};
+ loop_ids[d.id] = in_loop;
mark(d, false);
descend();
} else {
@@ -384,6 +387,7 @@ merge(Compressor.prototype, {
d.fixed = function() {
return iife.args[i] || make_node(AST_Undefined, iife);
};
+ loop_ids[d.id] = in_loop;
mark(d, true);
} else {
d.fixed = false;
@@ -431,10 +435,13 @@ merge(Compressor.prototype, {
return true;
}
if (node instanceof AST_DWLoop) {
+ var saved_loop = in_loop;
+ in_loop = node;
push();
node.condition.walk(tw);
node.body.walk(tw);
pop();
+ in_loop = saved_loop;
return true;
}
if (node instanceof AST_LabeledStatement) {
@@ -445,6 +452,8 @@ merge(Compressor.prototype, {
}
if (node instanceof AST_For) {
if (node.init) node.init.walk(tw);
+ var saved_loop = in_loop;
+ in_loop = node;
if (node.condition) {
push();
node.condition.walk(tw);
@@ -458,14 +467,18 @@ merge(Compressor.prototype, {
node.step.walk(tw);
pop();
}
+ in_loop = saved_loop;
return true;
}
if (node instanceof AST_ForIn) {
node.init.walk(suppressor);
node.object.walk(tw);
+ var saved_loop = in_loop;
+ in_loop = node;
push();
node.body.walk(tw);
pop();
+ in_loop = saved_loop;
return true;
}
if (node instanceof AST_Try) {
@@ -535,10 +548,23 @@ merge(Compressor.prototype, {
}
def.references = [];
def.should_replace = undefined;
- }
-
- function is_immutable(value) {
- return value && value.is_constant() || value instanceof AST_Lambda;
+ def.single_use = undefined;
+ }
+
+ function is_immutable(node) {
+ var value = node.fixed_value();
+ if (!value) return false;
+ if (value.is_constant()) return true;
+ if (compressor.option("unused")) {
+ var d = node.definition();
+ if (d.single_use === undefined) {
+ d.single_use = loop_ids[d.id] === in_loop
+ && d.scope === node.scope
+ && value.is_constant_expression();
+ }
+ if (d.references.length == 1 && d.single_use) return true;
+ }
+ return value instanceof AST_Lambda;
}
function is_modified(node, level, immutable) {
@@ -2115,6 +2141,22 @@ merge(Compressor.prototype, {
}
def(AST_Node, return_false);
def(AST_Constant, return_true);
+ def(AST_Function, function(){
+ var self = this;
+ var result = true;
+ self.walk(new TreeWalker(function(node) {
+ if (!result) return true;
+ if (node instanceof AST_SymbolRef) {
+ var def = node.definition();
+ if (self.enclosed.indexOf(def) >= 0
+ && self.variables.get(def.name) !== def) {
+ result = false;
+ return true;
+ }
+ }
+ }));
+ return result;
+ });
def(AST_Unary, function(){
return this.expression.is_constant_expression();
});
@@ -4078,12 +4120,13 @@ merge(Compressor.prototype, {
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
}
if (compressor.option("unused")
- && fixed instanceof AST_Function
&& d.references.length == 1
- && !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
- && !d.scope.uses_eval
- && compressor.find_parent(AST_Scope) === fixed.parent_scope) {
- return fixed.clone(true);
+ && (d.single_use || fixed instanceof AST_Function
+ && !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
+ && !d.scope.uses_eval
+ && compressor.find_parent(AST_Scope) === fixed.parent_scope)) {
+ var value = fixed.optimize(compressor);
+ return value === fixed ? fixed.clone(true) : value;
}
if (compressor.option("evaluate") && fixed) {
if (d.should_replace === undefined) {
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index 631f5b2..7d66f7c 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -1268,22 +1268,21 @@ collapse_vars_short_circuited_conditions: {
collapse_vars_regexp: {
options = {
+ booleans: true,
+ cascade: true,
collapse_vars: true,
- loops: false,
- sequences: true,
- dead_code: true,
- conditionals: true,
comparisons: true,
+ conditionals: true,
+ dead_code: true,
evaluate: true,
- booleans: true,
- unused: true,
- hoist_funs: true,
- keep_fargs: true,
if_return: true,
join_vars: true,
- cascade: true,
- side_effects: true,
+ hoist_funs: true,
+ keep_fargs: true,
+ loops: false,
reduce_vars: true,
+ side_effects: true,
+ unused: true,
}
input: {
function f1() {
@@ -1292,12 +1291,12 @@ collapse_vars_regexp: {
return [rx, k];
}
function f2() {
- var rx = /[abc123]+/;
+ var rx = /ab*/g;
return function(s) {
return rx.exec(s);
};
}
- (function(){
+ (function() {
var result;
var s = 'acdabcdeabbb';
var rx = /ab*/g;
@@ -1305,22 +1304,35 @@ collapse_vars_regexp: {
console.log(result[0]);
}
})();
+ (function() {
+ var result;
+ var s = 'acdabcdeabbb';
+ var rx = f2();
+ while (result = rx(s)) {
+ console.log(result[0]);
+ }
+ })();
}
expect: {
function f1() {
return [/[A-Z]+/, 9];
}
function f2() {
- var rx = /[abc123]+/;
+ var rx = /ab*/g;
return function(s) {
return rx.exec(s);
};
}
- (function(){
+ (function() {
var result, rx = /ab*/g;
while (result = rx.exec("acdabcdeabbb"))
console.log(result[0]);
})();
+ (function() {
+ var result, rx = f2();
+ while (result = rx("acdabcdeabbb"))
+ console.log(result[0]);
+ })();
}
expect_stdout: true
}
diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js
index c904854..4ce8d2e 100644
--- a/test/compress/drop-unused.js
+++ b/test/compress/drop-unused.js
@@ -751,12 +751,12 @@ issue_1583: {
expect: {
function m(t) {
(function(e) {
- t = e();
- })(function() {
- return (function(a) {
- return a;
- })(function(a) {});
- });
+ t = function() {
+ return (function(a) {
+ return function(a) {};
+ })();
+ }();
+ })();
}
}
}
diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js
index 1c73706..5f5a4a9 100644
--- a/test/compress/evaluate.js
+++ b/test/compress/evaluate.js
@@ -1021,6 +1021,7 @@ issue_1964_1: {
input: {
function f() {
var long_variable_name = /\s/;
+ console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
@@ -1028,11 +1029,15 @@ issue_1964_1: {
expect: {
function f() {
var long_variable_name = /\s/;
+ console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
- expect_stdout: "b"
+ expect_stdout: [
+ "\\s",
+ "b",
+ ]
}
issue_1964_2: {
@@ -1045,17 +1050,22 @@ issue_1964_2: {
input: {
function f() {
var long_variable_name = /\s/;
+ console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect: {
function f() {
+ console.log(/\s/.source);
return "a b c".split(/\s/)[1];
}
console.log(f());
}
- expect_stdout: "b"
+ expect_stdout: [
+ "\\s",
+ "b",
+ ]
}
array_slice_index: {
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 4e096d9..c1da299 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -172,6 +172,7 @@ unsafe_evaluate: {
options = {
evaluate : true,
reduce_vars : true,
+ side_effects : true,
unsafe : true,
unused : true
}
@@ -1898,10 +1899,7 @@ redefine_farg_3: {
console.log(f([]), g([]), h([]));
}
expect: {
- console.log(function(a) {
- var a;
- return typeof a;
- }([]), "number", "undefined");
+ console.log(typeof [], "number", "undefined");
}
expect_stdout: "object number undefined"
}
@@ -2629,3 +2627,190 @@ for_in_prop: {
}
expect_stdout: "1"
}
+
+obj_var_1: {
+ options = {
+ evaluate: true,
+ passes: 2,
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var C = 1;
+ var obj = {
+ bar: function() {
+ return C + C;
+ }
+ };
+ console.log(obj.bar());
+ }
+ expect: {
+ console.log({
+ bar: function() {
+ return 2;
+ }
+ }.bar());
+ }
+ expect_stdout: "2"
+}
+
+obj_var_2: {
+ options = {
+ evaluate: true,
+ inline: true,
+ passes: 2,
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ unsafe: true,
+ unused: true,
+ }
+ input: {
+ var C = 1;
+ var obj = {
+ bar: function() {
+ return C + C;
+ }
+ };
+ console.log(obj.bar());
+ }
+ expect: {
+ console.log(2);
+ }
+ expect_stdout: "2"
+}
+
+obj_arg_1: {
+ options = {
+ evaluate: true,
+ inline: true,
+ passes: 2,
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var C = 1;
+ function f(obj) {
+ return obj.bar();
+ }
+ console.log(f({
+ bar: function() {
+ return C + C;
+ }
+ }));
+ }
+ expect: {
+ console.log({
+ bar: function() {
+ return 2;
+ }
+ }.bar());
+ }
+ expect_stdout: "2"
+}
+
+obj_arg_2: {
+ options = {
+ evaluate: true,
+ inline: true,
+ passes: 2,
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ unsafe: true,
+ unused: true,
+ }
+ input: {
+ var C = 1;
+ function f(obj) {
+ return obj.bar();
+ }
+ console.log(f({
+ bar: function() {
+ return C + C;
+ }
+ }));
+ }
+ expect: {
+ console.log(2);
+ }
+ expect_stdout: "2"
+}
+
+func_arg_1: {
+ options = {
+ evaluate: true,
+ inline: true,
+ passes: 2,
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var a = 42;
+ !function(a) {
+ console.log(a());
+ }(function() {
+ return a;
+ });
+ }
+ expect: {
+ console.log(42);
+ }
+ expect_stdout: "42"
+}
+
+func_arg_2: {
+ options = {
+ evaluate: true,
+ inline: true,
+ passes: 2,
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var a = 42;
+ !function(a) {
+ console.log(a());
+ }(function(a) {
+ return a;
+ });
+ }
+ expect: {
+ console.log(void 0);
+ }
+ expect_stdout: "undefined"
+}
+
+regex_loop: {
+ options = {
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ function f(x) {
+ for (var r, s = "acdabcdeabbb"; r = x().exec(s);)
+ console.log(r[0]);
+ }
+ var a = /ab*/g;
+ f(function() {
+ return a;
+ });
+ }
+ expect: {
+ var a = /ab*/g;
+ (function(x) {
+ for (var r, s = "acdabcdeabbb"; r = x().exec(s);)
+ console.log(r[0]);
+ })(function() {
+ return a;
+ });
+ }
+ expect_stdout: true
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git
More information about the Pkg-javascript-commits
mailing list