[Pkg-javascript-commits] [uglifyjs] 245/491: enhance `unsafe` `evaluate` of arrays & objects (#2394)

Jonas Smedegaard dr at jones.dk
Wed Feb 14 19:51:41 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 86ea38a25954ba4cda017fbfee5e0ef537b24bf1
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Tue Oct 24 02:58:30 2017 +0800

    enhance `unsafe` `evaluate` of arrays & objects (#2394)
---
 lib/compress.js              |  39 ++++--
 test/compress/reduce_vars.js | 290 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 319 insertions(+), 10 deletions(-)

diff --git a/lib/compress.js b/lib/compress.js
index 7085fcb..25718a5 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -311,7 +311,7 @@ merge(Compressor.prototype, {
                     d.references.push(node);
                     if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") {
                         d.fixed = false;
-                    } else {
+                    } else if (d.fixed) {
                         var value = node.fixed_value();
                         if (unused) {
                             d.single_use = value
@@ -320,14 +320,14 @@ merge(Compressor.prototype, {
                                 && d.scope === node.scope
                                 && value.is_constant_expression();
                         }
-                        if (is_modified(node, 0, is_immutable(value))) {
+                        if (is_modified(node, value, 0, is_immutable(value))) {
                             if (d.single_use) {
                                 d.single_use = "m";
                             } else {
                                 d.fixed = false;
                             }
                         } else {
-                            mark_escaped(d, node, 0);
+                            mark_escaped(d, node, value, 0);
                         }
                     }
                 }
@@ -564,25 +564,46 @@ merge(Compressor.prototype, {
             return value && (value.is_constant() || value instanceof AST_Lambda);
         }
 
-        function is_modified(node, level, immutable) {
+        function read_property(obj, key) {
+            if (key instanceof AST_Constant) key = key.getValue();
+            if (key instanceof AST_Node) return null;
+            if (obj instanceof AST_Array) {
+                return obj.elements[key];
+            } else if (obj instanceof AST_Object) {
+                var props = obj.properties;
+                var value;
+                for (var i = props.length; --i >= 0;) {
+                    var prop = props[i];
+                    if (!(prop instanceof AST_ObjectKeyVal)) return;
+                    if (!value && props[i].key === key) value = props[i].value;
+                }
+                return value;
+            }
+        }
+
+        function is_modified(node, value, level, immutable) {
             var parent = tw.parent(level);
             if (is_lhs(node, parent)
-                || !immutable && parent instanceof AST_Call && parent.expression === node) {
+                || !immutable
+                    && parent instanceof AST_Call
+                    && parent.expression === node
+                    && (!(value instanceof AST_Function) || value.contains_this())) {
                 return true;
             } else if (parent instanceof AST_PropAccess && parent.expression === node) {
-                return !immutable && is_modified(parent, level + 1);
+                return !immutable && is_modified(parent, read_property(value, parent.property), level + 1);
             }
         }
 
-        function mark_escaped(d, node, level) {
+        function mark_escaped(d, node, value, level) {
             var parent = tw.parent(level);
+            if (value instanceof AST_Constant || value instanceof AST_Function) return;
             if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
                 || parent instanceof AST_Call && node !== parent.expression
                 || parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
                 || parent instanceof AST_VarDef && node === parent.value) {
                 d.escaped = true;
             } else if (parent instanceof AST_PropAccess && node === parent.expression) {
-                mark_escaped(d, parent, level + 1);
+                mark_escaped(d, parent, read_property(value, parent.property), level + 1);
             }
         }
     });
@@ -1660,6 +1681,7 @@ merge(Compressor.prototype, {
                 var elements = [];
                 for (var i = 0, len = this.elements.length; i < len; i++) {
                     var element = this.elements[i];
+                    if (element instanceof AST_Function) continue;
                     var value = ev(element, compressor);
                     if (element === value) return this;
                     elements.push(value);
@@ -1683,6 +1705,7 @@ merge(Compressor.prototype, {
                     if (typeof Object.prototype[key] === 'function') {
                         return this;
                     }
+                    if (prop.value instanceof AST_Function) continue;
                     val[key] = ev(prop.value, compressor);
                     if (val[key] === prop.value) return this;
                 }
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 1274024..f516b9d 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -211,7 +211,91 @@ unsafe_evaluate: {
     }
 }
 
-unsafe_evaluate_object: {
+unsafe_evaluate_side_effect_free: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        unsafe: true,
+        unused: true,
+    }
+    input: {
+        console.log(function(){ var o={p:1}; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:2}; console.log(o.p); return o; }());
+    }
+    expect: {
+        console.log(function(){ console.log(1); return 1; }());
+        console.log(function(){ var o={p:2}; console.log(2); return o; }());
+    }
+    expect_stdout: true
+}
+
+unsafe_evaluate_escaped: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        unsafe: true,
+        unused: true,
+    }
+    input: {
+        console.log(function(){ var o={p:1}; console.log(o, o.p); return o.p; }());
+        console.log(function(){ var o={p:2}; console.log(o.p, o); return o.p; }());
+    }
+    expect: {
+        console.log(function(){ var o={p:1}; console.log(o, o.p); return o.p; }());
+        console.log(function(){ var o={p:2}; console.log(o.p, o); return o.p; }());
+    }
+    expect_stdout: true
+}
+
+unsafe_evaluate_modified: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        unsafe: true,
+        unused: true,
+    }
+    input: {
+        console.log(function(){ var o={p:1}; o.p++; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:2}; --o.p; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:3}; o.p += ""; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:4}; o = {}; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:5}; o.p = -9; console.log(o.p); return o.p; }());
+        function inc() { this.p++; }
+        console.log(function(){ var o={p:6}; inc.call(o); console.log(o.p); return o.p; }());
+    }
+    expect: {
+        console.log(function(){ var o={p:1}; o.p++; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:2}; --o.p; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:3}; o.p += ""; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:4}; o = {}; console.log(o.p); return o.p; }());
+        console.log(function(){ var o={p:5}; o.p = -9; console.log(o.p); return o.p; }());
+        function inc() { this.p++; }
+        console.log(function(){ var o={p:6}; inc.call(o); console.log(o.p); return o.p; }());
+    }
+    expect_stdout: true
+}
+
+unsafe_evaluate_unknown: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        unsafe: true,
+        unused: true,
+    }
+    input: {
+        console.log(function(){ var o={p:1}; console.log(o.not_present); return o.p; }());
+        console.log(function(){ var o={p:2}; console.log(o.prototype); return o.p; }());
+        console.log(function(){ var o={p:3}; console.log(o.hasOwnProperty); return o.p; }());
+    }
+    expect: {
+        console.log(function(){ var o={p:1}; console.log(o.not_present); return o.p; }());
+        console.log(function(){ var o={p:2}; console.log(o.prototype); return o.p; }());
+        console.log(function(){ var o={p:3}; console.log(o.hasOwnProperty); return o.p; }());
+    }
+    expect_stdout: true
+}
+
+unsafe_evaluate_object_1: {
     options = {
         evaluate     : true,
         reduce_vars  : true,
@@ -251,7 +335,83 @@ unsafe_evaluate_object: {
     }
 }
 
-unsafe_evaluate_array: {
+unsafe_evaluate_object_2: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unsafe: true,
+    }
+    input: {
+        var obj = {
+            foo: 1,
+            bar: 2,
+            square: function(x) {
+                return x * x;
+            },
+            cube: function(x) {
+                return x * x * x;
+            },
+        };
+        console.log(obj.foo, obj.bar, obj.square(2), obj.cube);
+    }
+    expect: {
+        var obj = {
+            foo: 1,
+            bar: 2,
+            square: function(x) {
+                return x * x;
+            },
+            cube: function(x) {
+                return x * x * x;
+            },
+        };
+        console.log(1, 2, obj.square(2), obj.cube);
+    }
+    expect_stdout: true
+}
+
+unsafe_evaluate_object_3: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unsafe: true,
+    }
+    input: {
+        var obj = {
+            get foo() {
+                return 1;
+            },
+            bar: 2,
+            square: function(x) {
+                return x * x;
+            },
+            cube: function(x) {
+                return x * x * x;
+            },
+        };
+        console.log(obj.foo, obj.bar, obj.square(2), obj.cube);
+    }
+    expect: {
+        var obj = {
+            get foo() {
+                return 1;
+            },
+            bar: 2,
+            square: function(x) {
+                return x * x;
+            },
+            cube: function(x) {
+                return x * x * x;
+            },
+        };
+        console.log(obj.foo, obj.bar, obj.square(2), obj.cube);
+    }
+    expect_stdout: true
+}
+
+unsafe_evaluate_array_1: {
     options = {
         evaluate     : true,
         reduce_vars  : true,
@@ -299,6 +459,132 @@ unsafe_evaluate_array: {
     }
 }
 
+unsafe_evaluate_array_2: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unsafe: true,
+    }
+    input: {
+        var arr = [
+            1,
+            2,
+            function(x) {
+                return x * x;
+            },
+            function(x) {
+                return x * x * x;
+            },
+        ];
+        console.log(arr[0], arr[1], arr[2](2), arr[3]);
+    }
+    expect: {
+        var arr = [
+            1,
+            2,
+            function(x) {
+                return x * x;
+            },
+            function(x) {
+                return x * x * x;
+            },
+        ];
+        console.log(1, 2, arr[2](2), arr[3]);
+    }
+    expect_stdout: true
+}
+
+unsafe_evaluate_array_3: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unsafe: true,
+    }
+    input: {
+        var arr = [
+            1,
+            2,
+            function() {
+                return ++arr[0];
+            },
+        ];
+        console.log(arr[0], arr[1], arr[2](), arr[0]);
+    }
+    expect: {
+        var arr = [
+            1,
+            2,
+            function() {
+                return ++arr[0];
+            },
+        ];
+        console.log(arr[0], arr[1], arr[2](), arr[0]);
+    }
+    expect_stdout: "1 2 2 2"
+}
+
+unsafe_evaluate_array_4: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unsafe: true,
+    }
+    input: {
+        var arr = [
+            1,
+            2,
+            function() {
+                return ++this[0];
+            },
+        ];
+        console.log(arr[0], arr[1], arr[2], arr[0]);
+    }
+    expect: {
+        var arr = [
+            1,
+            2,
+            function() {
+                return ++this[0];
+            },
+        ];
+        console.log(1, 2, arr[2], 1);
+    }
+    expect_stdout: true
+}
+
+unsafe_evaluate_array_5: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unsafe: true,
+    }
+    input: {
+        var arr = [
+            1,
+            2,
+            function() {
+                return ++this[0];
+            },
+        ];
+        console.log(arr[0], arr[1], arr[2](), arr[0]);
+    }
+    expect: {
+        var arr = [
+            1,
+            2,
+            function() {
+                return ++this[0];
+            },
+        ];
+        console.log(arr[0], arr[1], arr[2](), arr[0]);
+    }
+    expect_stdout: "1 2 2 2"
+}
+
 unsafe_evaluate_equality_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