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:
Alex Lam S.L
2017-04-06 11:18:59 +08:00
committed by GitHub
parent ff289b90a9
commit 06cdb74279
4 changed files with 113 additions and 8 deletions

View File

@@ -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":

View File

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

View 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;
}
}

View File

@@ -35,7 +35,6 @@
"compress": { "compress": {
"keep_fargs": false, "keep_fargs": false,
"passes": 3, "passes": 3,
"pure_getters": true,
"warnings": false "warnings": false
} }
} }