From: Alex Lam S.L Date: Thu, 6 Jul 2017 21:35:32 +0000 (+0800) Subject: inlining of static methods & constants (#2211) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=4f70d2e28c9ffd6404756ed3ebf08a448aef5257;p=UglifyJS.git inlining of static methods & constants (#2211) - guard by `unsafe` - support `Array`, `Math`, `Number`, `Object` & `String` fixes #2207 --- diff --git a/lib/compress.js b/lib/compress.js index 76eb6918..e6349242 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1718,6 +1718,40 @@ merge(Compressor.prototype, { this._eval = fixed._eval; return value; }); + var global_objs = { + Array: Array, + Boolean: Boolean, + Math: Math, + Number: Number, + RegExp: RegExp, + Object: Object, + String: String, + }; + function convert_to_predicate(obj) { + for (var key in obj) { + obj[key] = makePredicate(obj[key]); + } + } + var static_values = { + Math: [ + "E", + "LN10", + "LN2", + "LOG2E", + "LOG10E", + "PI", + "SQRT1_2", + "SQRT2", + ], + Number: [ + "MAX_VALUE", + "MIN_VALUE", + "NaN", + "NEGATIVE_INFINITY", + "POSITIVE_INFINITY", + ], + }; + convert_to_predicate(static_values); def(AST_PropAccess, function(compressor){ if (compressor.option("unsafe")) { var key = this.property; @@ -1725,11 +1759,16 @@ merge(Compressor.prototype, { key = ev(key, compressor); if (key === this.property) return this; } - var val = ev(this.expression, compressor); - if (val === this.expression) return this; - if (val && HOP(val, key)) { - return val[key]; + var exp = this.expression; + var val; + if (exp instanceof AST_SymbolRef && exp.undeclared()) { + if (!(static_values[exp.name] || return_false)(key)) return this; + val = global_objs[exp.name]; + } else { + val = ev(exp, compressor); + if (!val || val === exp || !HOP(val, key)) return this; } + return val[key]; } return this; }); @@ -1739,22 +1778,22 @@ merge(Compressor.prototype, { "valueOf", ]; var native_fns = { - Array: makePredicate([ + Array: [ "indexOf", "join", "lastIndexOf", "slice", - ].concat(object_fns)), - Boolean: makePredicate(object_fns), - Number: makePredicate([ + ].concat(object_fns), + Boolean: object_fns, + Number: [ "toExponential", "toFixed", "toPrecision", - ].concat(object_fns)), - RegExp: makePredicate([ + ].concat(object_fns), + RegExp: [ "test", - ].concat(object_fns)), - String: makePredicate([ + ].concat(object_fns), + String: [ "charAt", "charCodeAt", "concat", @@ -1769,8 +1808,45 @@ merge(Compressor.prototype, { "substr", "substring", "trim", - ].concat(object_fns)), + ].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: [ + "keys", + "getOwnPropertyNames", + ], + String: [ + "fromCharCode", + ], }; + convert_to_predicate(static_fns); def(AST_Call, function(compressor){ var exp = this.expression; if (compressor.option("unsafe") && exp instanceof AST_PropAccess) { @@ -1779,18 +1855,23 @@ merge(Compressor.prototype, { key = ev(key, compressor); if (key === exp.property) return this; } - var val = ev(exp.expression, compressor); - if (val === exp.expression) return this; - if ((val && native_fns[val.constructor.name] || return_false)(key)) { - var args = []; - for (var i = 0, len = this.args.length; i < len; i++) { - var arg = this.args[i]; - var value = ev(arg, compressor); - if (arg === value) return this; - args.push(value); - } - return val[key].apply(val, args); + var val; + var e = exp.expression; + if (e instanceof AST_SymbolRef && e.undeclared()) { + if (!(static_fns[e.name] || return_false)(key)) return this; + val = global_objs[e.name]; + } else { + val = ev(e, compressor); + if (val === e || !(val && native_fns[val.constructor.name] || return_false)(key)) return this; + } + var args = []; + for (var i = 0, len = this.args.length; i < len; i++) { + var arg = this.args[i]; + var value = ev(arg, compressor); + if (arg === value) return this; + args.push(value); } + return val[key].apply(val, args); } return this; }); diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index 69ea8c19..38e9cdcb 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -1085,3 +1085,75 @@ string_charCodeAt: { } expect_stdout: "NaN" } + +issue_2207_1: { + options = { + evaluate: true, + unsafe: true, + } + input: { + console.log(String.fromCharCode(65)); + console.log(Math.max(3, 6, 2, 7, 3, 4)); + console.log(Math.cos(1.2345)); + console.log(Math.cos(1.2345) - Math.sin(4.321)); + console.log(Math.pow(Math.PI, Math.E - Math.LN10)); + } + expect: { + console.log("A"); + console.log(7); + console.log(Math.cos(1.2345)); + console.log(1.2543732512566947); + console.log(1.6093984514472044); + } + expect_stdout: true +} + +issue_2207_2: { + options = { + evaluate: true, + unsafe: true, + } + input: { + console.log(Math.E); + console.log(Math.LN10); + console.log(Math.LN2); + console.log(Math.LOG2E); + console.log(Math.LOG10E); + console.log(Math.PI); + console.log(Math.SQRT1_2); + console.log(Math.SQRT2); + } + expect: { + console.log(Math.E); + console.log(Math.LN10); + console.log(Math.LN2); + console.log(Math.LOG2E); + console.log(Math.LOG10E); + console.log(Math.PI); + console.log(Math.SQRT1_2); + console.log(Math.SQRT2); + } + expect_stdout: true +} + +issue_2207_3: { + options = { + evaluate: true, + unsafe: true, + } + input: { + console.log(Number.MAX_VALUE); + console.log(Number.MIN_VALUE); + console.log(Number.NaN); + console.log(Number.NEGATIVE_INFINITY); + console.log(Number.POSITIVE_INFINITY); + } + expect: { + console.log(Number.MAX_VALUE); + console.log(5e-324); + console.log(NaN); + console.log(-1/0); + console.log(1/0); + } + expect_stdout: true +}