enhance unsafe (#3382)

This commit is contained in:
Alex Lam S.L
2019-04-25 02:42:54 +08:00
committed by GitHub
parent c215706350
commit c56d89f804
2 changed files with 86 additions and 34 deletions

View File

@@ -2532,6 +2532,20 @@ merge(Compressor.prototype, {
return this.operator == "+" && return this.operator == "+" &&
(this.left.is_string(compressor) || this.right.is_string(compressor)); (this.left.is_string(compressor) || this.right.is_string(compressor));
}); });
var fn = makePredicate([
"charAt",
"substr",
"substring",
"toLowerCase",
"toString",
"toUpperCase",
"trim",
]);
def(AST_Call, function(compressor) {
if (!compressor.option("unsafe")) return false;
var exp = this.expression;
return exp instanceof AST_Dot && fn[exp.property];
});
def(AST_Conditional, function(compressor) { def(AST_Conditional, function(compressor) {
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor); return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
}); });
@@ -2539,6 +2553,9 @@ merge(Compressor.prototype, {
return this.tail_node().is_string(compressor); return this.tail_node().is_string(compressor);
}); });
def(AST_String, return_true); def(AST_String, return_true);
def(AST_Sub, function(compressor) {
return this.expression.is_string(compressor) && this.property instanceof AST_Number;
});
def(AST_SymbolRef, function(compressor) { def(AST_SymbolRef, function(compressor) {
var fixed = this.fixed_value(); var fixed = this.fixed_value();
if (!fixed) return false; if (!fixed) return false;
@@ -3127,25 +3144,31 @@ merge(Compressor.prototype, {
return this.pure || !compressor.pure_funcs(this); return this.pure || !compressor.pure_funcs(this);
}); });
AST_Node.DEFMETHOD("is_call_pure", return_false); AST_Node.DEFMETHOD("is_call_pure", return_false);
AST_Dot.DEFMETHOD("is_call_pure", function(compressor) { AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
if (!compressor.option("unsafe")) return; if (!compressor.option("unsafe")) return false;
var expr = this.expression; var dot = this.expression;
if (!(dot instanceof AST_Dot)) return false;
var exp = dot.expression;
var map; var map;
if (expr instanceof AST_Array) { var prop = dot.property;
if (exp instanceof AST_Array) {
map = native_fns.Array; map = native_fns.Array;
} else if (expr.is_boolean(compressor)) { } else if (exp.is_boolean(compressor)) {
map = native_fns.Boolean; map = native_fns.Boolean;
} else if (expr.is_number(compressor)) { } else if (exp.is_number(compressor)) {
map = native_fns.Number; map = native_fns.Number;
} else if (expr instanceof AST_RegExp) { } else if (exp instanceof AST_RegExp) {
map = native_fns.RegExp; map = native_fns.RegExp;
} else if (expr.is_string(compressor)) { } else if (exp.is_string(compressor)) {
if (this.property == "replace") return false;
map = native_fns.String; map = native_fns.String;
} else if (!this.may_throw_on_access(compressor)) { if (prop == "replace") {
var arg = this.args[1];
if (arg && !arg.is_string(compressor)) return false;
}
} else if (!dot.may_throw_on_access(compressor)) {
map = native_fns.Object; map = native_fns.Object;
} }
return map && map[this.property]; return map && map[prop];
}); });
// determine if expression has side effects // determine if expression has side effects
@@ -3170,8 +3193,7 @@ merge(Compressor.prototype, {
}); });
def(AST_Call, function(compressor) { def(AST_Call, function(compressor) {
if (!this.is_expr_pure(compressor) if (!this.is_expr_pure(compressor)
&& (!this.expression.is_call_pure(compressor) && (!this.is_call_pure(compressor) || this.expression.has_side_effects(compressor))) {
|| this.expression.has_side_effects(compressor))) {
return true; return true;
} }
return any(this.args, compressor); return any(this.args, compressor);
@@ -4162,16 +4184,15 @@ merge(Compressor.prototype, {
}); });
def(AST_Call, function(compressor, first_in_statement) { def(AST_Call, function(compressor, first_in_statement) {
if (!this.is_expr_pure(compressor)) { if (!this.is_expr_pure(compressor)) {
if (this.expression.is_call_pure(compressor)) { var exp = this.expression;
if (this.is_call_pure(compressor)) {
var exprs = this.args.slice(); var exprs = this.args.slice();
exprs.unshift(this.expression.expression); exprs.unshift(exp.expression);
exprs = trim(exprs, compressor, first_in_statement); exprs = trim(exprs, compressor, first_in_statement);
return exprs && make_sequence(this, exprs); return exprs && make_sequence(this, exprs);
} }
if (this.expression instanceof AST_Function if (exp instanceof AST_Function && (!exp.name || !exp.name.definition().references.length)) {
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
var node = this.clone(); var node = this.clone();
var exp = node.expression;
exp.process_expression(false, compressor); exp.process_expression(false, compressor);
exp.walk(new TreeWalker(function(node) { exp.walk(new TreeWalker(function(node) {
if (node instanceof AST_Return && node.value) { if (node instanceof AST_Return && node.value) {
@@ -4963,15 +4984,21 @@ merge(Compressor.prototype, {
} }
break; break;
case "charAt": case "charAt":
if (exp.expression.is_string(compressor)) { if (self.args.length < 2) {
var arg = self.args[0]; var node = make_node(AST_Sub, self, {
var index = arg ? arg.evaluate(compressor) : 0; expression: exp.expression,
if (index !== arg) { property: self.args.length ? make_node(AST_Binary, self.args[0], {
return make_node(AST_Sub, exp, { operator: "|",
expression: exp.expression, left: make_node(AST_Number, self, {
property: make_node_from_constant(index | 0, arg || exp) value: 0
}).optimize(compressor); }),
} right: self.args[0]
}) : make_node(AST_Number, self, {
value: 0
})
});
node.is_string = return_true;
return node.optimize(compressor);
} }
break; break;
case "apply": case "apply":
@@ -5610,7 +5637,8 @@ merge(Compressor.prototype, {
} }
break; break;
} }
if (compressor.option("booleans") && self.operator == "+" && compressor.in_boolean_context()) { if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
case "+":
var ll = self.left.evaluate(compressor); var ll = self.left.evaluate(compressor);
var rr = self.right.evaluate(compressor); var rr = self.right.evaluate(compressor);
if (ll && typeof ll == "string") { if (ll && typeof ll == "string") {
@@ -5627,6 +5655,20 @@ merge(Compressor.prototype, {
make_node(AST_True, self) make_node(AST_True, self)
]).optimize(compressor); ]).optimize(compressor);
} }
break;
case "==":
if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) {
return make_node(AST_UnaryPrefix, self, {
operator: "!",
expression: self.right
}).optimize(compressor);
}
break;
case "!=":
if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) {
return self.right.optimize(compressor);
}
break;
} }
if (compressor.option("comparisons") && self.is_boolean(compressor)) { if (compressor.option("comparisons") && self.is_boolean(compressor)) {
if (!(compressor.parent() instanceof AST_Binary) if (!(compressor.parent() instanceof AST_Binary)
@@ -5646,12 +5688,12 @@ merge(Compressor.prototype, {
if (self.right instanceof AST_String if (self.right instanceof AST_String
&& self.right.getValue() == "" && self.right.getValue() == ""
&& self.left.is_string(compressor)) { && self.left.is_string(compressor)) {
return self.left; return self.left.optimize(compressor);
} }
if (self.left instanceof AST_String if (self.left instanceof AST_String
&& self.left.getValue() == "" && self.left.getValue() == ""
&& self.right.is_string(compressor)) { && self.right.is_string(compressor)) {
return self.right; return self.right.optimize(compressor);
} }
if (self.left instanceof AST_Binary if (self.left instanceof AST_Binary
&& self.left.operator == "+" && self.left.operator == "+"
@@ -5659,7 +5701,7 @@ merge(Compressor.prototype, {
&& self.left.left.getValue() == "" && self.left.left.getValue() == ""
&& self.right.is_string(compressor)) { && self.right.is_string(compressor)) {
self.left = self.left.right; self.left = self.left.right;
return self.transform(compressor); return self.optimize(compressor);
} }
} }
if (compressor.option("evaluate")) { if (compressor.option("evaluate")) {
@@ -5918,6 +5960,16 @@ merge(Compressor.prototype, {
&& self.right instanceof AST_Call && self.right instanceof AST_Call
&& self.right.expression instanceof AST_Dot && self.right.expression instanceof AST_Dot
&& indexFns[self.right.expression.property]) { && indexFns[self.right.expression.property]) {
if (compressor.option("booleans")
&& (self.operator == "==" || self.operator == "!=")
&& self.left instanceof AST_Number
&& self.left.getValue() == 0
&& compressor.in_boolean_context()) {
return (self.operator == "==" ? make_node(AST_UnaryPrefix, self, {
operator: "!",
expression: self.right
}) : self.right).optimize(compressor);
}
if (compressor.option("comparisons") && is_indexOf_match_pattern()) { if (compressor.option("comparisons") && is_indexOf_match_pattern()) {
var node = make_node(AST_UnaryPrefix, self, { var node = make_node(AST_UnaryPrefix, self, {
operator: "!", operator: "!",
@@ -6229,7 +6281,7 @@ merge(Compressor.prototype, {
if (parent instanceof AST_Exit) { if (parent instanceof AST_Exit) {
if (in_try(level, parent)) break; if (in_try(level, parent)) break;
if (is_reachable(def.scope, [ def ])) break; if (is_reachable(def.scope, [ def ])) break;
if (self.operator == "=") return self.right; if (self.operator == "=") return self.right.optimize(compressor);
def.fixed = false; def.fixed = false;
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: self.operator.slice(0, -1), operator: self.operator.slice(0, -1),

View File

@@ -820,8 +820,8 @@ unsafe_charAt_noop: {
} }
expect: { expect: {
console.log( console.log(
s.charAt(0), s[0],
"string".charAt(x), "string"[0 | x],
(typeof x)[0] (typeof x)[0]
); );
} }