[Pkg-javascript-commits] [uglifyjs] 85/228: transform function calls to IIFEs (#1560)

Jonas Smedegaard dr at jones.dk
Sat Apr 15 14:25:19 UTC 2017


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository uglifyjs.

commit 8153b7bd8a70ad94666904bd41f12ebd6be684c8
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Tue Mar 7 15:37:52 2017 +0800

    transform function calls to IIFEs (#1560)
    
    - expose function body to call sites for potential optimisations
    - suppress substitution of variable used within `AST_Defun`
---
 lib/ast.js                   |  10 +-
 lib/compress.js              |  51 +++++++---
 test/compress/reduce_vars.js | 238 +++++++++++++++++++++++++++++++++++++++++--
 test/mocha/cli.js            |   2 +-
 test/mocha/glob.js           |  12 +--
 5 files changed, 284 insertions(+), 29 deletions(-)

diff --git a/lib/ast.js b/lib/ast.js
index 1f16330..a2125e7 100644
--- a/lib/ast.js
+++ b/lib/ast.js
@@ -91,7 +91,15 @@ var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos
 }, null);
 
 var AST_Node = DEFNODE("Node", "start end", {
-    clone: function() {
+    clone: function(deep) {
+        if (deep) {
+            var self = this.clone();
+            return self.transform(new TreeTransformer(function(node) {
+                if (node !== self) {
+                    return node.clone(true);
+                }
+            }));
+        }
         return new this.CTOR(this);
     },
     $documentation: "Base class of all AST nodes",
diff --git a/lib/compress.js b/lib/compress.js
index 696e205..8bbbc3f 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -245,7 +245,8 @@ merge(Compressor.prototype, {
                 if (node instanceof AST_SymbolRef) {
                     var d = node.definition();
                     d.references.push(node);
-                    if (!d.fixed || isModified(node, 0) || !is_safe(d)) {
+                    if (!d.fixed || !is_safe(d)
+                        || is_modified(node, 0, d.fixed instanceof AST_Lambda)) {
                         d.fixed = false;
                     }
                 }
@@ -261,6 +262,21 @@ merge(Compressor.prototype, {
                         d.fixed = false;
                     }
                 }
+                if (node instanceof AST_Defun) {
+                    var d = node.name.definition();
+                    if (!toplevel && d.global || is_safe(d)) {
+                        d.fixed = false;
+                    } else {
+                        d.fixed = node;
+                        mark_as_safe(d);
+                    }
+                    var save_ids = safe_ids;
+                    safe_ids = [];
+                    push();
+                    descend();
+                    safe_ids = save_ids;
+                    return true;
+                }
                 var iife;
                 if (node instanceof AST_Function
                     && (iife = tw.parent()) instanceof AST_Call
@@ -344,13 +360,13 @@ merge(Compressor.prototype, {
             def.should_replace = undefined;
         }
 
-        function isModified(node, level) {
+        function is_modified(node, level, func) {
             var parent = tw.parent(level);
             if (isLHS(node, parent)
-                || parent instanceof AST_Call && parent.expression === node) {
+                || !func && parent instanceof AST_Call && parent.expression === node) {
                 return true;
             } else if (parent instanceof AST_PropAccess && parent.expression === node) {
-                return isModified(parent, level + 1);
+                return !func && is_modified(parent, level + 1);
             }
         }
     });
@@ -1307,14 +1323,7 @@ merge(Compressor.prototype, {
         def(AST_Statement, function(){
             throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
         });
-        // XXX: AST_Accessor and AST_Function both inherit from AST_Scope,
-        // which itself inherits from AST_Statement; however, they aren't
-        // really statements.  This could bite in other places too. :-(
-        // Wish JS had multiple inheritance.
-        def(AST_Accessor, function(){
-            throw def;
-        });
-        def(AST_Function, function(){
+        def(AST_Lambda, function(){
             throw def;
         });
         function ev(node, compressor) {
@@ -2590,6 +2599,24 @@ merge(Compressor.prototype, {
 
     OPT(AST_Call, function(self, compressor){
         var exp = self.expression;
+        if (compressor.option("reduce_vars")
+            && exp instanceof AST_SymbolRef) {
+            var def = exp.definition();
+            if (def.fixed instanceof AST_Defun) {
+                def.fixed = make_node(AST_Function, def.fixed, def.fixed).clone(true);
+            }
+            if (def.fixed instanceof AST_Function) {
+                exp = def.fixed;
+                if (compressor.option("unused")
+                    && def.references.length == 1
+                    && compressor.find_parent(AST_Scope) === def.scope) {
+                    if (!compressor.option("keep_fnames")) {
+                        exp.name = null;
+                    }
+                    self.expression = exp;
+                }
+            }
+        }
         if (compressor.option("unused")
             && exp instanceof AST_Function
             && !exp.uses_arguments
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 27f77fb..a373de2 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -744,12 +744,11 @@ toplevel_on_loops_1: {
         while (x);
     }
     expect: {
-        function bar() {
-            console.log("bar:", --x);
-        }
         var x = 3;
         do
-            bar();
+            (function() {
+                console.log("bar:", --x);
+            })();
         while (x);
     }
 }
@@ -800,10 +799,9 @@ toplevel_on_loops_2: {
         while (x);
     }
     expect: {
-        function bar() {
+        for (;;) (function() {
             console.log("bar:");
-        }
-        for (;;) bar();
+        })();
     }
 }
 
@@ -869,3 +867,229 @@ toplevel_off_loops_3: {
         for (;x;) bar();
     }
 }
+
+defun_reference: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+    }
+    input: {
+        function f() {
+            function g() {
+                x();
+                return a;
+            }
+            var a = h();
+            var b = 2;
+            return a + b;
+            function h() {
+                y();
+                return b;
+            }
+        }
+    }
+    expect: {
+        function f() {
+            function g() {
+                x();
+                return a;
+            }
+            var a = h();
+            var b = 2;
+            return a + b;
+            function h() {
+                y();
+                return b;
+            }
+        }
+    }
+}
+
+defun_inline_1: {
+    options = {
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        function f() {
+            return g(2) + h();
+            function g(b) {
+                return b;
+            }
+            function h() {
+                return h();
+            }
+        }
+    }
+    expect: {
+        function f() {
+            return function(b) {
+                return b;
+            }(2) + h();
+            function h() {
+                return h();
+            }
+        }
+    }
+}
+
+defun_inline_2: {
+    options = {
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        function f() {
+            function g(b) {
+                return b;
+            }
+            function h() {
+                return h();
+            }
+            return g(2) + h();
+        }
+    }
+    expect: {
+        function f() {
+            function h() {
+                return h();
+            }
+            return function(b) {
+                return b;
+            }(2) + h();
+        }
+    }
+}
+
+defun_inline_3: {
+    options = {
+        evaluate: true,
+        passes: 2,
+        reduce_vars: true,
+        side_effects: true,
+        unused: true,
+    }
+    input: {
+        function f() {
+            return g(2);
+            function g(b) {
+                return b;
+            }
+        }
+    }
+    expect: {
+        function f() {
+            return 2;
+        }
+    }
+}
+
+defun_call: {
+    options = {
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        function f() {
+            return g() + h(1) - h(g(), 2, 3);
+            function g() {
+                return 4;
+            }
+            function h(a) {
+                return a;
+            }
+        }
+    }
+    expect: {
+        function f() {
+            return 4 + h(1) - h(4);
+            function h(a) {
+                return a;
+            }
+        }
+    }
+}
+
+defun_redefine: {
+    options = {
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        function f() {
+            function g() {
+                return 1;
+            }
+            function h() {
+                return 2;
+            }
+            g = function() {
+                return 3;
+            };
+            return g() + h();
+        }
+    }
+    expect:  {
+        function f() {
+            function g() {
+                return 1;
+            }
+            g = function() {
+                return 3;
+            };
+            return g() + 2;
+        }
+    }
+}
+
+func_inline: {
+    options = {
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        function f() {
+            var g = function() {
+                return 1;
+            };
+            console.log(g() + h());
+            var h = function() {
+                return 2;
+            };
+        }
+    }
+    expect: {
+        function f() {
+            console.log(1 + h());
+            var h = function() {
+                return 2;
+            };
+        }
+    }
+}
+
+func_modified: {
+    options = {
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        function f(a) {
+            function a() { return 1; }
+            function b() { return 2; }
+            function c() { return 3; }
+            b.inject = [];
+            c = function() { return 4; };
+            return a() + b() + c();
+        }
+    }
+    expect: {
+        function f(a) {
+            function b() { return 2; }
+            function c() { return 3; }
+            b.inject = [];
+            c = function() { return 4; };
+            return 1 + 2 + c();
+        }
+    }
+}
diff --git a/test/mocha/cli.js b/test/mocha/cli.js
index c07eeee..e8e07cb 100644
--- a/test/mocha/cli.js
+++ b/test/mocha/cli.js
@@ -82,7 +82,7 @@ describe("bin/uglifyjs", function () {
        });
     });
     it("Should work with --keep-fnames (mangle & compress)", function (done) {
-       var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c';
+       var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
 
        exec(command, function (err, stdout) {
            if (err) throw err;
diff --git a/test/mocha/glob.js b/test/mocha/glob.js
index c2fc946..3031365 100644
--- a/test/mocha/glob.js
+++ b/test/mocha/glob.js
@@ -3,17 +3,13 @@ var assert = require("assert");
 
 describe("minify() with input file globs", function() {
     it("minify() with one input file glob string.", function() {
-        var result = Uglify.minify("test/input/issue-1242/foo.*", {
-            compress: { collapse_vars: true }
-        });
+        var result = Uglify.minify("test/input/issue-1242/foo.*");
         assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);');
     });
     it("minify() with an array of one input file glob.", function() {
         var result = Uglify.minify([
             "test/input/issue-1242/b*.es5",
-        ], {
-            compress: { collapse_vars: true }
-        });
+        ]);
         assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}');
     });
     it("minify() with an array of multiple input file globs.", function() {
@@ -21,8 +17,8 @@ describe("minify() with input file globs", function() {
             "test/input/issue-1242/???.es5",
             "test/input/issue-1242/*.js",
         ], {
-            compress: { collapse_vars: true }
+            compress: { toplevel: true }
         });
-        assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}function foo(n){print("Foo:",2*n)}var print=console.log.bind(console);print("qux",bar(3),baz(12)),foo(11);');
+        assert.strictEqual(result.code, 'var print=console.log.bind(console);print("qux",function(n){return 3*n}(3),function(n){return n/2}(12)),function(n){print("Foo:",2*n)}(11);');
     });
 });

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