[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