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
This commit is contained in:
Alex Lam S.L
2017-10-22 20:10:13 +08:00
committed by GitHub
parent 5fd723f143
commit 24aa07855b
6 changed files with 226 additions and 120 deletions

View File

@@ -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);