reduce this within functions (#2421)
- only replace same-scope usages - augment `test/ufuzz.js` to test for `this` fixes #2420
This commit is contained in:
@@ -285,7 +285,7 @@ merge(Compressor.prototype, {
|
|||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor) {
|
AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
|
||||||
var reduce_vars = compressor.option("reduce_vars");
|
var reduce_vars = compressor.option("reduce_vars");
|
||||||
var unused = compressor.option("unused");
|
var unused = compressor.option("unused");
|
||||||
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
||||||
@@ -564,7 +564,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_immutable(value) {
|
function is_immutable(value) {
|
||||||
return value && (value.is_constant() || value instanceof AST_Lambda);
|
if (!value) return false;
|
||||||
|
return value.is_constant()
|
||||||
|
|| value instanceof AST_Lambda
|
||||||
|
|| value instanceof AST_This;
|
||||||
}
|
}
|
||||||
|
|
||||||
function read_property(obj, key) {
|
function read_property(obj, key) {
|
||||||
@@ -4211,39 +4214,49 @@ merge(Compressor.prototype, {
|
|||||||
var value = fixed.optimize(compressor);
|
var value = fixed.optimize(compressor);
|
||||||
return value === fixed ? fixed.clone(true) : value;
|
return value === fixed ? fixed.clone(true) : value;
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate") && fixed) {
|
if (fixed && d.should_replace === undefined) {
|
||||||
if (d.should_replace === undefined) {
|
var init;
|
||||||
var init = fixed.evaluate(compressor);
|
if (fixed instanceof AST_This) {
|
||||||
if (init !== fixed && (compressor.option("unsafe_regexp") || !(init instanceof RegExp))) {
|
if (!(d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
init = make_node_from_constant(init, fixed);
|
&& all(d.references, function(ref) {
|
||||||
var value_length = init.optimize(compressor).print_to_string().length;
|
return d.scope === ref.scope;
|
||||||
var fn;
|
})) {
|
||||||
if (has_symbol_ref(fixed)) {
|
init = fixed;
|
||||||
fn = function() {
|
}
|
||||||
var result = init.optimize(compressor);
|
} else {
|
||||||
return result === init ? result.clone(true) : result;
|
var ev = fixed.evaluate(compressor);
|
||||||
};
|
if (ev !== fixed && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))) {
|
||||||
} else {
|
init = make_node_from_constant(ev, fixed);
|
||||||
value_length = Math.min(value_length, fixed.print_to_string().length);
|
|
||||||
fn = function() {
|
|
||||||
var result = best_of_expression(init.optimize(compressor), fixed);
|
|
||||||
return result === init || result === fixed ? result.clone(true) : result;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var name_length = d.name.length;
|
|
||||||
var overhead = 0;
|
|
||||||
if (compressor.option("unused") && !compressor.exposed(d)) {
|
|
||||||
overhead = (name_length + 2 + value_length) / d.references.length;
|
|
||||||
}
|
|
||||||
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
|
||||||
} else {
|
|
||||||
d.should_replace = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (d.should_replace) {
|
if (init) {
|
||||||
return d.should_replace();
|
var value_length = init.optimize(compressor).print_to_string().length;
|
||||||
|
var fn;
|
||||||
|
if (has_symbol_ref(fixed)) {
|
||||||
|
fn = function() {
|
||||||
|
var result = init.optimize(compressor);
|
||||||
|
return result === init ? result.clone(true) : result;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
value_length = Math.min(value_length, fixed.print_to_string().length);
|
||||||
|
fn = function() {
|
||||||
|
var result = best_of_expression(init.optimize(compressor), fixed);
|
||||||
|
return result === init || result === fixed ? result.clone(true) : result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var name_length = d.name.length;
|
||||||
|
var overhead = 0;
|
||||||
|
if (compressor.option("unused") && !compressor.exposed(d)) {
|
||||||
|
overhead = (name_length + 2 + value_length) / d.references.length;
|
||||||
|
}
|
||||||
|
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
||||||
|
} else {
|
||||||
|
d.should_replace = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (d.should_replace) {
|
||||||
|
return d.should_replace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
|
|||||||
@@ -3295,3 +3295,87 @@ escaped_prop: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "2"
|
expect_stdout: "2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2420_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function run() {
|
||||||
|
var self = this;
|
||||||
|
if (self.count++)
|
||||||
|
self.foo();
|
||||||
|
else
|
||||||
|
self.bar();
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
count: 0,
|
||||||
|
foo: function() { console.log("foo"); },
|
||||||
|
bar: function() { console.log("bar"); },
|
||||||
|
};
|
||||||
|
run.call(o);
|
||||||
|
run.call(o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function run() {
|
||||||
|
if (this.count++)
|
||||||
|
this.foo();
|
||||||
|
else
|
||||||
|
this.bar();
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
count: 0,
|
||||||
|
foo: function() { console.log("foo"); },
|
||||||
|
bar: function() { console.log("bar"); },
|
||||||
|
};
|
||||||
|
run.call(o);
|
||||||
|
run.call(o);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"bar",
|
||||||
|
"foo",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2420_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var that = this;
|
||||||
|
if (that.bar)
|
||||||
|
that.foo();
|
||||||
|
else
|
||||||
|
!function(that, self) {
|
||||||
|
console.log(this === that, self === this, that === self);
|
||||||
|
}(that, this);
|
||||||
|
}
|
||||||
|
f.call({
|
||||||
|
bar: 1,
|
||||||
|
foo: function() { console.log("foo", this.bar); },
|
||||||
|
});
|
||||||
|
f.call({});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
if (this.bar)
|
||||||
|
this.foo();
|
||||||
|
else
|
||||||
|
!function(that, self) {
|
||||||
|
console.log(this === that, self === this, that === self);
|
||||||
|
}(this, this);
|
||||||
|
}
|
||||||
|
f.call({
|
||||||
|
bar: 1,
|
||||||
|
foo: function() { console.log("foo", this.bar); },
|
||||||
|
});
|
||||||
|
f.call({});
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo 1",
|
||||||
|
"false false true",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ var VALUES = [
|
|||||||
'"object"',
|
'"object"',
|
||||||
'"number"',
|
'"number"',
|
||||||
'"function"',
|
'"function"',
|
||||||
|
'this',
|
||||||
];
|
];
|
||||||
|
|
||||||
var BINARY_OPS_NO_COMMA = [
|
var BINARY_OPS_NO_COMMA = [
|
||||||
|
|||||||
Reference in New Issue
Block a user