[Pkg-javascript-commits] [uglifyjs] 243/491: safer `properties` transform (#2391)

Jonas Smedegaard dr at jones.dk
Wed Feb 14 19:51:40 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 24aa07855bc608f29cca2a58a40af1988256b116
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Sun Oct 22 20:10:13 2017 +0800

    safer `properties` transform (#2391)
    
    `{ a: x, b: y }.a` => `[ x, y ][0]`
    - `x` cannot be function containing `this`
    
    `[ x, y, z ][1]` => `(x, z, y)`
    - only if `z` is side-effect-free
---
 lib/compress.js                | 100 ++++++++++++++++++++--------
 test/compress/collapse_vars.js |  67 -------------------
 test/compress/evaluate.js      |  22 +++----
 test/compress/functions.js     |   2 +-
 test/compress/properties.js    | 145 ++++++++++++++++++++++++++++++++++++++---
 test/compress/reduce_vars.js   |   4 +-
 6 files changed, 223 insertions(+), 117 deletions(-)

diff --git a/lib/compress.js b/lib/compress.js
index 8bc0e26..eb0e201 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -4452,20 +4452,56 @@ merge(Compressor.prototype, {
     });
 
     OPT(AST_Sub, function(self, compressor){
-        var prop = self.property;
-        if (prop instanceof AST_String && compressor.option("properties")) {
-            prop = prop.getValue();
-            if (is_identifier_string(prop)) {
-                return make_node(AST_Dot, self, {
-                    expression : self.expression,
-                    property   : prop
-                }).optimize(compressor);
+        if (compressor.option("properties")) {
+            var prop = self.property;
+            if (prop instanceof AST_String) {
+                prop = prop.getValue();
+                if (is_identifier_string(prop)) {
+                    return make_node(AST_Dot, self, {
+                        expression : self.expression,
+                        property   : prop
+                    }).optimize(compressor);
+                }
+                var v = parseFloat(prop);
+                if (!isNaN(v) && v.toString() == prop) {
+                    self.property = make_node(AST_Number, self.property, {
+                        value: v
+                    });
+                }
             }
-            var v = parseFloat(prop);
-            if (!isNaN(v) && v.toString() == prop) {
-                self.property = make_node(AST_Number, self.property, {
-                    value: v
-                });
+            if (prop instanceof AST_Number && self.expression instanceof AST_Array) {
+                prop = prop.getValue();
+                var elements = self.expression.elements;
+                if (prop in elements) {
+                    var flatten = true;
+                    var values = [];
+                    for (var i = elements.length; --i > prop;) {
+                        var value = elements[i].drop_side_effect_free(compressor);
+                        if (value) {
+                            values.unshift(value);
+                            if (flatten && value.has_side_effects(compressor)) flatten = false;
+                        }
+                    }
+                    var retValue = elements[prop];
+                    retValue = retValue instanceof AST_Hole ? make_node(AST_Undefined, retValue) : retValue;
+                    if (!flatten) values.unshift(retValue);
+                    while (--i >= 0) {
+                        var value = elements[i].drop_side_effect_free(compressor);
+                        if (value) values.unshift(value);
+                        else prop--;
+                    }
+                    if (flatten) {
+                        values.push(retValue);
+                        return make_sequence(self, values).optimize(compressor);
+                    } else return make_node(AST_Sub, self, {
+                        expression: make_node(AST_Array, self.expression, {
+                            elements: values
+                        }),
+                        property: make_node(AST_Number, self.property, {
+                            value: prop
+                        })
+                    });
+                }
             }
         }
         if (is_lhs(self, compressor.parent())) return self;
@@ -4493,20 +4529,6 @@ merge(Compressor.prototype, {
         if (def) {
             return def.optimize(compressor);
         }
-        if (is_lhs(self, compressor.parent())) return self;
-        if (compressor.option("unsafe") && self.expression instanceof AST_Object) {
-            var values = self.expression.properties;
-            for (var i = values.length; --i >= 0;) {
-                if (values[i].key === self.property) {
-                    var value = values[i].value;
-                    if (value instanceof AST_Function ? value.contains_this() : value.has_side_effects(compressor)) break;
-                    var obj = self.expression.clone();
-                    obj.properties = obj.properties.slice();
-                    obj.properties.splice(i, 1);
-                    return make_sequence(self, [ obj, value ]).optimize(compressor);
-                }
-            }
-        }
         if (compressor.option("unsafe_proto")
             && self.expression instanceof AST_Dot
             && self.expression.property == "prototype") {
@@ -4529,6 +4551,30 @@ merge(Compressor.prototype, {
                 break;
             }
         }
+        if (is_lhs(self, compressor.parent())) return self;
+        if (compressor.option("properties") && self.expression instanceof AST_Object) {
+            var props = self.expression.properties;
+            for (var i = props.length; --i >= 0;) {
+                var prop = props[i];
+                if (prop.key === self.property) {
+                    if (!all(props, function(prop) {
+                        return prop instanceof AST_ObjectKeyVal;
+                    })) break;
+                    var value = prop.value;
+                    if (value instanceof AST_Function && value.contains_this()) break;
+                    return make_node(AST_Sub, self, {
+                        expression: make_node(AST_Array, self.expression, {
+                            elements: props.map(function(prop) {
+                                return prop.value;
+                            })
+                        }),
+                        property: make_node(AST_Number, self, {
+                            value: i
+                        })
+                    }).optimize(compressor);
+                }
+            }
+        }
         var ev = self.evaluate(compressor);
         if (ev !== self) {
             ev = make_node_from_constant(ev, self).optimize(compressor);
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index 52b2ddf..1f702ad 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -2534,73 +2534,6 @@ issue_2319_3: {
     expect_stdout: "true"
 }
 
-prop_side_effects_1: {
-    options = {
-        collapse_vars: true,
-        evaluate: true,
-        pure_getters: "strict",
-        reduce_vars: true,
-        toplevel: true,
-        unsafe: true,
-        unused: true,
-    }
-    input: {
-        var C = 1;
-        console.log(C);
-        var obj = {
-            bar: function() {
-                return C + C;
-            }
-        };
-        console.log(obj.bar());
-    }
-    expect: {
-        console.log(1);
-        console.log({
-            bar: function() {
-                return 2;
-            }
-        }.bar());
-    }
-    expect_stdout: [
-        "1",
-        "2",
-    ]
-}
-
-prop_side_effects_2: {
-    options = {
-        collapse_vars: true,
-        evaluate: true,
-        inline: true,
-        passes: 2,
-        pure_getters: "strict",
-        reduce_vars: true,
-        side_effects: true,
-        toplevel: true,
-        unsafe: true,
-        unused: true,
-    }
-    input: {
-        var C = 1;
-        console.log(C);
-        var obj = {
-            bar: function() {
-                return C + C;
-            }
-        };
-        console.log(obj.bar());
-    }
-    expect: {
-        console.log(1);
-        console.log(2);
-    }
-    expect_stdout: [
-        "1",
-        "2",
-    ]
-}
-
 issue_2365: {
     options = {
         collapse_vars: true,
diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js
index 5f5a4a9..fe9464b 100644
--- a/test/compress/evaluate.js
+++ b/test/compress/evaluate.js
@@ -386,10 +386,10 @@ unsafe_object_accessor: {
     }
 }
 
-unsafe_function: {
+prop_function: {
     options = {
-        evaluate  : true,
-        unsafe    : true
+        evaluate: true,
+        properties: true,
     }
     input: {
         console.log(
@@ -402,9 +402,9 @@ unsafe_function: {
     expect: {
         console.log(
             ({a:{b:1},b:function(){}}) + 1,
-            ({b:function(){}}, {b:1}) + 1,
-            ({a:{b:1}}, function(){}) + 1,
-            ({b:function(){}}, {b:1}).b + 1
+            ({b:1}) + 1,
+            function(){} + 1,
+            2
         );
     }
     expect_stdout: true
@@ -630,10 +630,10 @@ unsafe_string_bad_index: {
     expect_stdout: true
 }
 
-unsafe_prototype_function: {
+prototype_function: {
     options = {
-        evaluate  : true,
-        unsafe    : true
+        evaluate: true,
+        properties: true,
     }
     input: {
         var a = ({valueOf: 0}) < 1;
@@ -652,8 +652,8 @@ unsafe_prototype_function: {
         var d = ({toString: 0}) + "";
         var e = (({valueOf: 0}) + "")[2];
         var f = (({toString: 0}) + "")[2];
-        var g = ({}, 0)();
-        var h = ({}, 0)();
+        var g = 0();
+        var h = 0();
     }
 }
 
diff --git a/test/compress/functions.js b/test/compress/functions.js
index 6c82557..febf81c 100644
--- a/test/compress/functions.js
+++ b/test/compress/functions.js
@@ -153,10 +153,10 @@ function_returning_constant_literal: {
     options = {
         inline: true,
         passes: 2,
+        properties: true,
         reduce_vars: true,
         side_effects: true,
         toplevel: true,
-        unsafe: true,
         unused: true,
     }
     input: {
diff --git a/test/compress/properties.js b/test/compress/properties.js
index 496a43c..f435d37 100644
--- a/test/compress/properties.js
+++ b/test/compress/properties.js
@@ -677,8 +677,8 @@ accessor_this: {
 issue_2208_1: {
     options = {
         inline: true,
+        properties: true,
         side_effects: true,
-        unsafe: true,
     }
     input: {
         console.log({
@@ -696,8 +696,8 @@ issue_2208_1: {
 issue_2208_2: {
     options = {
         inline: true,
+        properties: true,
         side_effects: true,
-        unsafe: true,
     }
     input: {
         console.log({
@@ -721,8 +721,8 @@ issue_2208_2: {
 issue_2208_3: {
     options = {
         inline: true,
+        properties: true,
         side_effects: true,
-        unsafe: true,
     }
     input: {
         a = 42;
@@ -746,8 +746,8 @@ issue_2208_3: {
 issue_2208_4: {
     options = {
         inline: true,
+        properties: true,
         side_effects: true,
-        unsafe: true,
     }
     input: {
         function foo() {}
@@ -770,8 +770,8 @@ issue_2208_4: {
 issue_2208_5: {
     options = {
         inline: true,
+        properties: true,
         side_effects: true,
-        unsafe: true,
     }
     input: {
         console.log({
@@ -808,7 +808,7 @@ issue_2256: {
 lhs_prop_1: {
     options = {
         evaluate: true,
-        unsafe: true,
+        properties: true,
     }
     input: {
         console.log(++{
@@ -827,9 +827,9 @@ lhs_prop_2: {
     options = {
         evaluate: true,
         inline: true,
+        properties: true,
         reduce_vars: true,
         side_effects: true,
-        unsafe: true,
         unused: true,
     }
     input: {
@@ -844,7 +844,7 @@ lhs_prop_2: {
 
 literal_duplicate_key_side_effects: {
     options = {
-        unsafe: true,
+        properties: true,
     }
     input: {
         console.log({
@@ -853,10 +853,137 @@ literal_duplicate_key_side_effects: {
         }.a);
     }
     expect: {
+        console.log(console.log ? "PASS" : "FAIL");
+    }
+    expect_stdout: "PASS"
+}
+
+prop_side_effects_1: {
+    options = {
+        evaluate: true,
+        inline: true,
+        properties: true,
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var C = 1;
+        console.log(C);
+        var obj = {
+            bar: function() {
+                return C + C;
+            }
+        };
+        console.log(obj.bar());
+    }
+    expect: {
+        console.log(1);
+        var obj = {
+            bar: function() {
+                return 2;
+            }
+        };
+        console.log(obj.bar());
+    }
+    expect_stdout: [
+        "1",
+        "2",
+    ]
+}
+
+prop_side_effects_2: {
+    options = {
+        evaluate: true,
+        inline: true,
+        passes: 2,
+        properties: true,
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var C = 1;
+        console.log(C);
+        var obj = {
+            bar: function() {
+                return C + C;
+            }
+        };
+        console.log(obj.bar());
+    }
+    expect: {
+        console.log(1);
+        console.log(2);
+    }
+    expect_stdout: [
+        "1",
+        "2",
+    ]
+}
+
+accessor_1: {
+    options = {
+        properties: true,
+    }
+    input: {
+        console.log({
+            a: "FAIL",
+            get a() {
+                return "PASS";
+            }
+        }.a);
+    }
+    expect: {
         console.log({
             a: "FAIL",
-            a: console.log ? "PASS" : "FAIL"
+            get a() {
+                return "PASS";
+            }
         }.a);
     }
     expect_stdout: "PASS"
+    node_version: ">=4"
+}
+
+accessor_2: {
+    options = {
+        properties: true,
+    }
+    input: {
+        console.log({
+            get a() {
+                return "PASS";
+            },
+            set a(v) {},
+            a: "FAIL"
+        }.a);
+    }
+    expect: {
+        console.log({
+            get a() {
+                return "PASS";
+            },
+            set a(v) {},
+            a: "FAIL"
+        }.a);
+    }
+    expect_stdout: true
+}
+
+array_hole: {
+    options = {
+        properties: true,
+    }
+    input: {
+        console.log(
+            [ 1, 2, , 3][1],
+            [ 1, 2, , 3][2],
+            [ 1, 2, , 3][3]
+        );
+    }
+    expect: {
+        console.log(2, void 0, 3);
+    }
+    expect_stdout: "2 undefined 3"
 }
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 681dafd..1274024 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -2660,8 +2660,8 @@ obj_var_2: {
         evaluate: true,
         inline: true,
         passes: 2,
+        properties: true,
         reduce_vars: true,
-        side_effects: true,
         toplevel: true,
         unsafe: true,
         unused: true,
@@ -2716,10 +2716,10 @@ obj_arg_2: {
         evaluate: true,
         inline: true,
         passes: 2,
+        properties: true,
         reduce_vars: true,
         side_effects: true,
         toplevel: true,
-        unsafe: true,
         unused: true,
     }
     input: {

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