[Pkg-javascript-commits] [uglifyjs] 27/228: improve reduce_vars and fix a bug - update modified flag between compress() passes - support IIFE arguments - fix corner case with multiple definitions

Jonas Smedegaard dr at jones.dk
Sat Apr 15 14:25:13 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 a0f4fd390a0a1af80964aab9754bf5358db575e2
Author: alexlamsl <alexlamsl at gmail.com>
Date:   Sat Feb 18 19:19:55 2017 +0800

    improve reduce_vars and fix a bug
    - update modified flag between compress() passes
    - support IIFE arguments
    - fix corner case with multiple definitions
    
    closes #1473
---
 lib/compress.js              |  41 +++++++++++---
 lib/scope.js                 |  26 ++-------
 test/compress/reduce_vars.js | 124 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 161 insertions(+), 30 deletions(-)

diff --git a/lib/compress.js b/lib/compress.js
index 345a414..72afe92 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -108,7 +108,8 @@ merge(Compressor.prototype, {
     compress: function(node) {
         var passes = +this.options.passes || 1;
         for (var pass = 0; pass < passes && pass < 3; ++pass) {
-            if (pass > 0) node.clear_opt_flags();
+            if (pass > 0 || this.option("reduce_vars"))
+                node.reset_opt_flags(this);
             node = node.transform(this);
         }
         return node;
@@ -167,19 +168,45 @@ merge(Compressor.prototype, {
         return this.print_to_string() == node.print_to_string();
     });
 
-    AST_Node.DEFMETHOD("clear_opt_flags", function(){
-        this.walk(new TreeWalker(function(node){
+    AST_Node.DEFMETHOD("reset_opt_flags", function(compressor){
+        var reduce_vars = compressor.option("reduce_vars");
+        var tw = new TreeWalker(function(node){
+            if (reduce_vars && node instanceof AST_Scope) {
+                node.variables.each(function(def) {
+                    delete def.modified;
+                });
+            }
             if (node instanceof AST_SymbolRef) {
                 var d = node.definition();
-                if (d && d.init) {
+                if (d.init) {
                     delete d.init._evaluated;
                 }
+                if (reduce_vars && (d.orig.length > 1 || isModified(node, 0))) {
+                    d.modified = true;
+                }
+            }
+            if (reduce_vars && node instanceof AST_Call && node.expression instanceof AST_Function) {
+                node.expression.argnames.forEach(function(arg, i) {
+                    arg.definition().init = node.args[i] || make_node(AST_Undefined, node);
+                });
             }
             if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
                 node._squeezed = false;
                 node._optimized = false;
             }
-        }));
+        });
+        this.walk(tw);
+
+        function isModified(node, level) {
+            var parent = tw.parent(level);
+            if (parent instanceof AST_Unary && (parent.operator === "++" || parent.operator === "--")
+                || parent instanceof AST_Assign && parent.left === node
+                || parent instanceof AST_Call && parent.expression === node) {
+                return true;
+            } else if (parent instanceof AST_PropAccess && parent.expression === node) {
+                return isModified(parent, level + 1);
+            }
+        }
     });
 
     function make_node(ctor, orig, props) {
@@ -459,7 +486,7 @@ merge(Compressor.prototype, {
                     var_defs_removed = true;
                 }
                 // Further optimize statement after substitution.
-                stat.clear_opt_flags();
+                stat.reset_opt_flags(compressor);
 
                 compressor.warn("Replacing " + (is_constant ? "constant" : "variable") +
                     " " + var_name + " [{file}:{line},{col}]", node.start);
@@ -1158,7 +1185,7 @@ merge(Compressor.prototype, {
             this._evaluating = true;
             try {
                 var d = this.definition();
-                if (d && (d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
+                if ((d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
                     if (compressor.option("unsafe")) {
                         if (!HOP(d.init, '_evaluated')) {
                             d.init._evaluated = ev(d.init, compressor);
diff --git a/lib/scope.js b/lib/scope.js
index d5cadd3..6ad1261 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -183,17 +183,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
     var func = null;
     var globals = self.globals = new Dictionary();
     var tw = new TreeWalker(function(node, descend){
-        function isModified(node, level) {
-            var parent = tw.parent(level);
-            if (parent instanceof AST_Unary && (parent.operator === "++" || parent.operator === "--")
-                || parent instanceof AST_Assign && parent.left === node
-                || parent instanceof AST_Call && parent.expression === node) {
-                return true;
-            } else if (parent instanceof AST_PropAccess && parent.expression === node) {
-                return isModified(parent, level + 1);
-            }
-        }
-
         if (node instanceof AST_Lambda) {
             var prev_func = func;
             func = node;
@@ -217,21 +206,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
                 node.scope.uses_arguments = true;
             }
             if (!sym) {
-                var g;
                 if (globals.has(name)) {
-                    g = globals.get(name);
+                    sym = globals.get(name);
                 } else {
-                    g = new SymbolDef(self, globals.size(), node);
-                    g.undeclared = true;
-                    g.global = true;
-                    globals.set(name, g);
+                    sym = new SymbolDef(self, globals.size(), node);
+                    sym.undeclared = true;
+                    sym.global = true;
+                    globals.set(name, sym);
                 }
-                sym = g;
             }
             node.thedef = sym;
-            if (isModified(node, 0)) {
-                sym.modified = true;
-            }
             node.reference(options);
             return true;
         }
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 2301a92..d9d02ef 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -108,8 +108,6 @@ modified: {
             }
             console.log(a + b);
             console.log(b + c);
-            // TODO: as "modified" is determined in "figure_out_scope",
-            // even "passes" wouldn't improve this any further
             console.log(a + c);
             console.log(a + b + c);
         }
@@ -350,3 +348,125 @@ unsafe_evaluate_equality: {
         }
     }
 }
+
+passes: {
+    options = {
+        conditionals: true,
+        evaluate: true,
+        passes: 2,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        function f() {
+            var a = 1, b = 2, c = 3;
+            if (a) {
+                b = c;
+            } else {
+                c = b;
+            }
+            console.log(a + b);
+            console.log(b + c);
+            console.log(a + c);
+            console.log(a + b + c);
+        }
+    }
+    expect: {
+        function f() {
+            var b = 2, c = 3;
+            b = c;
+            console.log(1 + b);
+            console.log(b + 3);
+            console.log(4);
+            console.log(1 + b + 3);
+        }
+    }
+}
+
+iife: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+    }
+    input: {
+        !function(a, b, c) {
+            b++;
+            console.log(a - 1, b * 1, c + 2);
+        }(1, 2, 3);
+    }
+    expect: {
+        !function(a, b, c) {
+            b++;
+            console.log(0, 1 * b, 5);
+        }(1, 2, 3);
+    }
+}
+
+iife_new: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+    }
+    input: {
+        var A = new function(a, b, c) {
+            b++;
+            console.log(a - 1, b * 1, c + 2);
+        }(1, 2, 3);
+    }
+    expect: {
+        var A = new function(a, b, c) {
+            b++;
+            console.log(0, 1 * b, 5);
+        }(1, 2, 3);
+    }
+}
+
+multi_def: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+    }
+    input: {
+        function f(a) {
+            if (a)
+                var b = 1;
+            else
+                var b = 2
+            console.log(b + 1);
+        }
+    }
+    expect: {
+        function f(a) {
+            if (a)
+                var b = 1;
+            else
+                var b = 2
+            console.log(b + 1);
+        }
+    }
+}
+
+multi_def_2: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+    }
+    input: {
+        if (code == 16)
+            var bitsLength = 2, bitsOffset = 3, what = len;
+        else if (code == 17)
+            var bitsLength = 3, bitsOffset = 3, what = (len = 0);
+        else if (code == 18)
+            var bitsLength = 7, bitsOffset = 11, what = (len = 0);
+        var repeatLength = this.getBits(bitsLength) + bitsOffset;
+    }
+    expect: {
+        if (16 == code)
+            var bitsLength = 2, bitsOffset = 3, what = len;
+        else if (17 == code)
+            var bitsLength = 3, bitsOffset = 3, what = (len = 0);
+        else if (18 == code)
+            var bitsLength = 7, bitsOffset = 11, what = (len = 0);
+        var repeatLength = this.getBits(bitsLength) + bitsOffset;
+    }
+}

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