[Pkg-javascript-commits] [uglifyjs] 06/491: enhance `reduce_vars` (#1814)

Jonas Smedegaard dr at jones.dk
Wed Feb 14 19:51:17 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 1a498db2d3e520d1711144c423312c62a2673115
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Mon Apr 17 01:36:50 2017 +0800

    enhance `reduce_vars` (#1814)
    
    - allow immediate assignment after declaration of variable
    - relax modification rule for immutable value
    - fix order of visit for TreeWalker
    - remove extraneous code
---
 lib/ast.js                   |  12 +---
 lib/compress.js              |  74 ++++++++++++++++-------
 test/compress/reduce_vars.js | 140 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+), 33 deletions(-)

diff --git a/lib/ast.js b/lib/ast.js
index 0fa051b..739c21c 100644
--- a/lib/ast.js
+++ b/lib/ast.js
@@ -182,21 +182,13 @@ var AST_BlockStatement = DEFNODE("BlockStatement", null, {
 }, AST_Block);
 
 var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
-    $documentation: "The empty statement (empty block or simply a semicolon)",
-    _walk: function(visitor) {
-        return visitor._visit(this);
-    }
+    $documentation: "The empty statement (empty block or simply a semicolon)"
 }, AST_Statement);
 
 var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
     $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
     $propdoc: {
         body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
-    },
-    _walk: function(visitor) {
-        return visitor._visit(this, function(){
-            this.body._walk(visitor);
-        });
     }
 }, AST_Statement);
 
@@ -551,11 +543,11 @@ var AST_Call = DEFNODE("Call", "expression args", {
     },
     _walk: function(visitor) {
         return visitor._visit(this, function(){
-            this.expression._walk(visitor);
             var args = this.args;
             for (var i = 0, len = args.length; i < len; i++) {
                 args[i]._walk(visitor);
             }
+            this.expression._walk(visitor);
         });
     }
 });
