Merge branch 'master' into harmony-v3.3.5

This commit is contained in:
alexlamsl
2018-01-07 20:35:53 +08:00
30 changed files with 2063 additions and 290 deletions

View File

@@ -105,6 +105,7 @@ function Compressor(options, false_by_default) {
});
}
}
if (this.options["inline"] === true) this.options["inline"] = 3;
var pure_funcs = this.options["pure_funcs"];
if (typeof pure_funcs == "function") {
this.pure_funcs = pure_funcs;
@@ -317,12 +318,13 @@ merge(Compressor.prototype, {
def(AST_Node, noop);
function reset_def(compressor, def) {
def.assignments = 0;
def.direct_access = false;
def.escaped = false;
if (def.scope.uses_eval || def.scope.uses_with) {
def.fixed = false;
} else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
def.fixed = undefined;
def.fixed = def.init;
} else {
def.fixed = false;
}
@@ -332,9 +334,16 @@ merge(Compressor.prototype, {
def.single_use = undefined;
}
function reset_variables(compressor, node) {
function reset_variables(tw, compressor, node) {
node.variables.each(function(def) {
reset_def(compressor, def);
if (def.fixed === null) {
def.safe_ids = tw.safe_ids;
mark(tw, def, true);
} else if (def.fixed) {
tw.loop_ids[def.id] = tw.in_loop;
mark(tw, def, true);
}
});
}
@@ -369,10 +378,16 @@ merge(Compressor.prototype, {
}
function safe_to_assign(tw, def, value) {
if (def.fixed === undefined) return true;
if (def.fixed === null && def.safe_ids) {
def.safe_ids[def.id] = false;
delete def.safe_ids;
return true;
}
if (!HOP(tw.safe_ids, def.id)) return false;
if (!safe_to_read(tw, def)) return false;
if (def.fixed === false) return false;
if (def.fixed != null && (!value || def.references.length > 0)) return false;
if (def.fixed != null && (!value || def.references.length > def.assignments)) return false;
return all(def.orig, function(sym) {
return !(sym instanceof AST_SymbolConst
|| sym instanceof AST_SymbolDefun
@@ -489,11 +504,9 @@ merge(Compressor.prototype, {
}
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
var d = node.left.definition();
if (safe_to_assign(tw, d, node.right)
|| d.fixed === undefined && all(d.orig, function(sym) {
return sym instanceof AST_SymbolVar;
})) {
if (safe_to_assign(tw, d, node.right)) {
d.references.push(node.left);
d.assignments++;
d.fixed = function() {
return node.right;
};
@@ -533,19 +546,10 @@ merge(Compressor.prototype, {
});
function mark_def_node(tw, descend, compressor) {
reset_variables(compressor, this);
this.inlined = false;
var d = this.name.definition();
if (compressor.exposed(d) || safe_to_read(tw, d)) {
d.fixed = false;
} else {
d.fixed = this;
d.single_use = ref_once(tw, compressor, d);
tw.loop_ids[d.id] = tw.in_loop;
mark(tw, d, true);
}
var save_ids = tw.safe_ids;
tw.safe_ids = Object.create(null);
reset_variables(tw, compressor, this);
descend();
tw.safe_ids = save_ids;
return true;
@@ -600,9 +604,9 @@ merge(Compressor.prototype, {
function mark_func_expr(tw, descend, compressor) {
var node = this;
reset_variables(compressor, node);
node.inlined = false;
push(tw);
reset_variables(tw, compressor, node);
var iife;
if (!node.name
&& (iife = tw.parent()) instanceof AST_Call
@@ -693,7 +697,7 @@ merge(Compressor.prototype, {
this.globals.each(function(def) {
reset_def(compressor, def);
});
reset_variables(compressor, this);
reset_variables(tw, compressor, this);
});
def(AST_Try, function(tw, descend, compressor) {
reset_block_variables(compressor, this);
@@ -715,7 +719,7 @@ merge(Compressor.prototype, {
return;
}
var d = node.name.definition();
if (d.fixed === undefined || safe_to_assign(tw, d, node.value)) {
if (safe_to_assign(tw, d, node.value)) {
if (node.value) {
d.fixed = function() {
return node.value;
@@ -723,8 +727,6 @@ merge(Compressor.prototype, {
tw.loop_ids[d.id] = tw.in_loop;
mark(tw, d, false);
descend();
} else {
d.fixed = null;
}
mark(tw, d, true);
return true;
@@ -957,6 +959,7 @@ merge(Compressor.prototype, {
}
if (compressor.sequences_limit > 0) {
sequencesize(statements, compressor);
sequencesize_2(statements, compressor);
}
if (compressor.option("join_vars")) {
join_consecutive_vars(statements, compressor);
@@ -1259,10 +1262,10 @@ merge(Compressor.prototype, {
if (!expr.left.has_side_effects(compressor)) {
candidates.push(hit_stack.slice());
}
} else if (expr instanceof AST_Unary) {
if (expr.operator == "++" || expr.operator == "--") {
candidates.push(hit_stack.slice());
}
extract_candidates(expr.right);
} else if (expr instanceof AST_Binary) {
extract_candidates(expr.left);
extract_candidates(expr.right);
} else if (expr instanceof AST_Call) {
extract_candidates(expr.expression);
expr.args.forEach(extract_candidates);
@@ -1275,10 +1278,14 @@ merge(Compressor.prototype, {
} else if (expr instanceof AST_Definitions
&& (compressor.option("unused") || !(expr instanceof AST_Const))) {
expr.definitions.forEach(extract_candidates);
} else if (expr instanceof AST_DWLoop) {
extract_candidates(expr.condition);
} else if (expr instanceof AST_Exit) {
if (expr.value) extract_candidates(expr.value);
} else if (expr instanceof AST_For) {
if (expr.init) extract_candidates(expr.init);
if (expr.condition) extract_candidates(expr.condition);
if (expr.step) extract_candidates(expr.step);
} else if (expr instanceof AST_If) {
extract_candidates(expr.condition);
} else if (expr instanceof AST_Sequence) {
@@ -1288,21 +1295,31 @@ merge(Compressor.prototype, {
} else if (expr instanceof AST_Switch) {
extract_candidates(expr.expression);
expr.body.forEach(extract_candidates);
} else if (expr instanceof AST_Unary) {
if (expr.operator == "++" || expr.operator == "--") {
candidates.push(hit_stack.slice());
}
} else if (expr instanceof AST_VarDef) {
if (expr.value) candidates.push(hit_stack.slice());
if (expr.value) {
candidates.push(hit_stack.slice());
extract_candidates(expr.value);
}
}
hit_stack.pop();
}
function find_stop(node, level) {
var parent = scanner.parent(level);
if (parent instanceof AST_Binary) return node;
if (parent instanceof AST_Call) return node;
if (parent instanceof AST_Case) return node;
if (parent instanceof AST_Conditional) return node;
if (parent instanceof AST_Exit) return node;
if (parent instanceof AST_If) return node;
if (parent instanceof AST_IterationStatement) return node;
if (parent instanceof AST_Sequence) return find_stop(parent, level + 1);
if (parent instanceof AST_Switch) return node;
if (parent instanceof AST_VarDef) return node;
return null;
}
@@ -1450,12 +1467,13 @@ merge(Compressor.prototype, {
var in_lambda = self instanceof AST_Lambda;
for (var i = statements.length; --i >= 0;) {
var stat = statements[i];
var next = statements[i + 1];
var j = next_index(i);
var next = statements[j];
if (in_lambda && !next && stat instanceof AST_Return) {
if (!stat.value) {
CHANGED = true;
statements.length--;
statements.splice(i, 1);
continue;
}
if (stat.value instanceof AST_UnaryPrefix && stat.value.operator == "void") {
@@ -1525,19 +1543,22 @@ merge(Compressor.prototype, {
CHANGED = true;
stat = stat.clone();
stat.alternative = next;
statements.splice(i, 2, stat.transform(compressor));
statements.splice(i, 1, stat.transform(compressor));
statements.splice(j, 1);
continue;
}
//---
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
if (multiple_if_returns && in_lambda && value && !stat.alternative
&& (!next || next instanceof AST_Return)) {
if (value && !stat.alternative
&& (!next && in_lambda && multiple_if_returns
|| next instanceof AST_Return)) {
CHANGED = true;
stat = stat.clone();
stat.alternative = next || make_node(AST_Return, stat, {
value: null
});
statements.splice(i, next ? 2 : 1, stat.transform(compressor));
statements.splice(i, 1, stat.transform(compressor));
if (next) statements.splice(j, 1);
continue;
}
//---
@@ -1546,10 +1567,10 @@ merge(Compressor.prototype, {
// if sequences is not enabled, this can lead to an endless loop (issue #866).
// however, with sequences on this helps producing slightly better output for
// the example code.
var prev = statements[i - 1];
var prev = statements[prev_index(i)];
if (compressor.option("sequences") && in_lambda && !stat.alternative
&& prev instanceof AST_If && prev.body instanceof AST_Return
&& i + 2 == statements.length && next instanceof AST_SimpleStatement) {
&& next_index(j) == statements.length && next instanceof AST_SimpleStatement) {
CHANGED = true;
stat = stat.clone();
stat.alternative = make_node(AST_BlockStatement, next, {
@@ -1560,7 +1581,8 @@ merge(Compressor.prototype, {
})
]
});
statements.splice(i, 2, stat.transform(compressor));
statements.splice(i, 1, stat.transform(compressor));
statements.splice(j, 1);
continue;
}
}
@@ -1614,6 +1636,26 @@ merge(Compressor.prototype, {
}
return body;
}
function next_index(i) {
for (var j = i + 1, len = statements.length; j < len; j++) {
var stat = statements[j];
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
break;
}
}
return j;
}
function prev_index(i) {
for (var j = i; --j >= 0;) {
var stat = statements[j];
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
break;
}
}
return j;
}
}
function eliminate_dead_code(statements, compressor) {
@@ -1649,6 +1691,12 @@ merge(Compressor.prototype, {
});
}
function declarations_only(node) {
return all(node.definitions, function(var_def) {
return !var_def.value;
});
}
function sequencesize(statements, compressor) {
if (statements.length < 2) return;
var seq = [], n = 0;
@@ -1665,6 +1713,9 @@ merge(Compressor.prototype, {
var body = stat.body;
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
if (body) merge_sequence(seq, body);
} else if (stat instanceof AST_Definitions && declarations_only(stat)
|| stat instanceof AST_Defun) {
statements[n++] = stat;
} else {
push_seq();
statements[n++] = stat;
@@ -1672,18 +1723,34 @@ merge(Compressor.prototype, {
}
push_seq();
statements.length = n;
sequencesize_2(statements, compressor);
CHANGED = statements.length != len;
if (n != len) CHANGED = true;
}
function to_simple_statement(block, decls) {
if (!(block instanceof AST_BlockStatement)) return block;
var stat = null;
for (var i = 0, len = block.body.length; i < len; i++) {
var line = block.body[i];
if (line instanceof AST_Definitions && declarations_only(line)) {
decls.push(line);
} else if (stat) {
return false;
} else {
stat = line;
}
}
return stat;
}
function sequencesize_2(statements, compressor) {
function cons_seq(right) {
n--;
CHANGED = true;
var left = prev.body;
return make_sequence(left, [ left, right ]).transform(compressor);
};
var n = 0, prev;
for (var i = 0, len = statements.length; i < len; i++) {
for (var i = 0; i < statements.length; i++) {
var stat = statements[i];
if (prev) {
if (stat instanceof AST_For && !(stat.init instanceof AST_Definitions)) {
@@ -1700,6 +1767,7 @@ merge(Compressor.prototype, {
else {
stat.init = prev.body;
n--;
CHANGED = true;
}
}
}
@@ -1719,6 +1787,26 @@ merge(Compressor.prototype, {
stat.expression = cons_seq(stat.expression);
}
}
if (compressor.option("conditionals") && stat instanceof AST_If) {
var decls = [];
var body = to_simple_statement(stat.body, decls);
var alt = to_simple_statement(stat.alternative, decls);
if (body !== false && alt !== false && decls.length > 0) {
var len = decls.length;
decls.push(make_node(AST_If, stat, {
condition: stat.condition,
body: body || make_node(AST_EmptyStatement, stat.body),
alternative: alt
}));
decls.unshift(n, 1);
[].splice.apply(statements, decls);
i += len;
n += len + 1;
prev = null;
CHANGED = true;
continue;
}
}
statements[n++] = stat;
prev = stat instanceof AST_SimpleStatement ? stat : null;
}
@@ -1726,30 +1814,43 @@ merge(Compressor.prototype, {
}
function join_consecutive_vars(statements, compressor) {
var defs;
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
var stat = statements[i];
var prev = statements[j];
if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
prev.definitions = prev.definitions.concat(stat.definitions);
CHANGED = true;
}
else if (stat instanceof AST_For
&& prev instanceof AST_Var
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
CHANGED = true;
if (stat.init) {
stat.init.definitions = prev.definitions.concat(stat.init.definitions);
if (stat instanceof AST_Definitions) {
if (prev && prev.TYPE == stat.TYPE) {
prev.definitions = prev.definitions.concat(stat.definitions);
CHANGED = true;
} else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
defs.definitions = defs.definitions.concat(stat.definitions);
CHANGED = true;
} else {
stat.init = prev;
statements[++j] = stat;
defs = stat;
}
statements[j] = stat;
}
else {
} else if (stat instanceof AST_For) {
if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
if (stat.init) {
prev.definitions = prev.definitions.concat(stat.init.definitions);
}
stat.init = prev;
statements[j] = stat;
CHANGED = true;
} else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
defs.definitions = defs.definitions.concat(stat.init.definitions);
stat.init = null;
statements[++j] = stat;
CHANGED = true;
} else {
statements[++j] = stat;
}
} else {
statements[++j] = stat;
}
}
statements.length = j + 1;
};
}
}
function extract_declarations_from_unreachable_code(compressor, stat, target) {
@@ -2792,6 +2893,7 @@ merge(Compressor.prototype, {
};
var in_use = [];
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
var fixed_ids = Object.create(null);
if (self instanceof AST_Toplevel && compressor.top_retain) {
self.variables.each(function(def) {
if (compressor.top_retain(def) && !(def.id in in_use_ids)) {
@@ -2847,7 +2949,11 @@ merge(Compressor.prototype, {
def.walk(tw);
destructuring_value = destructuring_cache;
} else {
initializations.add(def.name.definition().id, def.value);
var node_def = def.name.definition();;
initializations.add(node_def.id, def.value);
if (def.name.fixed_value() === def.value) {
fixed_ids[node_def.id] = true;
}
}
if (def.value.has_side_effects(compressor)) {
def.value.walk(tw);
@@ -2878,13 +2984,16 @@ merge(Compressor.prototype, {
var parent = tt.parent();
if (drop_vars) {
var sym = assign_as_unused(node);
if (sym instanceof AST_SymbolRef
&& !((sym = sym.definition()).id in in_use_ids)
&& (drop_vars || !sym.global)) {
if (sym instanceof AST_SymbolRef) {
var def = sym.definition();
var in_use = def.id in in_use_ids;
if (node instanceof AST_Assign) {
return maintain_this_binding(parent, node, node.right.transform(tt));
}
return make_node(AST_Number, node, {
if (!in_use
|| def.id in fixed_ids
&& node.left.fixed_value() !== node.right) {
return maintain_this_binding(parent, node, node.right.transform(tt));
}
} else if (!in_use) return make_node(AST_Number, node, {
value: 0
});
}
@@ -2959,13 +3068,16 @@ merge(Compressor.prototype, {
operator: "=",
left: make_node(AST_SymbolRef, def.name, def.name),
right: def.value
}));
}).transform(tt));
}
remove(var_defs, def);
sym.eliminated++;
return;
}
}
if (def.value && sym.id in fixed_ids && def.name.fixed_value() !== def.value) {
def.value = def.value.drop_side_effect_free(compressor);
}
if (def.value) {
if (side_effects.length > 0) {
if (tail.length > 0) {
@@ -3077,15 +3189,20 @@ merge(Compressor.prototype, {
self.transform(tt);
function scan_ref_scoped(node, descend) {
var sym;
if ((sym = assign_as_unused(node)) instanceof AST_SymbolRef
var node_def, sym = assign_as_unused(node);
if (sym instanceof AST_SymbolRef
&& !is_ref_of(node.left, AST_SymbolBlockDeclaration)
&& self.variables.get(sym.name) === sym.definition()) {
if (node instanceof AST_Assign) node.right.walk(tw);
&& self.variables.get(sym.name) === (node_def = sym.definition())) {
if (node instanceof AST_Assign) {
node.right.walk(tw);
if (node.left.fixed_value() === node.right) {
fixed_ids[node_def.id] = true;
}
}
return true;
}
if (node instanceof AST_SymbolRef) {
var node_def = node.definition();
node_def = node.definition();
if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
@@ -3382,7 +3499,12 @@ merge(Compressor.prototype, {
});
def(AST_Assign, function(compressor){
var left = this.left;
if (left.has_side_effects(compressor)) return this;
if (left.has_side_effects(compressor)
|| compressor.has_directive("use strict")
&& left instanceof AST_PropAccess
&& left.expression.is_constant()) {
return this;
}
this.write_only = true;
while (left instanceof AST_PropAccess) {
left = left.expression;
@@ -4018,6 +4140,27 @@ merge(Compressor.prototype, {
operator: "!"
}).optimize(compressor);
break;
case "RegExp":
var params = [];
if (all(self.args, function(arg) {
var value = arg.evaluate(compressor);
params.unshift(value);
return arg !== value;
})) {
try {
return best_of(compressor, self, make_node(AST_RegExp, self, {
value: RegExp.apply(RegExp, params),
}));
} catch (ex) {
compressor.warn("Error converting {expr} [{file}:{line},{col}]", {
expr: self.print_to_string(),
file: self.start.file,
line: self.start.line,
col: self.start.col
});
}
}
break;
case "Symbol":
// Symbol's argument is only used for debugging.
self.args = [];
@@ -4219,24 +4362,22 @@ merge(Compressor.prototype, {
}
}
if (is_func && !fn.is_generator && !fn.async) {
var def, value, scope, level = -1;
var def, value, scope, in_loop, level = -1;
if (compressor.option("inline")
&& simple_args
&& !fn.uses_arguments
&& !fn.uses_eval
&& (fn.body instanceof AST_Node || fn.body.length == 1)
&& (exp === fn ? !fn.name
: compressor.option("unused")
&& !(fn.name && fn instanceof AST_Function)
&& (value = can_flatten_body(stat))
&& (exp === fn
|| compressor.option("unused")
&& (def = exp.definition()).references.length == 1
&& !recursive_ref(compressor, def)
&& fn.is_constant_expression(exp.scope))
&& !self.pure
&& !fn.contains_this()
&& can_flatten_args(fn)
&& (value = flatten_body(stat))) {
var expressions = flatten_args(fn);
expressions.push(value.clone(true));
return make_sequence(self, expressions).optimize(compressor);
&& can_inject_symbols()) {
return make_sequence(self, flatten_fn()).optimize(compressor);
}
if (compressor.option("side_effects") && !(fn.body instanceof AST_Node) && all(fn.body, is_empty)) {
var args = self.args.concat(make_node(AST_Undefined, self));
@@ -4266,19 +4407,45 @@ merge(Compressor.prototype, {
}
return self;
function can_flatten_args(fn) {
var catches = Object.create(null), defs;
do {
scope = compressor.parent(++level);
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;
function return_value(stat) {
if (!stat) return make_node(AST_Undefined, self);
if (stat instanceof AST_Return) {
if (!stat.value) return make_node(AST_Undefined, self);
return stat.value.clone(true);
}
if (stat instanceof AST_SimpleStatement) {
return make_node(AST_UnaryPrefix, stat, {
operator: "void",
expression: stat.body.clone(true)
});
}
}
function can_flatten_body(stat) {
var body = fn.body instanceof AST_Node ? [ fn.body ] : fn.body;
var len = body.length;
if (compressor.option("inline") < 3) {
return len == 1 && return_value(stat);
}
stat = null;
for (var i = 0; i < len; i++) {
var line = body[i];
if (line instanceof AST_Var) {
if (stat && !all(line.definitions, function(var_def) {
return !var_def.value;
})) {
return false;
}
} else if (stat) {
return false;
} else {
stat = line;
}
} while (!(scope instanceof AST_Scope) || scope instanceof AST_Arrow);
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
}
return return_value(stat);
}
function can_inject_args(catches, safe_to_inject) {
for (var i = 0, len = fn.argnames.length; i < len; i++) {
var arg = fn.argnames[i];
if (arg instanceof AST_DefaultAssign) {
@@ -4297,44 +4464,119 @@ merge(Compressor.prototype, {
|| scope.var_names()[arg.name]) {
return false;
}
if (defs) defs.push(arg.definition());
if (in_loop) in_loop.push(arg.definition());
}
return !defs || defs.length == 0 || !is_reachable(stat, defs);
return true;
}
function flatten_args(fn) {
var decls = [];
var expressions = [];
for (var len = fn.argnames.length, i = len; --i >= 0;) {
var name = fn.argnames[i];
var value = self.args[i];
if (name.__unused || !name.name) {
if (value || expressions.length) {
expressions.unshift(value || make_node(AST_Undefined, self));
function can_inject_vars(catches, safe_to_inject) {
var len = fn.body.length;
for (var i = 0; i < len; i++) {
var stat = fn.body[i];
if (!(stat instanceof AST_Var)) continue;
if (!safe_to_inject) return false;
for (var j = stat.definitions.length; --j >= 0;) {
var name = stat.definitions[j].name;
if (catches[name.name]
|| identifier_atom(name.name)
|| scope.var_names()[name.name]) {
return false;
}
} else {
var def = name.definition();
scope.var_names()[name.name] = true;
scope.variables.set(name.name, def);
scope.enclosed.push(def);
var symbol = make_node(AST_SymbolVar, name, name);
def.orig.push(symbol);
decls.unshift(make_node(AST_VarDef, name, {
name: symbol,
value: null
}));
var sym = make_node(AST_SymbolRef, name, name);
def.references.push(sym);
expressions.unshift(make_node(AST_Assign, self, {
operator: "=",
left: sym,
right: value || make_node(AST_Undefined, self)
}));
if (in_loop) in_loop.push(name.definition());
}
}
for (i = len, len = self.args.length; i < len; i++) {
return true;
}
function can_inject_symbols() {
var catches = Object.create(null);
do {
scope = compressor.parent(++level);
if (scope instanceof AST_Catch) {
catches[scope.argname.name] = true;
} else if (scope instanceof AST_IterationStatement) {
in_loop = [];
} 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 = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
var inline = compressor.option("inline");
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
}
function append_var(decls, expressions, name, value) {
var def = name.definition();
scope.variables.set(name.name, def);
scope.enclosed.push(def);
if (!scope.var_names()[name.name]) {
scope.var_names()[name.name] = true;
decls.push(make_node(AST_VarDef, name, {
name: name,
value: null
}));
}
var sym = make_node(AST_SymbolRef, name, name);
def.references.push(sym);
if (value) expressions.push(make_node(AST_Assign, self, {
operator: "=",
left: sym,
right: value
}));
}
function flatten_args(decls, expressions) {
var len = fn.argnames.length;
for (var i = self.args.length; --i >= len;) {
expressions.push(self.args[i]);
}
for (i = len; --i >= 0;) {
var name = fn.argnames[i];
var value = self.args[i];
if (name.__unused || !name.name || scope.var_names()[name.name]) {
if (value) expressions.push(value);
} else {
var symbol = make_node(AST_SymbolVar, name, name);
name.definition().orig.push(symbol);
if (!value && in_loop) value = make_node(AST_Undefined, self);
append_var(decls, expressions, symbol, value);
}
}
decls.reverse();
expressions.reverse();
}
function flatten_vars(decls, expressions) {
var pos = expressions.length;
for (var i = 0, lines = fn.body.length; i < lines; i++) {
var stat = fn.body[i];
if (!(stat instanceof AST_Var)) continue;
for (var j = 0, defs = stat.definitions.length; j < defs; j++) {
var var_def = stat.definitions[j];
var name = var_def.name;
append_var(decls, expressions, name, var_def.value);
if (in_loop) {
var def = name.definition();
var sym = make_node(AST_SymbolRef, name, name);
def.references.push(sym);
expressions.splice(pos++, 0, make_node(AST_Assign, var_def, {
operator: "=",
left: sym,
right: make_node(AST_Undefined, name)
}));
}
}
}
}
function flatten_fn() {
var decls = [];
var expressions = [];
flatten_args(decls, expressions);
flatten_vars(decls, expressions);
expressions.push(value);
if (decls.length) {
i = scope.body.indexOf(compressor.parent(level - 1)) + 1;
scope.body.splice(i, 0, make_node(AST_Var, fn, {
@@ -4343,17 +4585,6 @@ merge(Compressor.prototype, {
}
return expressions;
}
function flatten_body(stat) {
if (stat instanceof AST_Return) {
return stat.value;
} else if (stat instanceof AST_SimpleStatement) {
return make_node(AST_UnaryPrefix, stat, {
operator: "void",
expression: stat.body
});
}
}
});
OPT(AST_New, function(self, compressor){
@@ -5159,9 +5390,8 @@ merge(Compressor.prototype, {
if (reachable) return true;
if (node instanceof AST_Scope && node !== self) {
var parent = scan_scope.parent();
if (!(parent instanceof AST_Call && parent.expression === node)) {
node.walk(find_ref);
}
if (parent instanceof AST_Call && parent.expression === node) return;
node.walk(find_ref);
return true;
}
});
@@ -5595,6 +5825,14 @@ merge(Compressor.prototype, {
});
OPT(AST_Dot, function(self, compressor){
if (self.property == "arguments" || self.property == "caller") {
compressor.warn("Function.protoype.{prop} not supported [{file}:{line},{col}]", {
prop: self.property,
file: self.start.file,
line: self.start.line,
col: self.start.col
});
}
var def = self.resolve_defines(compressor);
if (def) {
return def.optimize(compressor);
@@ -5609,11 +5847,27 @@ merge(Compressor.prototype, {
elements: []
});
break;
case "Function":
self.expression = make_node(AST_Function, self.expression, {
argnames: [],
body: []
});
break;
case "Number":
self.expression = make_node(AST_Number, self.expression, {
value: 0
});
break;
case "Object":
self.expression = make_node(AST_Object, self.expression, {
properties: []
});
break;
case "RegExp":
self.expression = make_node(AST_RegExp, self.expression, {
value: /t/
});
break;
case "String":
self.expression = make_node(AST_String, self.expression, {
value: ""