Merge branch 'master' into harmony-v3.3.3

This commit is contained in:
alexlamsl
2017-12-29 03:30:53 +08:00
9 changed files with 491 additions and 71 deletions

View File

@@ -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),