allow symbol replacement on multiple occurrences (#2472)
- all-or-nothing replacement - avoid unmangleable names fixes #2436
This commit is contained in:
@@ -796,8 +796,8 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
function drop_decl(def) {
|
||||
def._eliminiated = (def._eliminiated || 0) + 1;
|
||||
if (def.orig.length == def._eliminiated) {
|
||||
def.eliminated++;
|
||||
if (def.orig.length == def.eliminated) {
|
||||
def.scope.functions.del(def.name);
|
||||
def.scope.variables.del(def.name);
|
||||
}
|
||||
@@ -854,10 +854,14 @@ merge(Compressor.prototype, {
|
||||
// Locate symbols which may execute code outside of scanning range
|
||||
var lvalues = get_lvalues(candidate);
|
||||
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
||||
var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
|
||||
var replace_all = candidate.multiple;
|
||||
if (!replace_all && lhs instanceof AST_SymbolRef) {
|
||||
var def = lhs.definition();
|
||||
replace_all = def.references.length - def.replaced == 1;
|
||||
}
|
||||
var side_effects = value_has_side_effects(candidate);
|
||||
var hit = candidate.name instanceof AST_SymbolFunarg;
|
||||
var abort = false, replaced = false, can_replace = !args || !hit;
|
||||
var abort = false, replaced = 0, can_replace = !args || !hit;
|
||||
var tt = new TreeTransformer(function(node, descend) {
|
||||
if (abort) return node;
|
||||
// Skip nodes before `candidate` as quickly as possible
|
||||
@@ -886,7 +890,8 @@ merge(Compressor.prototype, {
|
||||
&& !(node instanceof AST_SymbolDeclaration)
|
||||
&& !is_lhs(node, parent)
|
||||
&& lhs.equivalent_to(node)) {
|
||||
CHANGED = replaced = abort = true;
|
||||
CHANGED = abort = true;
|
||||
replaced++;
|
||||
compressor.info("Collapsing {name} [{file}:{line},{col}]", {
|
||||
name: node.print_to_string(),
|
||||
file: node.start.file,
|
||||
@@ -897,8 +902,13 @@ merge(Compressor.prototype, {
|
||||
return make_node(AST_UnaryPrefix, candidate, candidate);
|
||||
}
|
||||
if (candidate instanceof AST_VarDef) {
|
||||
if (candidate.multiple) {
|
||||
abort = false;
|
||||
return node;
|
||||
}
|
||||
var def = candidate.name.definition();
|
||||
if (def.references.length == 1 && !compressor.exposed(def)) {
|
||||
if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
|
||||
def.replaced++;
|
||||
return maintain_this_binding(parent, node, candidate.value);
|
||||
}
|
||||
return make_node(AST_Assign, candidate, {
|
||||
@@ -922,7 +932,7 @@ merge(Compressor.prototype, {
|
||||
|| side_effects && !references_in_scope(node.definition()))
|
||||
|| (sym = lhs_or_def(node))
|
||||
&& (sym instanceof AST_PropAccess || sym.name in lvalues)
|
||||
|| (side_effects || !one_off)
|
||||
|| (side_effects || !replace_all)
|
||||
&& (parent instanceof AST_Binary && lazy_op(parent.operator)
|
||||
|| parent instanceof AST_Case
|
||||
|| parent instanceof AST_Conditional
|
||||
@@ -935,7 +945,7 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
||||
});
|
||||
if (!can_replace) {
|
||||
for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; j < args.length; j++) {
|
||||
for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; !abort && j < args.length; j++) {
|
||||
args[j].transform(tt);
|
||||
}
|
||||
can_replace = true;
|
||||
@@ -943,6 +953,33 @@ merge(Compressor.prototype, {
|
||||
for (var i = stat_index; !abort && i < statements.length; i++) {
|
||||
statements[i].transform(tt);
|
||||
}
|
||||
if (candidate.multiple) {
|
||||
var def = candidate.name.definition();
|
||||
if (abort && def.references.length > replaced) replaced = false;
|
||||
else {
|
||||
abort = false;
|
||||
hit = candidate.name instanceof AST_SymbolFunarg;
|
||||
var value_def = candidate.value.definition();
|
||||
for (var i = stat_index; !abort && i < statements.length; i++) {
|
||||
statements[i].transform(new TreeTransformer(function(node) {
|
||||
if (abort) return node;
|
||||
if (!hit) {
|
||||
if (node === candidate) {
|
||||
hit = true;
|
||||
return node;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef && node.name == def.name) {
|
||||
def.replaced++;
|
||||
value_def.replaced--;
|
||||
if (!--replaced) abort = true;
|
||||
return candidate.value;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
|
||||
}
|
||||
}
|
||||
@@ -956,7 +993,7 @@ merge(Compressor.prototype, {
|
||||
&& (iife = compressor.parent()) instanceof AST_Call
|
||||
&& iife.expression === fn) {
|
||||
var fn_strict = compressor.has_directive("use strict");
|
||||
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
||||
if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false;
|
||||
var len = fn.argnames.length;
|
||||
args = iife.args.slice(len);
|
||||
var names = Object.create(null);
|
||||
@@ -1012,12 +1049,22 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
function mangleable_var(expr) {
|
||||
var value = expr.value;
|
||||
if (!(value instanceof AST_SymbolRef)) return false;
|
||||
if (value.name == "arguments") return false;
|
||||
if (value.definition().undeclared) return false;
|
||||
expr.multiple = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function get_lhs(expr) {
|
||||
if (expr instanceof AST_VarDef) {
|
||||
var def = expr.name.definition();
|
||||
if (def.orig.length - (def._eliminiated || 0) > 1
|
||||
&& !(expr.name instanceof AST_SymbolFunarg)
|
||||
|| def.references.length == 1 && !compressor.exposed(def)) {
|
||||
var declared = def.orig.length - def.eliminated;
|
||||
var referenced = def.references.length - def.replaced;
|
||||
if (declared > 1 && !(expr.name instanceof AST_SymbolFunarg)
|
||||
|| (referenced > 1 ? mangleable_var(expr) : !compressor.exposed(def))) {
|
||||
return make_node(AST_SymbolRef, expr.name, expr.name);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -46,8 +46,10 @@
|
||||
function SymbolDef(scope, index, orig) {
|
||||
this.name = orig.name;
|
||||
this.orig = [ orig ];
|
||||
this.eliminated = 0;
|
||||
this.scope = scope;
|
||||
this.references = [];
|
||||
this.replaced = 0;
|
||||
this.global = false;
|
||||
this.mangled_name = null;
|
||||
this.undeclared = false;
|
||||
|
||||
@@ -3098,3 +3098,423 @@ issue_2437: {
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
issue_2436_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log({
|
||||
x: o.a,
|
||||
y: o.b,
|
||||
});
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
o.a = 3;
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
o.a = 3;
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
o = {
|
||||
a: 3,
|
||||
b: 4,
|
||||
};
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
o = {
|
||||
a: 3,
|
||||
b: 4,
|
||||
};
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_4: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
var o;
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}({
|
||||
a: 1,
|
||||
b: 2,
|
||||
}));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_5: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(o) {
|
||||
return {
|
||||
x: o.a,
|
||||
y: o.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(o) {
|
||||
return {
|
||||
x: o.a,
|
||||
y: o.b,
|
||||
};
|
||||
}({
|
||||
a: 1,
|
||||
b: 2,
|
||||
}));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_6: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
x: 1,
|
||||
y: 2,
|
||||
});
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_7: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
hoist_props: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
x: 1,
|
||||
y: 2,
|
||||
});
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_8: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_9: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = console;
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
var o = console;
|
||||
console.log(function(c) {
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2436_10: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
function f(n) {
|
||||
o = { b: 3 };
|
||||
return n;
|
||||
}
|
||||
console.log(function(c) {
|
||||
return [
|
||||
c.a,
|
||||
f(c.b),
|
||||
c.b,
|
||||
];
|
||||
}(o).join(" "));
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
function f(n) {
|
||||
o = { b: 3 };
|
||||
return n;
|
||||
}
|
||||
console.log(function(c) {
|
||||
return [
|
||||
c.a,
|
||||
f(c.b),
|
||||
c.b,
|
||||
];
|
||||
}(o).join(" "));
|
||||
}
|
||||
expect_stdout: "1 2 2"
|
||||
}
|
||||
|
||||
issue_2436_11: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
join_vars: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function matrix() {}
|
||||
function isCollection() {}
|
||||
function _randomDataForMatrix() {}
|
||||
function _randomInt() {}
|
||||
function f(arg1, arg2) {
|
||||
if (isCollection(arg1)) {
|
||||
var size = arg1;
|
||||
var max = arg2;
|
||||
var min = 0;
|
||||
var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
|
||||
return size && true === size.isMatrix ? matrix(res) : res;
|
||||
} else {
|
||||
var min = arg1;
|
||||
var max = arg2;
|
||||
return _randomInt(min, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function matrix() {}
|
||||
function isCollection() {}
|
||||
function _randomDataForMatrix() {}
|
||||
function _randomInt() {}
|
||||
function f(arg1, arg2) {
|
||||
if (isCollection(arg1)) {
|
||||
var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
|
||||
return size && true === size.isMatrix ? matrix(res) : res;
|
||||
} else {
|
||||
return _randomInt(min = arg1, max = arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_2436_12: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function isUndefined() {}
|
||||
function f() {
|
||||
var viewValue = this.$$lastCommittedViewValue;
|
||||
var modelValue = viewValue;
|
||||
return isUndefined(modelValue) ? modelValue : null;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function isUndefined() {}
|
||||
function f() {
|
||||
var modelValue = this.$$lastCommittedViewValue;
|
||||
return isUndefined(modelValue) ? modelValue : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user