[Pkg-javascript-commits] [uglifyjs] 264/491: consolidate & enhance `unused` (#2439)

Jonas Smedegaard dr at jones.dk
Wed Feb 14 19:51:42 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 6c4510187066555c77003f03fd26e2cf5ff47491
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Mon Nov 6 14:25:10 2017 +0800

    consolidate & enhance `unused` (#2439)
    
    - defer declaration removal in `collapse_vars`
    - account for `AST_SymbolFunarg` in deduplication
    - private accounting for `collapse_vars`
    - avoid issues with identity reference due to deep cloning
    
    fixes #2437
---
 lib/compress.js                | 142 +++++++++++++++++++++--------------------
 test/compress/collapse_vars.js |  66 ++++++++++++++++++-
 test/compress/issue-973.js     |   1 +
 test/compress/reduce_vars.js   |  12 ++--
 4 files changed, 145 insertions(+), 76 deletions(-)

diff --git a/lib/compress.js b/lib/compress.js
index ba7c10f..d848233 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -788,6 +788,14 @@ merge(Compressor.prototype, {
             || compressor.option("unsafe") && global_names(this.name);
     });
 
+    function drop_decl(def) {
+        def._eliminiated = (def._eliminiated || 0) + 1;
+        if (def.orig.length == def._eliminiated) {
+            def.scope.functions.del(def.name);
+            def.scope.variables.del(def.name);
+        }
+    }
+
     function tighten_body(statements, compressor) {
         var CHANGED, max_iter = 10;
         do {
@@ -1000,7 +1008,8 @@ merge(Compressor.prototype, {
             function get_lhs(expr) {
                 if (expr instanceof AST_VarDef) {
                     var def = expr.name.definition();
-                    if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg)
+                    if (def.orig.length - (def._eliminiated || 0) > 1
+                            && !(expr.name instanceof AST_SymbolFunarg)
                         || def.references.length == 1 && !compressor.exposed(def)) {
                         return make_node(AST_SymbolRef, expr.name, expr.name);
                     }
@@ -1009,6 +1018,10 @@ merge(Compressor.prototype, {
                 }
             }
 
+            function get_rvalue(expr) {
+                return expr[expr instanceof AST_Assign ? "right" : "value"];
+            }
+
             function get_lvalues(expr) {
                 var lvalues = Object.create(null);
                 if (expr instanceof AST_Unary) return lvalues;
@@ -1019,7 +1032,7 @@ merge(Compressor.prototype, {
                         lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
                     }
                 });
-                expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw);
+                get_rvalue(expr).walk(tw);
                 return lvalues;
             }
 
@@ -1043,7 +1056,9 @@ merge(Compressor.prototype, {
                     if (node === expr) {
                         found = true;
                         if (node instanceof AST_VarDef) {
-                            remove(node.name.definition().orig, node.name);
+                            drop_decl(node.name.definition());
+                            node.value = null;
+                            return node;
                         }
                         return in_list ? MAP.skip : null;
                     }
@@ -1052,16 +1067,13 @@ merge(Compressor.prototype, {
                       case 0: return null;
                       case 1: return node.expressions[0];
                     }
-                    if (node instanceof AST_Definitions && node.definitions.length == 0
-                        || node instanceof AST_SimpleStatement && !node.body) {
-                        return null;
-                    }
+                    if (node instanceof AST_SimpleStatement && !node.body) return null;
                 }));
             }
 
             function value_has_side_effects(expr) {
                 if (expr instanceof AST_Unary) return false;
-                return expr[expr instanceof AST_Assign ? "right" : "value"].has_side_effects(compressor);
+                return get_rvalue(expr).has_side_effects(compressor);
             }
 
             function references_in_scope(def) {
@@ -2303,61 +2315,63 @@ merge(Compressor.prototype, {
         // this scope (not in nested scopes).
         var scope = this;
         var tw = new TreeWalker(function(node, descend){
-            if (node !== self) {
-                if (node instanceof AST_Defun) {
-                    if (!drop_funcs && scope === self) {
-                        var node_def = node.name.definition();
+            if (node === self) return;
+            if (node instanceof AST_Defun) {
+                if (!drop_funcs && scope === self) {
+                    var node_def = node.name.definition();
+                    if (!(node_def.id in in_use_ids)) {
+                        in_use_ids[node_def.id] = true;
+                        in_use.push(node_def);
+                    }
+                }
+                initializations.add(node.name.name, node);
+                return true; // don't go in nested scopes
+            }
+            if (node instanceof AST_SymbolFunarg && scope === self) {
+                var_defs_by_id.add(node.definition().id, node);
+            }
+            if (node instanceof AST_Definitions && scope === self) {
+                node.definitions.forEach(function(def){
+                    var node_def = def.name.definition();
+                    if (def.name instanceof AST_SymbolVar) {
+                        var_defs_by_id.add(node_def.id, def);
+                    }
+                    if (!drop_vars) {
                         if (!(node_def.id in in_use_ids)) {
                             in_use_ids[node_def.id] = true;
                             in_use.push(node_def);
                         }
                     }
-                    initializations.add(node.name.name, node);
-                    return true; // don't go in nested scopes
-                }
-                if (node instanceof AST_Definitions && scope === self) {
-                    node.definitions.forEach(function(def){
-                        var node_def = def.name.definition();
-                        if (def.name instanceof AST_SymbolVar) {
-                            var_defs_by_id.add(node_def.id, def);
-                        }
-                        if (!drop_vars) {
-                            if (!(node_def.id in in_use_ids)) {
-                                in_use_ids[node_def.id] = true;
-                                in_use.push(node_def);
-                            }
+                    if (def.value) {
+                        initializations.add(def.name.name, def.value);
+                        if (def.value.has_side_effects(compressor)) {
+                            def.value.walk(tw);
                         }
-                        if (def.value) {
-                            initializations.add(def.name.name, def.value);
-                            if (def.value.has_side_effects(compressor)) {
-                                def.value.walk(tw);
-                            }
-                        }
-                    });
-                    return true;
-                }
-                var sym;
-                if (scope === self
-                    && (sym = assign_as_unused(node)) instanceof AST_SymbolRef
-                    && self.variables.get(sym.name) === sym.definition()) {
-                    if (node instanceof AST_Assign) node.right.walk(tw);
-                    return true;
-                }
-                if (node instanceof AST_SymbolRef) {
-                    var node_def = node.definition();
-                    if (!(node_def.id in in_use_ids)) {
-                        in_use_ids[node_def.id] = true;
-                        in_use.push(node_def);
                     }
-                    return true;
-                }
-                if (node instanceof AST_Scope) {
-                    var save_scope = scope;
-                    scope = node;
-                    descend();
-                    scope = save_scope;
-                    return true;
+                });
+                return true;
+            }
+            var sym;
+            if (scope === self
+                && (sym = assign_as_unused(node)) instanceof AST_SymbolRef
+                && self.variables.get(sym.name) === sym.definition()) {
+                if (node instanceof AST_Assign) node.right.walk(tw);
+                return true;
+            }
+            if (node instanceof AST_SymbolRef) {
+                var node_def = node.definition();
+                if (!(node_def.id in in_use_ids)) {
+                    in_use_ids[node_def.id] = true;
+                    in_use.push(node_def);
                 }
+                return true;
+            }
+            if (node instanceof AST_Scope) {
+                var save_scope = scope;
+                scope = node;
+                descend();
+                scope = save_scope;
+                return true;
             }
         });
         self.walk(tw);
@@ -2415,7 +2429,7 @@ merge(Compressor.prototype, {
                     var def = node.name.definition();
                     if (!(def.id in in_use_ids)) {
                         compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
-                        drop_decl(def, node.name);
+                        drop_decl(def);
                         return make_node(AST_EmptyStatement, node);
                     }
                     return node;
@@ -2437,7 +2451,7 @@ merge(Compressor.prototype, {
                                 if (var_defs.length > 1 && !def.value) {
                                     compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
                                     remove(var_defs, def);
-                                    drop_decl(sym, def.name);
+                                    drop_decl(sym);
                                     return;
                                 }
                             }
@@ -2470,7 +2484,7 @@ merge(Compressor.prototype, {
                             } else {
                                 compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
                             }
-                            drop_decl(sym, def.name);
+                            drop_decl(sym);
                         }
                     });
                     if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
@@ -2479,7 +2493,7 @@ merge(Compressor.prototype, {
                             var def = tail.pop();
                             compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
                             remove(var_defs, def);
-                            drop_decl(def.name.definition(), def.name);
+                            drop_decl(def.name.definition());
                             side_effects.unshift(make_node(AST_Assign, def, {
                                 operator: "=",
                                 left: make_node(AST_SymbolRef, def.name, def.name),
@@ -2561,14 +2575,6 @@ merge(Compressor.prototype, {
                         col  : sym.start.col
                     };
                 }
-
-                function drop_decl(def, decl) {
-                    remove(def.orig, decl);
-                    if (!def.orig.length) {
-                        def.scope.functions.del(def.name);
-                        def.scope.variables.del(def.name);
-                    }
-                }
             }
         );
         self.transform(tt);
@@ -3288,7 +3294,7 @@ merge(Compressor.prototype, {
                 }));
                 if (reduce_vars) name.definition().fixed = false;
             }
-            remove(def.name.definition().orig, def.name);
+            drop_decl(def.name.definition());
             return a;
         }, []);
         if (assignments.length == 0) return null;
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index e2c5f1b..fe8e409 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -1388,6 +1388,7 @@ issue_1605_1: {
     options = {
         collapse_vars: true,
         toplevel: false,
+        unused: true,
     }
     input: {
         function foo(x) {
@@ -1410,6 +1411,7 @@ issue_1605_2: {
     options = {
         collapse_vars: true,
         toplevel: "vars",
+        unused: true,
     }
     input: {
         function foo(x) {
@@ -1537,6 +1539,7 @@ issue_1631_3: {
 var_side_effects_1: {
     options = {
         collapse_vars: true,
+        unused: true,
     }
     input: {
         var print = console.log.bind(console);
@@ -1559,6 +1562,7 @@ var_side_effects_1: {
 var_side_effects_2: {
     options = {
         collapse_vars: true,
+        unused: true,
     }
     input: {
         var print = console.log.bind(console);
@@ -1584,6 +1588,7 @@ var_side_effects_3: {
         collapse_vars: true,
         pure_getters: true,
         unsafe: true,
+        unused: true,
     }
     input: {
         var print = console.log.bind(console);
@@ -1659,6 +1664,7 @@ iife_2: {
         }(foo);
     }
     expect: {
+        var foo;
         !function(x) {
             console.log(x);
         }(bar());
@@ -1945,6 +1951,7 @@ ref_scope: {
 chained_1: {
     options = {
         collapse_vars: true,
+        unused: true,
     }
     input: {
         var a = 2;
@@ -1961,6 +1968,7 @@ chained_1: {
 chained_2: {
     options = {
         collapse_vars: true,
+        unused: true,
     }
     input: {
         var a;
@@ -2061,6 +2069,7 @@ inner_lvalues: {
 double_def: {
     options = {
         collapse_vars: true,
+        unused: true,
     }
     input: {
         var a = x, a = a && y;
@@ -2075,6 +2084,7 @@ double_def: {
 toplevel_single_reference: {
     options = {
         collapse_vars: true,
+        unused: true,
     }
     input: {
         var a;
@@ -2084,9 +2094,10 @@ toplevel_single_reference: {
         }
     }
     expect: {
-        var a;
-        for (var b in x)
+        for (var b in x) {
+            var a;
             b(a = b);
+        }
     }
 }
 
@@ -2889,6 +2900,7 @@ pure_getters_chain: {
     options = {
         collapse_vars: true,
         pure_getters: true,
+        unused: true,
     }
     input: {
         function o(t, r) {
@@ -2909,6 +2921,7 @@ pure_getters_chain: {
 conditional_1: {
     options = {
         collapse_vars: true,
+        unused: true,
     }
     input: {
         function f(a, b) {
@@ -2933,6 +2946,7 @@ conditional_1: {
 conditional_2: {
     options = {
         collapse_vars: true,
+        unused: true,
     }
     input: {
         function f(a, b) {
@@ -3015,3 +3029,51 @@ issue_2425_3: {
     }
     expect_stdout: "15"
 }
+
+issue_2437: {
+    options = {
+        collapse_vars: true,
+        conditionals: true,
+        inline: true,
+        join_vars: true,
+        reduce_vars: true,
+        side_effects: true,
+        sequences: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        function foo() {
+            bar();
+        }
+        function bar() {
+            if (xhrDesc) {
+                var req = new XMLHttpRequest();
+                var result = !!req.onreadystatechange;
+                Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
+                return result;
+            }
+            else {
+                var req = new XMLHttpRequest();
+                var detectFunc = function () { };
+                req.onreadystatechange = detectFunc;
+                var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
+                req.onreadystatechange = null;
+                return result;
+            }
+        }
+        foo();
+    }
+    expect: {
+        !function() {
+            if (xhrDesc)
+                return result = !!(req = new XMLHttpRequest()).onreadystatechange,
+                    Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
+                    result;
+            var req = new XMLHttpRequest(), detectFunc = function() {};
+            req.onreadystatechange = detectFunc;
+            var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
+            req.onreadystatechange = null;
+        }();
+    }
+}
diff --git a/test/compress/issue-973.js b/test/compress/issue-973.js
index 30f886a..fee05df 100644
--- a/test/compress/issue-973.js
+++ b/test/compress/issue-973.js
@@ -51,6 +51,7 @@ this_binding_collapse_vars: {
     options = {
         collapse_vars: true,
         toplevel: true,
+        unused: true,
     };
     input: {
         var c = a; c();
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 7714ad5..1acd902 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -2131,14 +2131,13 @@ redefine_farg_1: {
     }
     expect: {
         function f(a) {
-            var a;
             return typeof a;
         }
         function g() {
-            return"number";
+            return "number";
         }
         function h(a, b) {
-            var a = b;
+            a = b;
             return typeof a;
         }
         console.log(f([]), g([]), h([]));
@@ -2173,10 +2172,9 @@ redefine_farg_2: {
     }
     expect: {
         console.log(function(a) {
-            var a;
             return typeof a;
         }([]), "number",function(a, b) {
-            var a = b;
+            a = b;
             return typeof a;
         }([]));
     }
@@ -2185,11 +2183,13 @@ redefine_farg_2: {
 
 redefine_farg_3: {
     options = {
+        cascade: true,
         evaluate: true,
         inline: true,
         keep_fargs: false,
-        passes: 3,
+        passes: 2,
         reduce_vars: true,
+        sequences: true,
         side_effects: true,
         toplevel: true,
         unused: 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