diff --git a/lib/compress.js b/lib/compress.js
index 6062be5..640fcec 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -119,7 +119,7 @@ merge(Compressor.prototype, {
     option: function(key) { return this.options[key] },
     compress: function(node) {
         if (this.option("expression")) {
-            node = node.process_expression(true);
+            node.process_expression(true);
         }
         var passes = +this.options.passes || 1;
         for (var pass = 0; pass < passes && pass < 3; ++pass) {
@@ -128,7 +128,7 @@ merge(Compressor.prototype, {
             node = node.transform(this);
         }
         if (this.option("expression")) {
-            node = node.process_expression(false);
+            node.process_expression(false);
         }
         return node;
     },
@@ -200,7 +200,7 @@ merge(Compressor.prototype, {
         return this.TYPE == node.TYPE && this.print_to_string() == node.print_to_string();
     });
 
-    AST_Node.DEFMETHOD("process_expression", function(insert, compressor) {
+    AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) {
         var self = this;
         var tt = new TreeTransformer(function(node) {
             if (insert && node instanceof AST_SimpleStatement) {
@@ -244,10 +244,10 @@ merge(Compressor.prototype, {
             }
             return node;
         });
-        return self.transform(tt);
+        self.transform(tt);
     });
 
-    AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan){
+    AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
         var reduce_vars = rescan && compressor.option("reduce_vars");
         var toplevel = compressor.option("toplevel");
         var safe_ids = Object.create(null);
@@ -258,7 +258,7 @@ merge(Compressor.prototype, {
                 d.fixed = false;
             }
         });
-        var tw = new TreeWalker(function(node, descend){
+        var tw = new TreeWalker(function(node, descend) {
             node._squeezed = false;
             node._optimized = false;
             if (reduce_vars) {
@@ -268,7 +268,7 @@ merge(Compressor.prototype, {
                     var d = node.definition();
                     d.references.push(node);
                     if (d.fixed === undefined || !is_safe(d)
-                        || is_modified(node, 0, node.fixed_value() instanceof AST_Lambda)) {
+                        || is_modified(node, 0, is_immutable(node.fixed_value()))) {
                         d.fixed = false;
                     }
                 }
@@ -293,6 +293,20 @@ merge(Compressor.prototype, {
                         d.fixed = false;
                     }
                 }
+                if (node instanceof AST_Assign
+                    && node.operator == "="
+                    && node.left instanceof AST_SymbolRef) {
+                    var d = node.left.definition();
+                    if (HOP(safe_ids, d.id) && d.fixed == null) {
+                        d.fixed = function() {
+                            return node.right;
+                        };
+                        mark(d, false);
+                        node.right.walk(tw);
+                        mark(d, true);
+                        return true;
+                    }
+                }
                 if (node instanceof AST_Defun) {
                     var d = node.name.definition();
                     if (!toplevel && d.global || is_safe(d)) {
@@ -309,21 +323,24 @@ merge(Compressor.prototype, {
                 }
                 var iife;
                 if (node instanceof AST_Function
-                    && !node.name
                     && (iife = tw.parent()) instanceof AST_Call
                     && iife.expression === node) {
-                    // Virtually turn IIFE parameters into variable definitions:
-                    //   (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
-                    // So existing transformation rules can work on them.
-                    node.argnames.forEach(function(arg, i) {
-                        var d = arg.definition();
-                        d.fixed = function() {
-                            return iife.args[i] || make_node(AST_Undefined, iife);
-                        };
-                        mark(d, true);
-                    });
+                    if (node.name) {
+                        node.name.definition().fixed = node;
+                    } else {
+                        // Virtually turn IIFE parameters into variable definitions:
+                        //   (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
+                        // So existing transformation rules can work on them.
+                        node.argnames.forEach(function(arg, i) {
+                            var d = arg.definition();
+                            d.fixed = function() {
+                                return iife.args[i] || make_node(AST_Undefined, iife);
+                            };
+                            mark(d, true);
+                        });
+                    }
                 }
-                if (node instanceof AST_If || node instanceof AST_DWLoop) {
+                if (node instanceof AST_If) {
                     node.condition.walk(tw);
                     push();
                     node.body.walk(tw);
@@ -335,6 +352,13 @@ merge(Compressor.prototype, {
                     }
                     return true;
                 }
+                if (node instanceof AST_DWLoop) {
+                    push();
+                    node.condition.walk(tw);
+                    node.body.walk(tw);
+                    pop();
+                    return true;
+                }
                 if (node instanceof AST_LabeledStatement) {
                     push();
                     node.body.walk(tw);
@@ -401,13 +425,17 @@ merge(Compressor.prototype, {
             def.should_replace = undefined;
         }
 
-        function is_modified(node, level, func) {
+        function is_immutable(value) {
+            return value && value.is_constant() || value instanceof AST_Lambda;
+        }
+
+        function is_modified(node, level, immutable) {
             var parent = tw.parent(level);
             if (is_lhs(node, parent)
-                || !func && parent instanceof AST_Call && parent.expression === node) {
+                || !immutable && parent instanceof AST_Call && parent.expression === node) {
                 return true;
             } else if (parent instanceof AST_PropAccess && parent.expression === node) {
-                return !func && is_modified(parent, level + 1);
+                return !immutable && is_modified(parent, level + 1);
             }
         }
     });
@@ -2167,7 +2195,7 @@ merge(Compressor.prototype, {
                 if (this.expression instanceof AST_Function
                     && (!this.expression.name || !this.expression.name.definition().references.length)) {
                     var node = this.clone();
-                    node.expression = node.expression.process_expression(false, compressor);
+                    node.expression.process_expression(false, compressor);
                     return node;
                 }
                 return this;
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 7621dd4..6e079c1 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -1996,6 +1996,146 @@ catch_var: {
     expect_stdout: "true"
 }
 
+var_assign_1: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        sequences: true,
+        side_effects: true,
+        unused: true,
+    }
+    input: {
+        !function() {
+            var a;
+            a = 2;
+            console.log(a);
+        }();
+    }
+    expect: {
+        !function() {
+            console.log(2);
+        }();
+    }
+    expect_stdout: "2"
+}
+
+var_assign_2: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        sequences: true,
+        side_effects: true,
+        unused: true,
+    }
+    input: {
+        !function() {
+            var a;
+            if (a = 2) console.log(a);
+        }();
+    }
+    expect: {
+        !function() {
+            if (2) console.log(2);
+        }();
+    }
+    expect_stdout: "2"
+}
+
+var_assign_3: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        sequences: true,
+        side_effects: true,
+        unused: true,
+    }
+    input: {
+        !function() {
+            var a;
+            while (a = 2);
+            console.log(a);
+        }();
+    }
+    expect: {
+        !function() {
+            var a;
+            while (a = 2);
+            console.log(a);
+        }();
+    }
+}
+
+var_assign_4: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        sequences: true,
+        side_effects: true,
+        unused: true,
+    }
+    input: {
+        !function a() {
+            a = 2;
+            console.log(a);
+        }();
+    }
+    expect: {
+        !function a() {
+            a = 2,
+            console.log(a);
+        }();
+    }
+}
+
+var_assign_5: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        sequences: true,
+        side_effects: true,
+        unused: true,
+    }
+    input: {
+        !function() {
+            var a;
+            !function(b) {
+                a = 2;
+                console.log(a, b);
+            }(a);
+        }();
+    }
+    expect: {
+        !function() {
+            var a;
+            !function(b) {
+                a = 2,
+                console.log(a, b);
+            }(a);
+        }();
+    }
+    expect_stdout: "2 undefined"
+}
+
+immutable: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        !function() {
+            var a = "test";
+            console.log(a.indexOf("e"));
+        }();
+    }
+    expect: {
+        !function() {
+            console.log("test".indexOf("e"));
+        }();
+    }
+    expect_stdout: "1"
+}
+
 issue_1814_1: {
     options = {
         evaluate: 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