handle inline of function arguments (#2590)

fixes #2476
This commit is contained in:
Alex Lam S.L
2017-12-15 13:28:30 +08:00
committed by GitHub
parent 90313875f7
commit 8f681b1d17
6 changed files with 137 additions and 65 deletions

View File

@@ -2997,10 +2997,10 @@ merge(Compressor.prototype, {
return self; return self;
}); });
AST_Scope.DEFMETHOD("make_var_name", function(prefix) { AST_Scope.DEFMETHOD("var_names", function() {
var var_names = this.var_names; var var_names = this._var_names;
if (!var_names) { if (!var_names) {
this.var_names = var_names = Object.create(null); this._var_names = var_names = Object.create(null);
this.enclosed.forEach(function(def) { this.enclosed.forEach(function(def) {
var_names[def.name] = true; var_names[def.name] = true;
}); });
@@ -3008,6 +3008,11 @@ merge(Compressor.prototype, {
var_names[name] = true; var_names[name] = true;
}); });
} }
return var_names;
});
AST_Scope.DEFMETHOD("make_var_name", function(prefix) {
var var_names = this.var_names();
prefix = prefix.replace(/[^a-z_$]+/ig, "_"); prefix = prefix.replace(/[^a-z_$]+/ig, "_");
var name = prefix; var name = prefix;
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i; for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
@@ -3862,7 +3867,7 @@ merge(Compressor.prototype, {
} }
} }
if (fn instanceof AST_Function) { if (fn instanceof AST_Function) {
var def; var def, scope, value;
if (compressor.option("inline") if (compressor.option("inline")
&& !fn.uses_arguments && !fn.uses_arguments
&& !fn.uses_eval && !fn.uses_eval
@@ -3871,24 +3876,13 @@ merge(Compressor.prototype, {
: compressor.option("unused") : compressor.option("unused")
&& (def = exp.definition()).references.length == 1 && (def = exp.definition()).references.length == 1
&& !recursive_ref(compressor, def)) && !recursive_ref(compressor, def))
&& !self.has_pure_annotation(compressor)
&& !fn.contains_this() && !fn.contains_this()
&& all(fn.argnames, function(arg) { && (scope = can_flatten_args(fn))
return arg.__unused; && (value = flatten_body(stat))) {
}) var expressions = flatten_args(fn, scope);
&& !self.has_pure_annotation(compressor)) { expressions.push(value);
var value; return make_sequence(self, expressions).optimize(compressor);
if (stat instanceof AST_Return) {
value = stat.value;
} else if (stat instanceof AST_SimpleStatement) {
value = make_node(AST_UnaryPrefix, stat, {
operator: "void",
expression: stat.body
});
}
if (value) {
var args = self.args.concat(value);
return make_sequence(self, args).optimize(compressor);
}
} }
if (compressor.option("side_effects") && all(fn.body, is_empty)) { if (compressor.option("side_effects") && all(fn.body, is_empty)) {
var args = self.args.concat(make_node(AST_Undefined, self)); var args = self.args.concat(make_node(AST_Undefined, self));
@@ -3917,6 +3911,62 @@ merge(Compressor.prototype, {
return best_of(compressor, ev, self); return best_of(compressor, ev, self);
} }
return self; return self;
function can_flatten_args(fn) {
var scope = compressor.find_parent(AST_Scope);
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
return all(fn.argnames, function(arg) {
return arg.__unused || safe_to_inject && !scope.var_names()[arg.name];
}) && scope;
}
function flatten_args(fn, scope) {
var decls = [];
var expressions = [];
for (var len = fn.argnames.length, i = len; --i >= 0;) {
var name = fn.argnames[i];
var value = self.args[i];
if (name.__unused) {
if (value || expressions.length) {
expressions.unshift(value || make_node(AST_Undefined, self));
}
} else {
decls.unshift(make_node(AST_VarDef, name, {
name: name,
value: null
}));
var sym = make_node(AST_SymbolRef, name, name);
name.definition().references.push(sym);
expressions.unshift(make_node(AST_Assign, self, {
operator: "=",
left: sym,
right: value || make_node(AST_Undefined, self)
}));
}
}
for (i = len, len = self.args.length; i < len; i++) {
expressions.push(self.args[i]);
}
if (decls.length) {
for (i = 0; compressor.parent(i) !== scope;) i++;
i = scope.body.indexOf(compressor.parent(i - 1)) + 1;
scope.body.splice(i, 0, make_node(AST_Var, fn, {
definitions: decls
}));
}
return expressions;
}
function flatten_body(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

@@ -3317,15 +3317,14 @@ issue_2436_4: {
}(o)); }(o));
} }
expect: { expect: {
console.log(function(c) { console.log({
return { x: (c = {
x: c.a,
y: c.b,
};
}({
a: 1, a: 1,
b: 2, b: 2,
})); }).a,
y: c.b,
});
var c;
} }
expect_stdout: true expect_stdout: true
} }
@@ -3448,12 +3447,11 @@ issue_2436_8: {
}(o)); }(o));
} }
expect: { expect: {
console.log(function(c) { console.log({
return { x: (c = o).a,
x: c.a,
y: c.b, y: c.b,
}; });
}(o)); var c;
} }
expect_stdout: true expect_stdout: true
} }
@@ -3478,12 +3476,11 @@ issue_2436_9: {
} }
expect: { expect: {
var o = console; var o = console;
console.log(function(c) { console.log({
return { x: (c = o).a,
x: c.a,
y: c.b, y: c.b,
}; });
}(o)); var c;
} }
expect_stdout: true expect_stdout: true
} }
@@ -3523,13 +3520,12 @@ issue_2436_10: {
o = { b: 3 }; o = { b: 3 };
return n; return n;
} }
console.log(function(c) { console.log((c = o, [
return [
c.a, c.a,
f(c.b), f(c.b),
c.b, c.b,
]; ]).join(" "));
}(o).join(" ")); var c;
} }
expect_stdout: "1 2 2" expect_stdout: "1 2 2"
} }

