improve pure_getters (#1786)
- property access to `null` & `undefined` always has side effects - utilise `reduce_vars` to determine safe property access - may-be cases treated as side effects unless `unsafe`
This commit is contained in:
@@ -1160,6 +1160,26 @@ merge(Compressor.prototype, {
|
|||||||
&& !node.expression.has_side_effects(compressor);
|
&& !node.expression.has_side_effects(compressor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(function(def) {
|
||||||
|
def(AST_Node, return_false);
|
||||||
|
def(AST_Null, return_true);
|
||||||
|
def(AST_Undefined, return_true);
|
||||||
|
def(AST_UnaryPrefix, function() {
|
||||||
|
return this.operator == "void";
|
||||||
|
});
|
||||||
|
def(AST_PropAccess, function(compressor) {
|
||||||
|
return !compressor.option("unsafe");
|
||||||
|
});
|
||||||
|
def(AST_SymbolRef, function(compressor) {
|
||||||
|
if (this.is_undefined) return true;
|
||||||
|
if (compressor.option("unsafe")) return false;
|
||||||
|
var fixed = this.fixed_value();
|
||||||
|
return !fixed || fixed.may_eq_null(compressor);
|
||||||
|
});
|
||||||
|
})(function(node, func) {
|
||||||
|
node.DEFMETHOD("may_eq_null", func);
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ boolean/negation helpers ]----- */
|
/* -----[ boolean/negation helpers ]----- */
|
||||||
|
|
||||||
// methods to determine whether an expression has a boolean result type
|
// methods to determine whether an expression has a boolean result type
|
||||||
@@ -1688,7 +1708,7 @@ merge(Compressor.prototype, {
|
|||||||
|| this.expression.has_side_effects(compressor);
|
|| this.expression.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor){
|
def(AST_SymbolRef, function(compressor){
|
||||||
return this.global() && this.undeclared();
|
return this.undeclared();
|
||||||
});
|
});
|
||||||
def(AST_Object, function(compressor){
|
def(AST_Object, function(compressor){
|
||||||
return any(this.properties, compressor);
|
return any(this.properties, compressor);
|
||||||
@@ -1701,16 +1721,15 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Dot, function(compressor){
|
def(AST_Dot, function(compressor){
|
||||||
if (!compressor.option("pure_getters")) return true;
|
if (!compressor.option("pure_getters")) return true;
|
||||||
return this.expression.has_side_effects(compressor);
|
return this.expression.may_eq_null(compressor)
|
||||||
|
|| this.expression.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Sub, function(compressor){
|
def(AST_Sub, function(compressor){
|
||||||
if (!compressor.option("pure_getters")) return true;
|
if (!compressor.option("pure_getters")) return true;
|
||||||
return this.expression.has_side_effects(compressor)
|
return this.expression.may_eq_null(compressor)
|
||||||
|
|| this.expression.has_side_effects(compressor)
|
||||||
|| this.property.has_side_effects(compressor);
|
|| this.property.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_PropAccess, function(compressor){
|
|
||||||
return !compressor.option("pure_getters");
|
|
||||||
});
|
|
||||||
def(AST_Seq, function(compressor){
|
def(AST_Seq, function(compressor){
|
||||||
return this.car.has_side_effects(compressor)
|
return this.car.has_side_effects(compressor)
|
||||||
|| this.cdr.has_side_effects(compressor);
|
|| this.cdr.has_side_effects(compressor);
|
||||||
@@ -2275,10 +2294,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Dot, function(compressor, first_in_statement){
|
def(AST_Dot, function(compressor, first_in_statement){
|
||||||
if (!compressor.option("pure_getters")) return this;
|
if (!compressor.option("pure_getters")) return this;
|
||||||
|
if (this.expression.may_eq_null(compressor)) return this;
|
||||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||||
});
|
});
|
||||||
def(AST_Sub, function(compressor, first_in_statement){
|
def(AST_Sub, function(compressor, first_in_statement){
|
||||||
if (!compressor.option("pure_getters")) return this;
|
if (!compressor.option("pure_getters")) return this;
|
||||||
|
if (this.expression.may_eq_null(compressor)) return this;
|
||||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
|
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
|
||||||
var property = this.property.drop_side_effect_free(compressor);
|
var property = this.property.drop_side_effect_free(compressor);
|
||||||
@@ -3509,7 +3530,6 @@ merge(Compressor.prototype, {
|
|||||||
// testing against !self.scope.uses_with first is an optimization
|
// testing against !self.scope.uses_with first is an optimization
|
||||||
if (compressor.option("screw_ie8")
|
if (compressor.option("screw_ie8")
|
||||||
&& self.undeclared()
|
&& self.undeclared()
|
||||||
&& !isLHS(self, compressor.parent())
|
|
||||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||||
switch (self.name) {
|
switch (self.name) {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
|
|||||||
@@ -1573,6 +1573,7 @@ var_side_effects_3: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
pure_getters: true,
|
pure_getters: true,
|
||||||
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var print = console.log.bind(console);
|
var print = console.log.bind(console);
|
||||||
|
|||||||
85
test/compress/pure_getters.js
Normal file
85
test/compress/pure_getters.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
side_effects: {
|
||||||
|
options = {
|
||||||
|
pure_getters: true,
|
||||||
|
reduce_vars: false,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b = null, c = {};
|
||||||
|
a.prop;
|
||||||
|
b.prop;
|
||||||
|
c.prop;
|
||||||
|
d.prop;
|
||||||
|
null.prop;
|
||||||
|
(void 0).prop;
|
||||||
|
undefined.prop;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b = null, c = {};
|
||||||
|
a.prop;
|
||||||
|
b.prop;
|
||||||
|
c.prop;
|
||||||
|
d.prop;
|
||||||
|
null.prop;
|
||||||
|
(void 0).prop;
|
||||||
|
(void 0).prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
side_effects_reduce_vars: {
|
||||||
|
options = {
|
||||||
|
pure_getters: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b = null, c = {};
|
||||||
|
a.prop;
|
||||||
|
b.prop;
|
||||||
|
c.prop;
|
||||||
|
d.prop;
|
||||||
|
null.prop;
|
||||||
|
(void 0).prop;
|
||||||
|
undefined.prop;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b = null, c = {};
|
||||||
|
a.prop;
|
||||||
|
b.prop;
|
||||||
|
d.prop;
|
||||||
|
null.prop;
|
||||||
|
(void 0).prop;
|
||||||
|
(void 0).prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
side_effects_unsafe: {
|
||||||
|
options = {
|
||||||
|
pure_getters: true,
|
||||||
|
reduce_vars: false,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b = null, c = {};
|
||||||
|
a.prop;
|
||||||
|
b.prop;
|
||||||
|
c.prop;
|
||||||
|
d.prop;
|
||||||
|
null.prop;
|
||||||
|
(void 0).prop;
|
||||||
|
undefined.prop;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b = null, c = {};
|
||||||
|
d;
|
||||||
|
null.prop;
|
||||||
|
(void 0).prop;
|
||||||
|
(void 0).prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,6 @@
|
|||||||
"compress": {
|
"compress": {
|
||||||
"keep_fargs": false,
|
"keep_fargs": false,
|
||||||
"passes": 3,
|
"passes": 3,
|
||||||
"pure_getters": true,
|
|
||||||
"warnings": false
|
"warnings": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user