Merge branch 'master' into harmony-v3.3.3
This commit is contained in:
161
lib/compress.js
161
lib/compress.js
@@ -326,6 +326,7 @@ merge(Compressor.prototype, {
|
||||
} else {
|
||||
def.fixed = false;
|
||||
}
|
||||
def.recursive_refs = 0;
|
||||
def.references = [];
|
||||
def.should_replace = undefined;
|
||||
def.single_use = undefined;
|
||||
@@ -383,7 +384,7 @@ merge(Compressor.prototype, {
|
||||
return compressor.option("unused")
|
||||
&& !def.scope.uses_eval
|
||||
&& !def.scope.uses_with
|
||||
&& def.references.length == 1
|
||||
&& def.references.length - def.recursive_refs == 1
|
||||
&& tw.loop_ids[def.id] === tw.in_loop;
|
||||
}
|
||||
|
||||
@@ -669,7 +670,9 @@ merge(Compressor.prototype, {
|
||||
d.fixed = false;
|
||||
} else if (d.fixed) {
|
||||
value = this.fixed_value();
|
||||
if (value && !compressor.exposed(d) && ref_once(tw, compressor, d)) {
|
||||
if (value instanceof AST_Lambda && recursive_ref(tw, d)) {
|
||||
d.recursive_refs++;
|
||||
} else if (value && !compressor.exposed(d) && ref_once(tw, compressor, d)) {
|
||||
d.single_use = value instanceof AST_Lambda
|
||||
|| value instanceof AST_Class
|
||||
|| d.scope === this.scope && value.is_constant_expression();
|
||||
@@ -1820,15 +1823,8 @@ merge(Compressor.prototype, {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def(AST_Binary, function(compressor) {
|
||||
switch (this.operator) {
|
||||
case "&&":
|
||||
return this.left._dot_throw(compressor);
|
||||
case "||":
|
||||
return this.left._dot_throw(compressor)
|
||||
&& this.right._dot_throw(compressor);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return (this.operator == "&&" || this.operator == "||")
|
||||
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||
})
|
||||
def(AST_Assign, function(compressor) {
|
||||
return this.operator == "="
|
||||
@@ -2813,15 +2809,15 @@ merge(Compressor.prototype, {
|
||||
var tw = new TreeWalker(function(node, descend){
|
||||
if (node === self) return;
|
||||
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
||||
var node_def = node.name.definition();
|
||||
var in_export = tw.parent() instanceof AST_Export;
|
||||
if (in_export || !drop_funcs && scope === self) {
|
||||
var node_def = node.name.definition();
|
||||
if (node_def.global && !(node_def.id in in_use_ids)) {
|
||||
in_use_ids[node_def.id] = true;
|
||||
in_use.push(node_def);
|
||||
}
|
||||
}
|
||||
initializations.add(node.name.name, node);
|
||||
initializations.add(node_def.id, node);
|
||||
return true; // don't go in nested scopes
|
||||
}
|
||||
if (node instanceof AST_SymbolFunarg && scope === self) {
|
||||
@@ -2851,7 +2847,7 @@ merge(Compressor.prototype, {
|
||||
def.walk(tw);
|
||||
destructuring_value = destructuring_cache;
|
||||
} else {
|
||||
initializations.add(def.name.name, def.value);
|
||||
initializations.add(def.name.definition().id, def.value);
|
||||
}
|
||||
if (def.value.has_side_effects(compressor)) {
|
||||
def.value.walk(tw);
|
||||
@@ -2870,13 +2866,10 @@ merge(Compressor.prototype, {
|
||||
// initialization code to figure out if it uses other
|
||||
// symbols (that may not be in_use).
|
||||
tw = new TreeWalker(scan_ref_scoped);
|
||||
for (var i = 0; i < in_use.length; ++i) {
|
||||
in_use[i].orig.forEach(function(decl){
|
||||
// undeclared globals will be instanceof AST_SymbolRef
|
||||
var init = initializations.get(decl.name);
|
||||
if (init) init.forEach(function(init){
|
||||
init.walk(tw);
|
||||
});
|
||||
for (var i = 0; i < in_use.length; i++) {
|
||||
var init = initializations.get(in_use[i].id);
|
||||
if (init) init.forEach(function(init) {
|
||||
init.walk(tw);
|
||||
});
|
||||
}
|
||||
// pass 3: we should drop declarations not in_use
|
||||
@@ -3942,9 +3935,10 @@ merge(Compressor.prototype, {
|
||||
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
||||
fn = fn.fixed_value();
|
||||
}
|
||||
var is_func = fn instanceof AST_Lambda;
|
||||
if (compressor.option("unused")
|
||||
&& simple_args
|
||||
&& is_func_expr(fn)
|
||||
&& is_func
|
||||
&& !fn.uses_arguments
|
||||
&& !fn.uses_eval) {
|
||||
var pos = 0, last = 0;
|
||||
@@ -4131,7 +4125,7 @@ merge(Compressor.prototype, {
|
||||
if (func instanceof AST_SymbolRef) {
|
||||
func = func.fixed_value();
|
||||
}
|
||||
if (func instanceof AST_Function && !func.contains_this()) {
|
||||
if (func instanceof AST_Lambda && !func.contains_this()) {
|
||||
return make_sequence(this, [
|
||||
self.args[0],
|
||||
make_node(AST_Call, self, {
|
||||
@@ -4208,7 +4202,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
}
|
||||
var stat = is_func_expr(fn) && fn.body;
|
||||
var stat = is_func && fn.body;
|
||||
if (stat instanceof AST_Node) {
|
||||
stat = make_node(AST_Return, stat, {
|
||||
value: stat
|
||||
@@ -4223,7 +4217,7 @@ merge(Compressor.prototype, {
|
||||
return make_sequence(self, args).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (is_func_expr(fn) && !fn.is_generator && !fn.async) {
|
||||
if (is_func && !fn.is_generator && !fn.async) {
|
||||
var def, value, scope, level = -1;
|
||||
if (compressor.option("inline")
|
||||
&& simple_args
|
||||
@@ -4272,26 +4266,39 @@ merge(Compressor.prototype, {
|
||||
return self;
|
||||
|
||||
function can_flatten_args(fn) {
|
||||
var catches = Object.create(null);
|
||||
var catches = Object.create(null), defs;
|
||||
do {
|
||||
scope = compressor.parent(++level);
|
||||
if (scope instanceof AST_SymbolRef) {
|
||||
scope = scope.fixed_value();
|
||||
} else if (scope instanceof AST_Catch) {
|
||||
if (scope instanceof AST_Catch) {
|
||||
catches[scope.argname.name] = true;
|
||||
} else if (scope instanceof AST_IterationStatement) {
|
||||
defs = [];
|
||||
} else if (scope instanceof AST_SymbolRef) {
|
||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||
}
|
||||
} while (!(scope instanceof AST_Scope) || scope instanceof AST_Arrow);
|
||||
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
|
||||
return all(fn.argnames, function(arg) {
|
||||
if (arg instanceof AST_DefaultAssign) return arg.left.__unused;
|
||||
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
||||
var arg = fn.argnames[i];
|
||||
if (arg instanceof AST_DefaultAssign) {
|
||||
if (arg.left.__unused) continue;
|
||||
return false;
|
||||
}
|
||||
if (arg instanceof AST_Destructuring) return false;
|
||||
if (arg instanceof AST_Expansion) return arg.expression.__unused;
|
||||
return arg.__unused
|
||||
|| safe_to_inject
|
||||
&& !catches[arg.name]
|
||||
&& !identifier_atom(arg.name)
|
||||
&& !scope.var_names()[arg.name];
|
||||
});
|
||||
if (arg instanceof AST_Expansion) {
|
||||
if (arg.expression.__unused) continue;
|
||||
return false;
|
||||
}
|
||||
if (arg.__unused) continue;
|
||||
if (!safe_to_inject
|
||||
|| catches[arg.name]
|
||||
|| identifier_atom(arg.name)
|
||||
|| scope.var_names()[arg.name]) {
|
||||
return false;
|
||||
}
|
||||
if (defs) defs.push(arg.definition());
|
||||
}
|
||||
return !defs || defs.length == 0 || !is_reachable(stat, defs);
|
||||
}
|
||||
|
||||
function flatten_args(fn) {
|
||||
@@ -4969,23 +4976,18 @@ merge(Compressor.prototype, {
|
||||
&& is_lhs(self, compressor.parent()) !== self) {
|
||||
var d = self.definition();
|
||||
var fixed = self.fixed_value();
|
||||
if (fixed instanceof AST_DefClass) {
|
||||
d.fixed = fixed = make_node(AST_ClassExpression, fixed, fixed);
|
||||
}
|
||||
if (fixed instanceof AST_Defun) {
|
||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||
}
|
||||
if (d.single_use && (is_func_expr(fixed) || fixed instanceof AST_ClassExpression)) {
|
||||
var single_use = d.single_use;
|
||||
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
|
||||
if (d.scope !== self.scope
|
||||
&& (!compressor.option("reduce_funcs") && is_func_expr(fixed)
|
||||
&& (!compressor.option("reduce_funcs") && fixed instanceof AST_Lambda
|
||||
|| d.escaped == 1
|
||||
|| fixed.inlined)) {
|
||||
d.single_use = false;
|
||||
single_use = false;
|
||||
} else if (recursive_ref(compressor, d)) {
|
||||
d.single_use = false;
|
||||
single_use = false;
|
||||
} else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
|
||||
d.single_use = fixed.is_constant_expression(self.scope);
|
||||
if (d.single_use == "f") {
|
||||
single_use = fixed.is_constant_expression(self.scope);
|
||||
if (single_use == "f") {
|
||||
var scope = self.scope;
|
||||
do {
|
||||
if (scope instanceof AST_Defun || is_func_expr(scope)) {
|
||||
@@ -4995,9 +4997,36 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d.single_use && fixed) {
|
||||
var value = fixed.optimize(compressor);
|
||||
return value === fixed ? fixed.clone(true) : value;
|
||||
if (single_use && fixed) {
|
||||
if (fixed instanceof AST_DefClass) {
|
||||
fixed = make_node(AST_ClassExpression, fixed, fixed);
|
||||
}
|
||||
if (fixed instanceof AST_Defun) {
|
||||
fixed = make_node(AST_Function, fixed, fixed);
|
||||
}
|
||||
var value;
|
||||
if (d.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
|
||||
value = fixed.clone(true);
|
||||
var defun_def = value.name.definition();
|
||||
var lambda_def = value.variables.get(value.name.name);
|
||||
var name = lambda_def && lambda_def.orig[0];
|
||||
if (!(name instanceof AST_SymbolLambda)) {
|
||||
name = make_node(AST_SymbolLambda, value.name, value.name);
|
||||
name.scope = value;
|
||||
value.name = name;
|
||||
lambda_def = value.def_function(name);
|
||||
}
|
||||
value.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
|
||||
node.thedef = lambda_def;
|
||||
lambda_def.references.push(node);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
value = fixed.optimize(compressor);
|
||||
if (value === fixed) value = fixed.clone(true);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (fixed && d.should_replace === undefined) {
|
||||
var init;
|
||||
@@ -5119,18 +5148,42 @@ merge(Compressor.prototype, {
|
||||
return self;
|
||||
});
|
||||
|
||||
function is_reachable(node, defs) {
|
||||
var reachable = false;
|
||||
var find_ref = new TreeWalker(function(node) {
|
||||
if (reachable) return true;
|
||||
if (node instanceof AST_SymbolRef && member(node.definition(), defs)) {
|
||||
return reachable = true;
|
||||
}
|
||||
});
|
||||
var scan_scope = new TreeWalker(function(node) {
|
||||
if (reachable) return true;
|
||||
if (node instanceof AST_Scope) {
|
||||
var parent = scan_scope.parent();
|
||||
if (!(parent instanceof AST_Call && parent.expression === node)) {
|
||||
node.walk(find_ref);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
node.walk(scan_scope);
|
||||
return reachable;
|
||||
}
|
||||
|
||||
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
||||
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
|
||||
OPT(AST_Assign, function(self, compressor){
|
||||
var def;
|
||||
if (compressor.option("dead_code")
|
||||
&& self.left instanceof AST_SymbolRef
|
||||
&& self.left.definition().scope === compressor.find_parent(AST_Lambda)) {
|
||||
&& (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) {
|
||||
var level = 0, node, parent = self;
|
||||
do {
|
||||
node = parent;
|
||||
parent = compressor.parent(level++);
|
||||
if (parent instanceof AST_Exit) {
|
||||
if (in_try(level, parent instanceof AST_Throw)) break;
|
||||
if (is_reachable(self, [ def ])) break;
|
||||
if (self.operator == "=") return self.right;
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: self.operator.slice(0, -1),
|
||||
|
||||
Reference in New Issue
Block a user