improve unused on built-in functions (#2817)

This commit is contained in:
Alex Lam S.L
2018-01-19 20:41:57 +08:00
committed by GitHub
parent e21bab7ce6
commit 3e7873217c
4 changed files with 205 additions and 87 deletions

View File

@@ -2113,6 +2113,95 @@ merge(Compressor.prototype, {
return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2);
}
function convert_to_predicate(obj) {
for (var key in obj) {
obj[key] = makePredicate(obj[key]);
}
}
var object_fns = [
"constructor",
"toString",
"valueOf",
];
var native_fns = {
Array: [
"indexOf",
"join",
"lastIndexOf",
"slice",
].concat(object_fns),
Boolean: object_fns,
Number: [
"toExponential",
"toFixed",
"toPrecision",
].concat(object_fns),
Object: object_fns,
RegExp: [
"test",
].concat(object_fns),
String: [
"charAt",
"charCodeAt",
"concat",
"indexOf",
"italics",
"lastIndexOf",
"match",
"replace",
"search",
"slice",
"split",
"substr",
"substring",
"trim",
].concat(object_fns),
};
convert_to_predicate(native_fns);
var static_fns = {
Array: [
"isArray",
],
Math: [
"abs",
"acos",
"asin",
"atan",
"ceil",
"cos",
"exp",
"floor",
"log",
"round",
"sin",
"sqrt",
"tan",
"atan2",
"pow",
"max",
"min",
],
Number: [
"isFinite",
"isNaN",
],
Object: [
"create",
"getOwnPropertyDescriptor",
"getOwnPropertyNames",
"getPrototypeOf",
"isExtensible",
"isFrozen",
"isSealed",
"keys",
],
String: [
"fromCharCode",
],
};
convert_to_predicate(static_fns);
// methods to evaluate a constant expression
(function(def){
// If the node has been successfully reduced to a constant,
@@ -2278,13 +2367,9 @@ merge(Compressor.prototype, {
Array: Array,
Math: Math,
Number: Number,
Object: Object,
String: String,
};
function convert_to_predicate(obj) {
for (var key in obj) {
obj[key] = makePredicate(obj[key]);
}
}
var static_values = {
Math: [
"E",
@@ -2325,77 +2410,6 @@ merge(Compressor.prototype, {
}
return this;
});
var object_fns = [
"constructor",
"toString",
"valueOf",
];
var native_fns = {
Array: [
"indexOf",
"join",
"lastIndexOf",
"slice",
].concat(object_fns),
Boolean: object_fns,
Number: [
"toExponential",
"toFixed",
"toPrecision",
].concat(object_fns),
RegExp: [
"test",
].concat(object_fns),
String: [
"charAt",
"charCodeAt",
"concat",
"indexOf",
"italics",
"lastIndexOf",
"match",
"replace",
"search",
"slice",
"split",
"substr",
"substring",
"trim",
].concat(object_fns),
};
convert_to_predicate(native_fns);
var static_fns = {
Array: [
"isArray",
],
Math: [
"abs",
"acos",
"asin",
"atan",
"ceil",
"cos",
"exp",
"floor",
"log",
"round",
"sin",
"sqrt",
"tan",
"atan2",
"pow",
"max",
"min"
],
Number: [
"isFinite",
"isNaN",
],
String: [
"fromCharCode",
],
};
convert_to_predicate(static_fns);
def(AST_Call, function(compressor, depth) {
var exp = this.expression;
if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
@@ -2420,7 +2434,16 @@ merge(Compressor.prototype, {
if (arg === value) return this;
args.push(value);
}
return val[key].apply(val, args);
try {
return val[key].apply(val, args);
} catch (ex) {
compressor.warn("Error evaluating {code} [{file}:{line},{col}]", {
code: this.print_to_string(),
file: this.start.file,
line: this.start.line,
col: this.start.col
});
}
}
return this;
});
@@ -2511,9 +2534,34 @@ merge(Compressor.prototype, {
if (compressor.option("unsafe")) {
var expr = this.expression;
if (is_undeclared_ref(expr) && global_pure_fns(expr.name)) return true;
if (expr instanceof AST_Dot
&& is_undeclared_ref(expr.expression)
&& (static_fns[expr.expression.name] || return_false)(expr.property)) {
return true;
}
}
return this.pure || !compressor.pure_funcs(this);
});
AST_Node.DEFMETHOD("is_call_pure", return_false);
AST_Dot.DEFMETHOD("is_call_pure", function(compressor) {
if (!compressor.option("unsafe")) return;
var expr = this.expression;
var fns = return_false;
if (expr instanceof AST_Array) {
fns = native_fns.Array;
} else if (expr.is_boolean()) {
fns = native_fns.Boolean;
} else if (expr.is_number(compressor)) {
fns = native_fns.Number;
} else if (expr instanceof AST_RegExp) {
fns = native_fns.RegExp;
} else if (expr.is_string(compressor)) {
fns = native_fns.String;
} else if (!this.may_throw_on_access(compressor)) {
fns = native_fns.Object;
}
return fns(this.property);
});
// determine if expression has side effects
(function(def){
@@ -2534,8 +2582,12 @@ merge(Compressor.prototype, {
return any(this.body, compressor);
});
def(AST_Call, function(compressor){
return !this.is_expr_pure(compressor)
|| any(this.args, compressor);
if (!this.is_expr_pure(compressor)
&& (!this.expression.is_call_pure(compressor)
|| this.expression.has_side_effects(compressor))) {
return true;
}
return any(this.args, compressor);
});
def(AST_Switch, function(compressor){
return this.expression.has_side_effects(compressor)
@@ -3365,6 +3417,12 @@ merge(Compressor.prototype, {
def(AST_This, return_null);
def(AST_Call, function(compressor, first_in_statement){
if (!this.is_expr_pure(compressor)) {
if (this.expression.is_call_pure(compressor)) {
var exprs = this.args.slice();
exprs.unshift(this.expression.expression);
exprs = trim(exprs, compressor, first_in_statement);
return exprs && make_sequence(this, exprs);
}
if (this.expression instanceof AST_Function
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
var node = this.clone();