[Pkg-javascript-commits] [uglifyjs] 275/491: allow symbol replacement on multiple occurrences (#2472)

Jonas Smedegaard dr at jones.dk
Wed Feb 14 19:51:44 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 c6cfa04d10c648dc1ccdf7ac6369f4162f0a46dc
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Sun Nov 12 22:31:47 2017 +0800

    allow symbol replacement on multiple occurrences (#2472)
    
    - all-or-nothing replacement
    - avoid unmangleable names
    
    fixes #2436
---
 lib/compress.js                |  71 +++++--
 lib/scope.js                   |   2 +
 test/compress/collapse_vars.js | 420 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 481 insertions(+), 12 deletions(-)

diff --git a/lib/compress.js b/lib/compress.js
index fdf3a2b..54ac3d7 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -796,8 +796,8 @@ merge(Compressor.prototype, {
     });
 
     function drop_decl(def) {
-        def._eliminiated = (def._eliminiated || 0) + 1;
-        if (def.orig.length == def._eliminiated) {
+        def.eliminated++;
+        if (def.orig.length == def.eliminated) {
             def.scope.functions.del(def.name);
             def.scope.variables.del(def.name);
         }
@@ -854,10 +854,14 @@ merge(Compressor.prototype, {
                     // 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 one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
+                    var replace_all = candidate.multiple;
+                    if (!replace_all && lhs instanceof AST_SymbolRef) {
+                        var def = lhs.definition();
+                        replace_all = def.references.length - def.replaced == 1;
+                    }
                     var side_effects = value_has_side_effects(candidate);
                     var hit = candidate.name instanceof AST_SymbolFunarg;
-                    var abort = false, replaced = false, can_replace = !args || !hit;
+                    var abort = false, replaced = 0, can_replace = !args || !hit;
                     var tt = new TreeTransformer(function(node, descend) {
                         if (abort) return node;
                         // Skip nodes before `candidate` as quickly as possible
@@ -886,7 +890,8 @@ merge(Compressor.prototype, {
                             && !(node instanceof AST_SymbolDeclaration)
                             && !is_lhs(node, parent)
                             && lhs.equivalent_to(node)) {
-                            CHANGED = replaced = abort = true;
+                            CHANGED = abort = true;
+                            replaced++;
                             compressor.info("Collapsing {name} [{file}:{line},{col}]", {
                                 name: node.print_to_string(),
                                 file: node.start.file,
@@ -897,8 +902,13 @@ merge(Compressor.prototype, {
                                 return make_node(AST_UnaryPrefix, candidate, candidate);
                             }
                             if (candidate instanceof AST_VarDef) {
+                                if (candidate.multiple) {
+                                    abort = false;
+                                    return node;
+                                }
                                 var def = candidate.name.definition();
-                                if (def.references.length == 1 && !compressor.exposed(def)) {
+                                if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
+                                    def.replaced++;
                                     return maintain_this_binding(parent, node, candidate.value);
                                 }
                                 return make_node(AST_Assign, candidate, {
@@ -922,7 +932,7 @@ merge(Compressor.prototype, {
                                    || side_effects && !references_in_scope(node.definition()))
                             || (sym = lhs_or_def(node))
                                 && (sym instanceof AST_PropAccess || sym.name in lvalues)
-                            || (side_effects || !one_off)
+                            || (side_effects || !replace_all)
                                 && (parent instanceof AST_Binary && lazy_op(parent.operator)
                                     || parent instanceof AST_Case
                                     || parent instanceof AST_Conditional
@@ -935,7 +945,7 @@ merge(Compressor.prototype, {
                         if (node instanceof AST_Default || node instanceof AST_Scope) return node;
                     });
                     if (!can_replace) {
-                        for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; j < args.length; j++) {
+                        for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; !abort && j < args.length; j++) {
                             args[j].transform(tt);
                         }
                         can_replace = true;
@@ -943,6 +953,33 @@ merge(Compressor.prototype, {
                     for (var i = stat_index; !abort && i < statements.length; i++) {
                         statements[i].transform(tt);
                     }
+                    if (candidate.multiple) {
+                        var def = candidate.name.definition();
+                        if (abort && def.references.length > replaced) replaced = false;
+                        else {
+                            abort = false;
+                            hit = candidate.name instanceof AST_SymbolFunarg;
+                            var value_def = candidate.value.definition();
+                            for (var i = stat_index; !abort && i < statements.length; i++) {
+                                statements[i].transform(new TreeTransformer(function(node) {
+                                    if (abort) return node;
+                                    if (!hit) {
+                                        if (node === candidate) {
+                                            hit = true;
+                                            return node;
+                                        }
+                                        return;
+                                    }
+                                    if (node instanceof AST_SymbolRef && node.name == def.name) {
+                                        def.replaced++;
+                                        value_def.replaced--;
+                                        if (!--replaced) abort = true;
+                                        return candidate.value;
+                                    }
+                                }));
+                            }
+                        }
+                    }
                     if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
                 }
             }
@@ -956,7 +993,7 @@ merge(Compressor.prototype, {
                     && (iife = compressor.parent()) instanceof AST_Call
                     && iife.expression === fn) {
                     var fn_strict = compressor.has_directive("use strict");
-                    if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
+                    if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false;
                     var len = fn.argnames.length;
                     args = iife.args.slice(len);
                     var names = Object.create(null);
@@ -1012,12 +1049,22 @@ merge(Compressor.prototype, {
                 }
             }
 
+            function mangleable_var(expr) {
+                var value = expr.value;
+                if (!(value instanceof AST_SymbolRef)) return false;
+                if (value.name == "arguments") return false;
+                if (value.definition().undeclared) return false;
+                expr.multiple = true;
+                return true;
+            }
+
             function get_lhs(expr) {
                 if (expr instanceof AST_VarDef) {
                     var def = expr.name.definition();
-                    if (def.orig.length - (def._eliminiated || 0) > 1
-                            && !(expr.name instanceof AST_SymbolFunarg)
-                        || def.references.length == 1 && !compressor.exposed(def)) {
+                    var declared = def.orig.length - def.eliminated;
+                    var referenced = def.references.length - def.replaced;
+                    if (declared > 1 && !(expr.name instanceof AST_SymbolFunarg)
+                        || (referenced > 1 ? mangleable_var(expr) : !compressor.exposed(def))) {
                         return make_node(AST_SymbolRef, expr.name, expr.name);
                     }
                 } else {
diff --git a/lib/scope.js b/lib/scope.js
index 8e766a5..0d2a7ae 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -46,8 +46,10 @@
 function SymbolDef(scope, index, orig) {
     this.name = orig.name;
     this.orig = [ orig ];
+    this.eliminated = 0;
     this.scope = scope;
     this.references = [];
+    this.replaced = 0;
     this.global = false;
     this.mangled_name = null;
     this.undeclared = false;
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index d98dca9..402bd22 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -3098,3 +3098,423 @@ issue_2437: {
         }();
     }
 }
+
+issue_2436_1: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log({
+            x: o.a,
+            y: o.b,
+        });
+    }
+    expect_stdout: true
+}
+
+issue_2436_2: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(c) {
+            o.a = 3;
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(c) {
+            o.a = 3;
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect_stdout: true
+}
+
+issue_2436_3: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(c) {
+            o = {
+                a: 3,
+                b: 4,
+            };
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(c) {
+            o = {
+                a: 3,
+                b: 4,
+            };
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect_stdout: true
+}
+
+issue_2436_4: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+            var o;
+        }(o));
+    }
+    expect: {
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }({
+            a: 1,
+            b: 2,
+        }));
+    }
+    expect_stdout: true
+}
+
+issue_2436_5: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(o) {
+            return {
+                x: o.a,
+                y: o.b,
+            };
+        }(o));
+    }
+    expect: {
+        console.log(function(o) {
+            return {
+                x: o.a,
+                y: o.b,
+            };
+        }({
+            a: 1,
+            b: 2,
+        }));
+    }
+    expect_stdout: true
+}
+
+issue_2436_6: {
+    options = {
+        collapse_vars: true,
+        evaluate: true,
+        inline: true,
+        passes: 2,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+        unsafe: true,
+    }
+    input: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect: {
+        console.log({
+            x: 1,
+            y: 2,
+        });
+    }
+    expect_stdout: true
+}
+
+issue_2436_7: {
+    options = {
+        collapse_vars: true,
+        hoist_props: true,
+        inline: true,
+        passes: 3,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect: {
+        console.log({
+            x: 1,
+            y: 2,
+        });
+    }
+    expect_stdout: true
+}
+
+issue_2436_8: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect: {
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect_stdout: true
+}
+
+issue_2436_9: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var o = console;
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect: {
+        var o = console;
+        console.log(function(c) {
+            return {
+                x: c.a,
+                y: c.b,
+            };
+        }(o));
+    }
+    expect_stdout: true
+}
+
+issue_2436_10: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        pure_getters: true,
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        function f(n) {
+            o = { b: 3 };
+            return n;
+        }
+        console.log(function(c) {
+            return [
+                c.a,
+                f(c.b),
+                c.b,
+            ];
+        }(o).join(" "));
+    }
+    expect: {
+        var o = {
+            a: 1,
+            b: 2,
+        };
+        function f(n) {
+            o = { b: 3 };
+            return n;
+        }
+        console.log(function(c) {
+            return [
+                c.a,
+                f(c.b),
+                c.b,
+            ];
+        }(o).join(" "));
+    }
+    expect_stdout: "1 2 2"
+}
+
+issue_2436_11: {
+    options = {
+        collapse_vars: true,
+        join_vars: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        function matrix() {}
+        function isCollection() {}
+        function _randomDataForMatrix() {}
+        function _randomInt() {}
+        function f(arg1, arg2) {
+            if (isCollection(arg1)) {
+                var size = arg1;
+                var max = arg2;
+                var min = 0;
+                var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
+                return size && true === size.isMatrix ? matrix(res) : res;
+            } else {
+                var min = arg1;
+                var max = arg2;
+                return _randomInt(min, max);
+            }
+        }
+    }
+    expect: {
+        function matrix() {}
+        function isCollection() {}
+        function _randomDataForMatrix() {}
+        function _randomInt() {}
+        function f(arg1, arg2) {
+            if (isCollection(arg1)) {
+                var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
+                return size && true === size.isMatrix ? matrix(res) : res;
+            } else {
+                return _randomInt(min = arg1, max = arg2);
+            }
+        }
+    }
+}
+
+issue_2436_12: {
+    options = {
+        collapse_vars: true,
+        unused: true,
+    }
+    input: {
+        function isUndefined() {}
+        function f() {
+            var viewValue = this.$$lastCommittedViewValue;
+            var modelValue = viewValue;
+            return isUndefined(modelValue) ? modelValue : null;
+        }
+    }
+    expect: {
+        function isUndefined() {}
+        function f() {
+            var modelValue = this.$$lastCommittedViewValue;
+            return isUndefined(modelValue) ? modelValue : null;
+        }
+    }
+}

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