[Pkg-javascript-commits] [uglifyjs] 170/491: improve `inline` efficiency (#2188)

Jonas Smedegaard dr at jones.dk
Wed Feb 14 19:51:32 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 d40950b741d67bafc91a102ce2c6e862af46fd11
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Sun Jul 2 01:05:14 2017 +0800

    improve `inline` efficiency (#2188)
    
    ... by teaching `collapse_vars` some new tricks.
    
    fixes #2187
---
 lib/compress.js                | 114 ++++++++++++++++++++++-------------------
 test/compress/collapse_vars.js |  35 ++++++++++++-
 test/compress/drop-unused.js   |   5 +-
 test/compress/functions.js     |   6 +--
 test/compress/issue-281.js     |  24 ++++++---
 test/mocha/glob.js             |   4 +-
 6 files changed, 119 insertions(+), 69 deletions(-)

diff --git a/lib/compress.js b/lib/compress.js
index 352be28..dffdd6e 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -714,15 +714,23 @@ merge(Compressor.prototype, {
             var candidates = [];
             var stat_index = statements.length;
             while (--stat_index >= 0) {
+                // Treat parameters as collapsible in IIFE, i.e.
+                //   function(a, b){ ... }(x());
+                // would be translated into equivalent assignments:
+                //   var a = x(), b = undefined;
+                if (stat_index == 0 && compressor.option("unused")) extract_args();
+                // Find collapsible assignments
                 extract_candidates(statements[stat_index]);
                 while (candidates.length > 0) {
                     var candidate = candidates.pop();
                     var lhs = get_lhs(candidate);
                     if (!lhs || is_lhs_read_only(lhs)) continue;
+                    // Locate symbols which may execute code outside of scanning range
                     var lvalues = get_lvalues(candidate);
                     if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
                     var side_effects = value_has_side_effects(candidate);
-                    var hit = false, abort = false, replaced = false;
+                    var hit = candidate.name instanceof AST_SymbolFunarg;
+                    var abort = false, replaced = false;
                     var tt = new TreeTransformer(function(node, descend) {
                         if (abort) return node;
                         // Skip nodes before `candidate` as quickly as possible
@@ -803,6 +811,35 @@ merge(Compressor.prototype, {
                 }
             }
 
+            function extract_args() {
+                var iife, fn = compressor.self();
+                if (fn instanceof AST_Function
+                    && !fn.name
+                    && !fn.uses_arguments
+                    && !fn.uses_eval
+                    && (iife = compressor.parent()) instanceof AST_Call
+                    && iife.expression === fn) {
+                    fn.argnames.forEach(function(sym, i) {
+                        var arg = iife.args[i];
+                        if (!arg) arg = make_node(AST_Undefined, sym);
+                        else arg.walk(new TreeWalker(function(node) {
+                            if (!arg) return true;
+                            if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) {
+                                var s = node.definition().scope;
+                                if (s !== scope) while (s = s.parent_scope) {
+                                    if (s === scope) return true;
+                                }
+                                arg = null;
+                            }
+                        }));
+                        if (arg) candidates.push(make_node(AST_VarDef, sym, {
+                            name: sym,
+                            value: arg
+                        }));
+                    });
+                }
+            }
+
             function extract_candidates(expr) {
                 if (expr instanceof AST_Assign && !expr.left.has_side_effects(compressor)
                     || expr instanceof AST_Unary && (expr.operator == "++" || expr.operator == "--")) {
@@ -823,7 +860,7 @@ merge(Compressor.prototype, {
             function get_lhs(expr) {
                 if (expr instanceof AST_VarDef) {
                     var def = expr.name.definition();
-                    if (def.orig.length > 1
+                    if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg)
                         || def.references.length == 1 && !compressor.exposed(def)) {
                         return make_node(AST_SymbolRef, expr.name, expr.name);
                     }
@@ -3174,69 +3211,42 @@ merge(Compressor.prototype, {
         if (exp instanceof AST_Function) {
             if (compressor.option("inline")
                 && !exp.name
-                && exp.body.length == 1
                 && !exp.uses_arguments
                 && !exp.uses_eval
+                && exp.body.length == 1
+                && all(exp.argnames, function(arg) {
+                    return arg.__unused;
+                })
                 && !self.has_pure_annotation(compressor)) {
                 var value;
                 if (stat instanceof AST_Return) {
-                    value = stat.value.clone(true);
+                    value = stat.value;
                 } else if (stat instanceof AST_SimpleStatement) {
                     value = make_node(AST_UnaryPrefix, stat, {
                         operator: "void",
-                        expression: stat.body.clone(true)
+                        expression: stat.body
                     });
                 }
                 if (value) {
-                    var fn = exp.clone();
-                    fn.argnames = [];
-                    fn.body = [];
-                    if (exp.argnames.length > 0) {
-                        fn.body.push(make_node(AST_Var, self, {
-                            definitions: exp.argnames.map(function(sym, i) {
-                                var arg = self.args[i];
-                                return make_node(AST_VarDef, sym, {
-                                    name: sym,
-                                    value: arg ? arg.clone(true) : make_node(AST_Undefined, self)
-                                });
-                            })
-                        }));
-                    }
-                    if (self.args.length > exp.argnames.length) {
-                        fn.body.push(make_node(AST_SimpleStatement, self, {
-                            body: make_sequence(self, self.args.slice(exp.argnames.length).map(function(node) {
-                                return node.clone(true);
-                            }))
-                        }));
-                    }
-                    fn.body.push(make_node(AST_Return, self, {
-                        value: value
-                    }));
-                    var body = fn.transform(compressor).body;
-                    if (body.length == 0) return make_node(AST_Undefined, self);
-                    if (body.length == 1 && body[0] instanceof AST_Return) {
-                        value = body[0].value;
-                        if (!value) return make_node(AST_Undefined, self);
-                        var tw = new TreeWalker(function(node) {
-                            if (value === self) return true;
-                            if (node instanceof AST_SymbolRef) {
-                                var ref = node.scope.find_variable(node);
-                                if (ref && ref.scope.parent_scope === fn.parent_scope) {
-                                    value = self;
-                                    return true;
-                                }
-                            }
-                            if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
-                                value = self;
+                    var tw = new TreeWalker(function(node) {
+                        if (!value) return true;
+                        if (node instanceof AST_SymbolRef) {
+                            var ref = node.scope.find_variable(node);
+                            if (ref && ref.scope.parent_scope === fn.parent_scope) {
+                                value = null;
                                 return true;
                             }
-                        });
-                        value.walk(tw);
-                        if (value !== self) value = best_of(compressor, value, self);
-                    } else {
-                        value = self;
-                    }
-                    if (value !== self) return value;
+                        }
+                        if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
+                            value = null;
+                            return true;
+                        }
+                    });
+                    value.walk(tw);
+                }
+                if (value) {
+                    var args = self.args.concat(value);
+                    return make_sequence(self, args).transform(compressor);
                 }
             }
             if (compressor.option("side_effects") && all(exp.body, is_empty)) {
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index 158d1b4..f3eb781 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -1978,10 +1978,10 @@ chained_3: {
     }
     expect: {
         console.log(function(a, b) {
-            var c = a, c = b;
+            var c = 1, c = b;
             b++;
             return c;
-        }(1, 2));
+        }(0, 2));
     }
     expect_stdout: "2"
 }
@@ -2186,3 +2186,34 @@ compound_assignment: {
     }
     expect_stdout: "4"
 }
+
+issue_2187: {
+    options = {
+        collapse_vars: true,
+        unused: true,
+    }
+    input: {
+        var a = 1;
+        !function(foo) {
+            foo();
+            var a = 2;
+            console.log(a);
+        }(function() {
+            console.log(a);
+        });
+    }
+    expect: {
+        var a = 1;
+        !function(foo) {
+            foo();
+            var a = 2;
+            console.log(a);
+        }(function() {
+            console.log(a);
+        });
+    }
+    expect_stdout: [
+        "1",
+        "2",
+    ]
+}
diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js
index 08fc7b1..e1acdc1 100644
--- a/test/compress/drop-unused.js
+++ b/test/compress/drop-unused.js
@@ -1113,6 +1113,7 @@ issue_2105: {
     options = {
         collapse_vars: true,
         inline: true,
+        passes: 2,
         reduce_vars: true,
         side_effects: true,
         unused: true,
@@ -1138,7 +1139,7 @@ issue_2105: {
         });
     }
     expect: {
-        !void function() {
+        (function() {
             var quux = function() {
                 console.log("PASS");
             };
@@ -1148,7 +1149,7 @@ issue_2105: {
                     quux();
                 }
             };
-        }().prop();
+        })().prop();
     }
     expect_stdout: "PASS"
 }
diff --git a/test/compress/functions.js b/test/compress/functions.js
index c8efc12..f411afa 100644
--- a/test/compress/functions.js
+++ b/test/compress/functions.js
@@ -468,11 +468,9 @@ issue_2114_1: {
     }
     expect: {
         var c = 0;
-        !function() {
-            0;
-        }((c += 1, c = 1 + c, function() {
+        c = 1 + (c += 1), function() {
             var b = void (b && (b.b += (c += 1, 0)));
-        }()));
+        }();
         console.log(c);
     }
     expect_stdout: "2"
diff --git a/test/compress/issue-281.js b/test/compress/issue-281.js
index 9b8c8bf..65871a8 100644
--- a/test/compress/issue-281.js
+++ b/test/compress/issue-281.js
@@ -419,7 +419,7 @@ wrap_iife_in_return_call: {
     expect_exact: '(void console.log("test"))();'
 }
 
-pure_annotation: {
+pure_annotation_1: {
     options = {
         inline: true,
         side_effects: true,
@@ -432,6 +432,20 @@ pure_annotation: {
     expect_exact: ""
 }
 
+pure_annotation_2: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        side_effects: true,
+    }
+    input: {
+        /*@__PURE__*/(function(n) {
+            console.log("hello", n);
+        }(42));
+    }
+    expect_exact: ""
+}
+
 drop_fargs: {
     options = {
         cascade: true,
@@ -449,9 +463,7 @@ drop_fargs: {
     }
     expect: {
         var a = 1;
-        !function() {
-            a++;
-        }(++a && a.var);
+        ++a && a.var, a++;
         console.log(a);
     }
     expect_stdout: "3"
@@ -474,9 +486,7 @@ keep_fargs: {
     }
     expect: {
         var a = 1;
-        !function(a_1) {
-            a++;
-        }(++a && a.var);
+        ++a && a.var, a++;
         console.log(a);
     }
     expect_stdout: "3"
diff --git a/test/mocha/glob.js b/test/mocha/glob.js
index 8567ecb..eb5d477 100644
--- a/test/mocha/glob.js
+++ b/test/mocha/glob.js
@@ -26,12 +26,12 @@ describe("bin/uglifyjs with input file globs", function() {
         });
     });
     it("bin/uglifyjs with multiple input file globs.", function(done) {
-        var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel';
+        var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=2';
 
         exec(command, function(err, stdout) {
             if (err) throw err;
 
-            assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",2*11);\n');
+            assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",22);\n');
             done();
         });
     });

-- 
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