View File

@@ -578,11 +578,10 @@ issue_2531_1: {
} }
expect: { expect: {
function outer() { function outer() {
return function(value) { return value = "Hello", function() {
return function() {
return value; return value;
}; };
}("Hello"); var value;
} }
console.log("Greeting:", outer()()); console.log("Greeting:", outer()());
} }
@@ -593,9 +592,10 @@ issue_2531_2: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 3,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true,
unused: true, unused: true,
} }
input: { input: {
@@ -627,9 +627,10 @@ issue_2531_3: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 3,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@@ -747,3 +748,27 @@ inline_loop_4: {
}; };
} }
} }
issue_2476: {
options = {
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function foo(x, y, z) {
return x < y ? x * y + z : x * z - y;
}
for (var sum = 0, i = 0; i < 10; i++)
sum += foo(i, i + 1, 3 * i);
console.log(sum);
}
expect: {
for (var sum = 0, i = 0; i < 10; i++)
sum += (x = i, y = i + 1, z = 3 * i, x < y ? x * y + z : x * z - y);
var x, y, z;
console.log(sum);
}
expect_stdout: "465"
}

View File

@@ -55,9 +55,8 @@ issue_2377_2: {
console.log(obj.foo, obj.cube(3)); console.log(obj.foo, obj.cube(3));
} }
expect: { expect: {
console.log(1, function(x) { console.log(1, (x = 3, x * x * x));
return x * x * x; var x;
}(3));
} }
expect_stdout: "1 27" expect_stdout: "1 27"
} }
@@ -67,9 +66,10 @@ issue_2377_3: {
evaluate: true, evaluate: true,
inline: true, inline: true,
hoist_props: true, hoist_props: true,
passes: 3, passes: 4,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }

View File

@@ -1396,7 +1396,7 @@ defun_inline_3: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 3,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
@@ -2250,12 +2250,11 @@ redefine_farg_2: {
console.log(f([]), g([]), h([])); console.log(f([]), g([]), h([]));
} }
expect: { expect: {
console.log(function(a) { console.log((a = [], typeof a), "number",function(a, b) {
return typeof a;
}([]), "number",function(a, b) {
a = b; a = b;
return typeof a; return typeof a;
}([])); }([]));
var a;
} }
expect_stdout: "object number undefined" expect_stdout: "object number undefined"
} }
@@ -2266,7 +2265,7 @@ redefine_farg_3: {
evaluate: true, evaluate: true,
inline: true, inline: true,
keep_fargs: false, keep_fargs: false,
passes: 2, passes: 3,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
@@ -3107,6 +3106,7 @@ obj_var_2: {
obj_arg_1: { obj_arg_1: {
options = { options = {
collapse_vars: true,
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 2,
@@ -3138,9 +3138,10 @@ obj_arg_1: {
obj_arg_2: { obj_arg_2: {
options = { options = {
collapse_vars: true,
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 3,
properties: true, properties: true,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,

View File

@@ -26,7 +26,7 @@ describe("bin/uglifyjs with input file globs", function() {
}); });
}); });
it("bin/uglifyjs with multiple input file globs.", function(done) { it("bin/uglifyjs with multiple input file globs.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=2'; var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=3';
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;