compress arguments[index] (#2967)

- always replace with existing parameter
- only introduce new parameter if `keep_fargs` is disabled
This commit is contained in:
Alex Lam S.L
2018-03-02 11:22:09 +08:00
committed by GitHub
parent 38f2b4579f
commit a75a046abb
4 changed files with 155 additions and 7 deletions

View File

@@ -598,6 +598,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
## Compress options
- `arguments` (default: `true`) -- replace `arguments[index]` with function
parameter name whenever possible.
- `booleans` (default: `true`) -- various optimizations for boolean context,
for example `!!a ? b : c → a ? b : c`

View File

@@ -48,6 +48,7 @@ function Compressor(options, false_by_default) {
return new Compressor(options, false_by_default);
TreeTransformer.call(this, this.before, this.after);
this.options = defaults(options, {
arguments : !false_by_default,
booleans : !false_by_default,
collapse_vars : !false_by_default,
comparisons : !false_by_default,
@@ -3551,7 +3552,7 @@ merge(Compressor.prototype, {
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_$]|[^a-z0-9_$])/ig, "_");
var name = prefix;
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
var_names[name] = true;
@@ -5954,6 +5955,31 @@ merge(Compressor.prototype, {
});
}
}
var fn;
if (compressor.option("arguments")
&& expr instanceof AST_SymbolRef
&& expr.name == "arguments"
&& expr.definition().orig.length == 1
&& (fn = expr.scope) instanceof AST_Lambda
&& prop instanceof AST_Number) {
var index = prop.getValue();
var argname = fn.argnames[index];
if (!argname && !compressor.option("keep_fargs")) {
while (index >= fn.argnames.length) {
argname = make_node(AST_SymbolFunarg, fn, {
name: fn.make_var_name("argument_" + fn.argnames.length),
scope: fn
});
fn.argnames.push(argname);
fn.enclosed.push(fn.def_variable(argname));
}
}
if (argname) {
var sym = make_node(AST_SymbolRef, self, argname);
sym.reference({});
return sym;
}
}
var ev = self.evaluate(compressor);
if (ev !== self) {
ev = make_node_from_constant(ev, self).optimize(compressor);

119
test/compress/arguments.js Normal file
View File

@@ -0,0 +1,119 @@
replace_index: {
options = {
arguments: true,
evaluate: true,
properties: true,
}
input: {
console.log(arguments && arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
console.log(arguments && arguments[0]);
(function() {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function(a, b) {
console.log(b, b, arguments.foo);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
}
expect_stdout: [
"undefined",
"42 42 undefined",
"42 42 undefined",
"a a undefined",
"42 42 undefined",
]
}
replace_index_keep_fargs: {
options = {
arguments: true,
evaluate: true,
keep_fargs: false,
properties: true,
}
input: {
console.log(arguments && arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
console.log(arguments && arguments[0]);
(function(argument_0, argument_1) {
console.log(argument_1, argument_1, arguments.foo);
})("bar", 42);
(function(a, b) {
console.log(b, b, arguments.foo);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
}
expect_stdout: [
"undefined",
"42 42 undefined",
"42 42 undefined",
"a a undefined",
"42 42 undefined",
]
}
modified: {
options = {
arguments: true,
}
input: {
(function(a, b) {
var c = arguments[0];
var d = arguments[1];
a = "foo";
b++;
console.log(a, b, c, d, arguments[0], arguments[1]);
})("bar", 42);
}
expect: {
(function(a, b) {
var c = a;
var d = b;
a = "foo";
b++;
console.log(a, b, c, d, a, b);
})("bar", 42);
}
expect_stdout: "foo 43 bar 42 foo 43"
}

View File

@@ -239,14 +239,14 @@ name_collision_2: {
input: {
var o = {
p: 1,
0: function(x) {
"+": function(x) {
return x;
},
1: function(x) {
"-": function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o[0](4), o[1](5), o__$0, o__$1);
console.log(o.p === o.p, o["+"](4), o["-"](5), o__$0, o__$1);
}
expect: {
var o_p = 1,
@@ -273,14 +273,14 @@ name_collision_3: {
input: {
var o = {
p: 1,
0: function(x) {
"+": function(x) {
return x;
},
1: function(x) {
"-": function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o[0](4), o[1](5));
console.log(o.p === o.p, o["+"](4), o["-"](5));
}
expect: {
var o_p = 1,