enhance collapse_vars (#5556)
This commit is contained in:
211
lib/compress.js
211
lib/compress.js
@@ -1675,6 +1675,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (may_throw && parent.bcatch && parent.bcatch !== node) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var identifier_atom = makePredicate("Infinity NaN undefined");
|
||||
@@ -1917,7 +1918,7 @@ Compressor.prototype.compress = function(node) {
|
||||
var in_lambda = last_of(compressor, function(node) {
|
||||
return node instanceof AST_Lambda;
|
||||
});
|
||||
var block_scope, in_loop, in_try, scope;
|
||||
var block_scope, iife_in_try, in_iife_single, in_loop, in_try, scope;
|
||||
find_loop_scope_try();
|
||||
var changed, last_changed, max_iter = 10;
|
||||
do {
|
||||
@@ -2490,10 +2491,10 @@ Compressor.prototype.compress = function(node) {
|
||||
var after = stop_after;
|
||||
var if_hit = stop_if_hit;
|
||||
for (var i = 0; !abort && i < fn.argnames.length; i++) {
|
||||
if (may_throw_arg(reject, fn.argnames[i], node.args[i])) abort = true;
|
||||
if (arg_may_throw(reject, fn.argnames[i], node.args[i])) abort = true;
|
||||
}
|
||||
if (!abort) {
|
||||
if (fn.rest && may_throw_arg(reject, fn.rest, make_node(AST_Array, node, {
|
||||
if (fn.rest && arg_may_throw(reject, fn.rest, make_node(AST_Array, node, {
|
||||
elements: node.args.slice(i),
|
||||
}))) {
|
||||
abort = true;
|
||||
@@ -2579,128 +2580,134 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
}
|
||||
|
||||
function may_throw_arg(reject, node, value) {
|
||||
function arg_may_throw(reject, node, value) {
|
||||
if (node instanceof AST_DefaultValue) {
|
||||
return reject(node.value)
|
||||
|| may_throw_arg(reject, node.name, node.value)
|
||||
|| !is_undefined(value) && may_throw_arg(reject, node.name, value);
|
||||
|| arg_may_throw(reject, node.name, node.value)
|
||||
|| !is_undefined(value) && arg_may_throw(reject, node.name, value);
|
||||
}
|
||||
if (!value) return !(node instanceof AST_Symbol);
|
||||
if (node instanceof AST_Destructured) {
|
||||
if (node.rest && may_throw_arg(reject, node.rest)) return true;
|
||||
if (node.rest && arg_may_throw(reject, node.rest)) return true;
|
||||
if (node instanceof AST_DestructuredArray) {
|
||||
if (value instanceof AST_Array) return !all(node.elements, function(element, index) {
|
||||
return !may_throw_arg(reject, element, value[index]);
|
||||
return !arg_may_throw(reject, element, value[index]);
|
||||
});
|
||||
return value.is_string(compressor) && !all(node.elements, function(element) {
|
||||
return !may_throw_arg(reject, element);
|
||||
return !arg_may_throw(reject, element);
|
||||
});
|
||||
}
|
||||
if (node instanceof AST_DestructuredObject) {
|
||||
if (value.may_throw_on_access(compressor)) return true;
|
||||
return !all(node.properties, function(prop) {
|
||||
if (prop.key instanceof AST_Node && reject(prop.key)) return false;
|
||||
return !may_throw_arg(reject, prop.value);
|
||||
return !arg_may_throw(reject, prop.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extract_args() {
|
||||
var iife, fn = compressor.self();
|
||||
if (fn instanceof AST_LambdaExpression
|
||||
&& !is_generator(fn)
|
||||
&& !fn.uses_arguments
|
||||
&& !fn.pinned()
|
||||
&& (iife = compressor.parent()) instanceof AST_Call
|
||||
&& iife.expression === fn
|
||||
&& is_iife_single(iife)
|
||||
&& all(iife.args, function(arg) {
|
||||
return !(arg instanceof AST_Spread);
|
||||
})) {
|
||||
var fn_strict = fn.in_strict_mode(compressor)
|
||||
&& !fn.parent_scope.resolve(true).in_strict_mode(compressor);
|
||||
var check_arg = false, has_await;
|
||||
if (is_async(fn)) {
|
||||
check_arg = true;
|
||||
has_await = function(node) {
|
||||
return node instanceof AST_Symbol && node.name == "await";
|
||||
};
|
||||
} else {
|
||||
check_arg = find_try(compressor, 1, iife, null, true, true);
|
||||
has_await = function(node) {
|
||||
return node instanceof AST_Await && !tw.find_parent(AST_Scope);
|
||||
};
|
||||
if (in_iife_single === false) return;
|
||||
var iife = compressor.parent(), fn = compressor.self();
|
||||
if (in_iife_single === undefined) {
|
||||
if (!(fn instanceof AST_LambdaExpression)
|
||||
|| is_generator(fn)
|
||||
|| fn.uses_arguments
|
||||
|| fn.pinned()
|
||||
|| !(iife instanceof AST_Call)
|
||||
|| iife.expression !== fn
|
||||
|| !all(iife.args, function(arg) {
|
||||
return !(arg instanceof AST_Spread);
|
||||
})) {
|
||||
in_iife_single = false;
|
||||
return;
|
||||
}
|
||||
var arg_scope = null;
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
if (!arg) return true;
|
||||
if (has_await(node) || node instanceof AST_Yield) {
|
||||
arg = null;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_ObjectIdentity && (fn_strict || !arg_scope)) {
|
||||
arg = null;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) {
|
||||
var s = node.definition().scope;
|
||||
if (s !== scope) while (s = s.parent_scope) {
|
||||
if (s === scope) return true;
|
||||
}
|
||||
arg = null;
|
||||
}
|
||||
if (node instanceof AST_Scope && !is_arrow(node)) {
|
||||
var save_scope = arg_scope;
|
||||
arg_scope = node;
|
||||
descend();
|
||||
arg_scope = save_scope;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
args = iife.args.slice();
|
||||
var len = args.length;
|
||||
var names = new Dictionary();
|
||||
for (var i = fn.argnames.length; --i >= 0;) {
|
||||
var sym = fn.argnames[i];
|
||||
var arg = args[i];
|
||||
var value = null;
|
||||
if (sym instanceof AST_DefaultValue) {
|
||||
value = sym.value;
|
||||
sym = sym.name;
|
||||
args[len + i] = value;
|
||||
}
|
||||
if (sym instanceof AST_Destructured) {
|
||||
if (check_arg && may_throw_arg(function(node) {
|
||||
return node.has_side_effects(compressor);
|
||||
}, sym, arg)) {
|
||||
candidates.length = 0;
|
||||
break;
|
||||
}
|
||||
args[len + i] = fn.argnames[i];
|
||||
continue;
|
||||
}
|
||||
if (names.has(sym.name)) continue;
|
||||
names.set(sym.name, true);
|
||||
if (value) arg = is_undefined(arg) ? value : null;
|
||||
if (!arg && !value) {
|
||||
arg = make_node(AST_Undefined, sym).transform(compressor);
|
||||
} else if (arg instanceof AST_Lambda && arg.pinned()) {
|
||||
arg = null;
|
||||
} else if (arg) {
|
||||
arg.walk(tw);
|
||||
}
|
||||
if (!arg) continue;
|
||||
var candidate = make_node(AST_VarDef, sym, {
|
||||
name: sym,
|
||||
value: arg,
|
||||
});
|
||||
candidate.name_index = i;
|
||||
candidate.arg_index = value ? len + i : i;
|
||||
candidates.unshift([ candidate ]);
|
||||
}
|
||||
if (fn.rest) args.push(fn.rest);
|
||||
if (!is_iife_single(iife)) return;
|
||||
in_iife_single = true;
|
||||
}
|
||||
var fn_strict = fn.in_strict_mode(compressor)
|
||||
&& !fn.parent_scope.resolve(true).in_strict_mode(compressor);
|
||||
var has_await;
|
||||
if (is_async(fn)) {
|
||||
has_await = function(node) {
|
||||
return node instanceof AST_Symbol && node.name == "await";
|
||||
};
|
||||
iife_in_try = true;
|
||||
} else {
|
||||
has_await = function(node) {
|
||||
return node instanceof AST_Await && !tw.find_parent(AST_Scope);
|
||||
};
|
||||
if (iife_in_try === undefined) iife_in_try = find_try(compressor, 1, iife, null, true, true);
|
||||
}
|
||||
var arg_scope = null;
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
if (!arg) return true;
|
||||
if (has_await(node) || node instanceof AST_Yield) {
|
||||
arg = null;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_ObjectIdentity && (fn_strict || !arg_scope)) {
|
||||
arg = null;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) {
|
||||
var s = node.definition().scope;
|
||||
if (s !== scope) while (s = s.parent_scope) {
|
||||
if (s === scope) return true;
|
||||
}
|
||||
arg = null;
|
||||
}
|
||||
if (node instanceof AST_Scope && !is_arrow(node)) {
|
||||
var save_scope = arg_scope;
|
||||
arg_scope = node;
|
||||
descend();
|
||||
arg_scope = save_scope;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
args = iife.args.slice();
|
||||
var len = args.length;
|
||||
var names = new Dictionary();
|
||||
for (var i = fn.argnames.length; --i >= 0;) {
|
||||
var sym = fn.argnames[i];
|
||||
var arg = args[i];
|
||||
var value = null;
|
||||
if (sym instanceof AST_DefaultValue) {
|
||||
value = sym.value;
|
||||
sym = sym.name;
|
||||
args[len + i] = value;
|
||||
}
|
||||
if (sym instanceof AST_Destructured) {
|
||||
if (iife_in_try && arg_may_throw(function(node) {
|
||||
return node.has_side_effects(compressor);
|
||||
}, sym, arg)) {
|
||||
candidates.length = 0;
|
||||
break;
|
||||
}
|
||||
args[len + i] = fn.argnames[i];
|
||||
continue;
|
||||
}
|
||||
if (names.has(sym.name)) continue;
|
||||
names.set(sym.name, true);
|
||||
if (value) arg = is_undefined(arg) ? value : null;
|
||||
if (!arg && !value) {
|
||||
arg = make_node(AST_Undefined, sym).transform(compressor);
|
||||
} else if (arg instanceof AST_Lambda && arg.pinned()) {
|
||||
arg = null;
|
||||
} else if (arg) {
|
||||
arg.walk(tw);
|
||||
}
|
||||
if (!arg) continue;
|
||||
var candidate = make_node(AST_VarDef, sym, {
|
||||
name: sym,
|
||||
value: arg,
|
||||
});
|
||||
candidate.name_index = i;
|
||||
candidate.arg_index = value ? len + i : i;
|
||||
candidates.unshift([ candidate ]);
|
||||
}
|
||||
if (fn.rest) args.push(fn.rest);
|
||||
}
|
||||
|
||||
function extract_candidates(expr, unused) {
|
||||
|
||||
Reference in New Issue
Block a user