suppress variable inlining within loops

This commit is contained in:
alexlamsl 2018-01-03 00:25:52 +08:00
parent 1dbe97c655
commit 9480c46ac3
2 changed files with 56 additions and 33 deletions

View File

@ -4031,7 +4031,7 @@ merge(Compressor.prototype, {
if (compressor.option("inline") if (compressor.option("inline")
&& !fn.uses_arguments && !fn.uses_arguments
&& !fn.uses_eval && !fn.uses_eval
&& can_flatten_body() && (value = can_flatten_body(stat))
&& (exp === fn ? !fn.name && (exp === fn ? !fn.name
: compressor.option("unused") : compressor.option("unused")
&& (def = exp.definition()).references.length == 1 && (def = exp.definition()).references.length == 1
@ -4039,8 +4039,7 @@ merge(Compressor.prototype, {
&& fn.is_constant_expression(exp.scope)) && fn.is_constant_expression(exp.scope))
&& !self.pure && !self.pure
&& !fn.contains_this() && !fn.contains_this()
&& can_inject_symbols() && can_inject_symbols()) {
&& (value = return_value(stat))) {
return make_sequence(self, flatten_fn()).optimize(compressor); return make_sequence(self, flatten_fn()).optimize(compressor);
} }
if (compressor.option("side_effects") && all(fn.body, is_empty)) { if (compressor.option("side_effects") && all(fn.body, is_empty)) {
@ -4071,10 +4070,25 @@ merge(Compressor.prototype, {
} }
return self; return self;
function can_flatten_body() { function return_value(stat) {
if (!stat) return make_node(AST_Undefined, self);
if (stat instanceof AST_Return) {
if (!stat.value) return make_node(AST_Undefined, self);
return stat.value.clone(true);
}
if (stat instanceof AST_SimpleStatement) {
return make_node(AST_UnaryPrefix, stat, {
operator: "void",
expression: stat.body.clone(true)
});
}
}
function can_flatten_body(stat) {
var len = fn.body.length; var len = fn.body.length;
if (len == 1) return true; if (compressor.option("inline") < 3) {
if (compressor.option("inline") < 3) return false; return len == 1 && return_value(stat);
}
stat = null; stat = null;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
var line = fn.body[i]; var line = fn.body[i];
@ -4090,7 +4104,7 @@ merge(Compressor.prototype, {
stat = line; stat = line;
} }
} }
return stat; return return_value(stat);
} }
function can_inject_args(catches, defs, safe_to_inject) { function can_inject_args(catches, defs, safe_to_inject) {
@ -4108,21 +4122,18 @@ merge(Compressor.prototype, {
return true; return true;
} }
function can_inject_vars(catches, defs, safe_to_inject) { function can_inject_vars(catches, safe_to_inject) {
var len = fn.body.length; var len = fn.body.length;
if (len == 1) return true;
if (!safe_to_inject) return false;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
var stat = fn.body[i]; var stat = fn.body[i];
if (stat instanceof AST_Definitions) { if (!(stat instanceof AST_Definitions)) continue;
for (var j = stat.definitions.length; --j >= 0;) { if (!safe_to_inject) return false;
var name = stat.definitions[j].name; for (var j = stat.definitions.length; --j >= 0;) {
if (catches[name.name] var name = stat.definitions[j].name;
|| identifier_atom(name.name) if (catches[name.name]
|| scope.var_names()[name.name]) { || identifier_atom(name.name)
return false; || scope.var_names()[name.name]) {
} return false;
if (defs) defs.push(name.definition());
} }
} }
} }
@ -4143,7 +4154,7 @@ merge(Compressor.prototype, {
} while (!(scope instanceof AST_Scope)); } while (!(scope instanceof AST_Scope));
var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars; var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
var inline = compressor.option("inline"); var inline = compressor.option("inline");
if (!can_inject_vars(catches, in_loop, inline >= 3 && safe_to_inject)) return false; if (!can_inject_vars(catches, !in_loop && inline >= 3 && safe_to_inject)) return false;
if (!can_inject_args(catches, in_loop, inline >= 2 && safe_to_inject)) return false; if (!can_inject_args(catches, in_loop, inline >= 2 && safe_to_inject)) return false;
return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop); return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
} }
@ -4193,10 +4204,9 @@ merge(Compressor.prototype, {
stat.definitions.forEach(function(var_def) { stat.definitions.forEach(function(var_def) {
append_var(decls, expressions, var_def.name, var_def.value); append_var(decls, expressions, var_def.name, var_def.value);
}); });
} else {
expressions.push(value.clone(true));
} }
} }
expressions.push(value);
} }
function flatten_fn() { function flatten_fn() {
@ -4212,17 +4222,6 @@ merge(Compressor.prototype, {
} }
return expressions; return expressions;
} }
function return_value(stat) {
if (stat instanceof AST_Return) {
return stat.value;
} else if (stat instanceof AST_SimpleStatement) {
return make_node(AST_UnaryPrefix, stat, {
operator: "void",
expression: stat.body
});
}
}
}); });
OPT(AST_New, function(self, compressor){ OPT(AST_New, function(self, compressor){

View File

@ -1901,3 +1901,27 @@ inline_true: {
"3", "3",
] ]
} }
use_before_init_in_loop: {
options = {
inline: true,
toplevel: true,
}
input: {
var a = "PASS";
for (var b = 2; --b >= 0;) (function() {
var c = function() {
return 1;
}(c && (a = "FAIL"));
})();
console.log(a);
}
expect: {
var a = "PASS";
for (var b = 2; --b >= 0;) (function() {
var c = (c && (a = "FAIL"), 1);
})();
console.log(a);
}
expect_stdout: "PASS"
}