diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2019-11-16 06:10:47 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-16 06:10:47 +0800 |
commit | 552be61c4d6756fb31675fee0b1284e23d5d8721 (patch) | |
tree | 4e7cf68f49301fe0e4cf7707c7c78ef68bb553cf | |
parent | dcfc4aca5b97419150e742f2f94c40cdd8497189 (diff) | |
download | tracifyjs-552be61c4d6756fb31675fee0b1284e23d5d8721.tar.gz tracifyjs-552be61c4d6756fb31675fee0b1284e23d5d8721.zip |
introduce eager evaluation (#3587)
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | lib/compress.js | 69 | ||||
-rw-r--r-- | test/compress/evaluate.js | 136 | ||||
-rw-r--r-- | test/compress/issue-1609.js | 27 |
4 files changed, 192 insertions, 45 deletions
@@ -631,7 +631,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u - `drop_debugger` (default: `true`) -- remove `debugger;` statements -- `evaluate` (default: `true`) -- attempt to evaluate constant expressions +- `evaluate` (default: `true`) -- Evaluate expression for shorter constant + representation. Pass `"eager"` to always replace function calls whenever + possible, or a positive integer to specify an upper bound for each individual + evaluation in number of characters. - `expression` (default: `false`) -- Pass `true` to preserve completion values from terminal statements without `return`, e.g. in bookmarklets. diff --git a/lib/compress.js b/lib/compress.js index 9d844b81..f82a165e 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -96,6 +96,8 @@ function Compressor(options, false_by_default) { unsafe_undefined: false, unused : !false_by_default, }, true); + var evaluate = this.options["evaluate"]; + this.eval_threshold = /eager/.test(evaluate) ? 1 / 0 : +evaluate; var global_defs = this.options["global_defs"]; if (typeof global_defs == "object") for (var key in global_defs) { if (/^@/.test(key) && HOP(global_defs, key)) { @@ -2676,22 +2678,21 @@ merge(Compressor.prototype, { node.DEFMETHOD("_find_defs", func); }); - function best_of_expression(ast1, ast2) { - return ast1.print_to_string().length > - ast2.print_to_string().length - ? ast2 : ast1; + function best_of_expression(ast1, ast2, threshold) { + var delta = ast2.print_to_string().length - ast1.print_to_string().length; + return delta < (threshold || 0) ? ast2 : ast1; } - function best_of_statement(ast1, ast2) { + function best_of_statement(ast1, ast2, threshold) { return best_of_expression(make_node(AST_SimpleStatement, ast1, { body: ast1 }), make_node(AST_SimpleStatement, ast2, { body: ast2 - })).body; + }), threshold).body; } - function best_of(compressor, ast1, ast2) { - return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2); + function best_of(compressor, ast1, ast2, threshold) { + return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2, threshold); } function convert_to_predicate(obj) { @@ -2700,6 +2701,13 @@ merge(Compressor.prototype, { }); } + function try_evaluate(compressor, node) { + var ev = node.evaluate(compressor); + if (ev === node) return node; + ev = make_node_from_constant(ev, node).optimize(compressor); + return best_of(compressor, node, ev, compressor.eval_threshold); + } + var object_fns = [ "constructor", "toString", @@ -5366,12 +5374,7 @@ merge(Compressor.prototype, { && is_iife_call(self)) { return self.negate(compressor, true); } - var ev = self.evaluate(compressor); - if (ev !== self) { - ev = make_node_from_constant(ev, self).optimize(compressor); - return best_of(compressor, ev, self); - } - return self; + return try_evaluate(compressor, self); function return_value(stat) { if (!stat) return make_node(AST_Undefined, self); @@ -5702,15 +5705,8 @@ merge(Compressor.prototype, { }); } // avoids infinite recursion of numerals - if (self.operator != "-" - || !(e instanceof AST_Number || e instanceof AST_Infinity)) { - var ev = self.evaluate(compressor); - if (ev !== self) { - ev = make_node_from_constant(ev, self).optimize(compressor); - return best_of(compressor, ev, self); - } - } - return self; + return self.operator == "-" && (e instanceof AST_Number || e instanceof AST_Infinity) + ? self : try_evaluate(compressor, self); }); AST_Binary.DEFMETHOD("lift_sequences", function(compressor) { @@ -6274,12 +6270,7 @@ merge(Compressor.prototype, { self.right = self.right.right; return self.transform(compressor); } - var ev = self.evaluate(compressor); - if (ev !== self) { - ev = make_node_from_constant(ev, self).optimize(compressor); - return best_of(compressor, ev, self); - } - return self; + return try_evaluate(compressor, self); function align(ref, op) { switch (ref) { @@ -6448,11 +6439,11 @@ merge(Compressor.prototype, { }; } var name_length = def.name.length; - var overhead = 0; if (compressor.option("unused") && !compressor.exposed(def)) { - overhead = (name_length + 2 + value_length) / (def.references.length - def.assignments); + name_length += (name_length + 2 + value_length) / (def.references.length - def.assignments); } - def.should_replace = value_length <= name_length + overhead ? fn : false; + var delta = value_length - Math.floor(name_length); + def.should_replace = delta < compressor.eval_threshold ? fn : false; } else { def.should_replace = false; } @@ -7046,12 +7037,7 @@ merge(Compressor.prototype, { }); } } - var ev = self.evaluate(compressor); - if (ev !== self) { - ev = make_node_from_constant(ev, self).optimize(compressor); - return best_of(compressor, ev, self); - } - return self; + return try_evaluate(compressor, self); function find_lambda() { var i = 0, p; @@ -7152,12 +7138,7 @@ merge(Compressor.prototype, { } var sub = self.flatten_object(self.property, compressor); if (sub) return sub.optimize(compressor); - var ev = self.evaluate(compressor); - if (ev !== self) { - ev = make_node_from_constant(ev, self).optimize(compressor); - return best_of(compressor, ev, self); - } - return self; + return try_evaluate(compressor, self); }); OPT(AST_Object, function(self, compressor) { diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index ea707e63..94258049 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -1921,3 +1921,139 @@ conditional_function: { } expect_stdout: "42 42" } + +best_of_evaluate: { + options = { + evaluate: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function d(x, y) { + return x / y; + } + console.log(0 / 3, 1 / 64, 4 / 7, 7 / 7); + console.log(d(0, 3), d(1, 64), d(4, 7), d(7, 7)); + } + expect: { + function d(x, y) { + return x / y; + } + console.log(0, 1 / 64, 4 / 7, 1); + console.log(0, .015625, d(4, 7), 1); + } + expect_stdout: [ + "0 0.015625 0.5714285714285714 1", + "0 0.015625 0.5714285714285714 1", + ] +} + +eager_evaluate: { + options = { + evaluate: "eager", + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function d(x, y) { + return x / y; + } + console.log(0 / 3, 1 / 64, 4 / 7, 7 / 7); + console.log(d(0, 3), d(1, 64), d(4, 7), d(7, 7)); + } + expect: { + console.log(0, .015625, .5714285714285714, 1); + console.log(0, .015625, .5714285714285714, 1); + } + expect_stdout: [ + "0 0.015625 0.5714285714285714 1", + "0 0.015625 0.5714285714285714 1", + ] +} + +threshold_evaluate_default: { + options = { + evaluate: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function b(x) { + return x + x + x; + } + console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK")))); + } + expect: { + function b(x) { + return x + x + x; + } + console.log("111", 6, b(b(b("ABCDEFGHIJK")))); + } + expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK" +} + +threshold_evaluate_30: { + options = { + evaluate: 30, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function b(x) { + return x + x + x; + } + console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK")))); + } + expect: { + function b(x) { + return x + x + x; + } + console.log("111", 6, b(b("ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"))); + } + expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK" +} + +threshold_evaluate_100: { + options = { + evaluate: 100, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function b(x) { + return x + x + x; + } + console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK")))); + } + expect: { + function b(x) { + return x + x + x; + } + console.log("111", 6, b("ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK")); + } + expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK" +} + +threshold_evaluate_999: { + options = { + evaluate: 999, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function b(x) { + return x + x + x; + } + console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK")))); + } + expect: { + console.log("111", 6, "ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"); + } + expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK" +} diff --git a/test/compress/issue-1609.js b/test/compress/issue-1609.js index d8e82263..17fbb0e7 100644 --- a/test/compress/issue-1609.js +++ b/test/compress/issue-1609.js @@ -52,3 +52,30 @@ chained_evaluation_2: { })(); } } + +chained_evaluation_3: { + options = { + collapse_vars: true, + evaluate: 10, + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + (function() { + var a = "long piece of string"; + (function() { + var b = a, c; + c = f(b); + c.bar = b; + })(); + })(); + } + expect: { + (function() { + (function() { + f("long piece of string").bar = "long piece of string"; + })(); + })(); + } +} |