harmony-v3.1.7
This commit is contained in:
190
lib/compress.js
190
lib/compress.js
@@ -291,7 +291,7 @@ merge(Compressor.prototype, {
|
|||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor) {
|
AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
|
||||||
var reduce_vars = compressor.option("reduce_vars");
|
var reduce_vars = compressor.option("reduce_vars");
|
||||||
var unused = compressor.option("unused");
|
var unused = compressor.option("unused");
|
||||||
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
||||||
@@ -322,12 +322,18 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
} else if (d.fixed) {
|
} else if (d.fixed) {
|
||||||
var value = node.fixed_value();
|
var value = node.fixed_value();
|
||||||
if (unused && !compressor.exposed(d)) {
|
if (unused && !compressor.exposed(d) && value && d.references.length == 1) {
|
||||||
d.single_use = value
|
if (value instanceof AST_Lambda) {
|
||||||
&& d.references.length == 1
|
d.single_use = d.scope === node.scope
|
||||||
&& loop_ids[d.id] === in_loop
|
&& !(d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
&& d.scope === node.scope
|
|| value.is_constant_expression(node.scope);
|
||||||
&& value.is_constant_expression();
|
} else {
|
||||||
|
d.single_use = d.scope === node.scope
|
||||||
|
&& loop_ids[d.id] === in_loop
|
||||||
|
&& value.is_constant_expression();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d.single_use = false;
|
||||||
}
|
}
|
||||||
if (is_modified(node, value, 0, is_immutable(value))) {
|
if (is_modified(node, value, 0, is_immutable(value))) {
|
||||||
if (d.single_use) {
|
if (d.single_use) {
|
||||||
@@ -390,6 +396,10 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
d.fixed = node;
|
d.fixed = node;
|
||||||
mark(d, true);
|
mark(d, true);
|
||||||
|
if (unused && d.references.length == 1) {
|
||||||
|
d.single_use = d.scope === d.references[0].scope
|
||||||
|
|| node.is_constant_expression(d.references[0].scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var save_ids = safe_ids;
|
var save_ids = safe_ids;
|
||||||
safe_ids = Object.create(null);
|
safe_ids = Object.create(null);
|
||||||
@@ -542,6 +552,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return def.fixed instanceof AST_Defun;
|
||||||
}
|
}
|
||||||
|
|
||||||
function safe_to_assign(def, value) {
|
function safe_to_assign(def, value) {
|
||||||
@@ -580,7 +591,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_immutable(value) {
|
function is_immutable(value) {
|
||||||
return value && (value.is_constant() || value instanceof AST_Lambda);
|
if (!value) return false;
|
||||||
|
return value.is_constant()
|
||||||
|
|| value instanceof AST_Lambda
|
||||||
|
|| value instanceof AST_This;
|
||||||
}
|
}
|
||||||
|
|
||||||
function read_property(obj, key) {
|
function read_property(obj, key) {
|
||||||
@@ -608,7 +622,7 @@ merge(Compressor.prototype, {
|
|||||||
|| !immutable
|
|| !immutable
|
||||||
&& parent instanceof AST_Call
|
&& parent instanceof AST_Call
|
||||||
&& parent.expression === node
|
&& parent.expression === node
|
||||||
&& (!(value instanceof AST_Function) || value.contains_this())) {
|
&& (!(value instanceof AST_Function) || value.contains_this(parent))) {
|
||||||
return true;
|
return true;
|
||||||
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
|
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
|
||||||
return is_modified(parent, parent, level + 1);
|
return is_modified(parent, parent, level + 1);
|
||||||
@@ -848,6 +862,7 @@ merge(Compressor.prototype, {
|
|||||||
function collapse(statements, compressor) {
|
function collapse(statements, compressor) {
|
||||||
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
|
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
|
||||||
if (scope.uses_eval || scope.uses_with) return statements;
|
if (scope.uses_eval || scope.uses_with) return statements;
|
||||||
|
var args;
|
||||||
var candidates = [];
|
var candidates = [];
|
||||||
var stat_index = statements.length;
|
var stat_index = statements.length;
|
||||||
while (--stat_index >= 0) {
|
while (--stat_index >= 0) {
|
||||||
@@ -868,7 +883,7 @@ merge(Compressor.prototype, {
|
|||||||
var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
|
var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
|
||||||
var side_effects = value_has_side_effects(candidate);
|
var side_effects = value_has_side_effects(candidate);
|
||||||
var hit = candidate.name instanceof AST_SymbolFunarg;
|
var hit = candidate.name instanceof AST_SymbolFunarg;
|
||||||
var abort = false, replaced = false;
|
var abort = false, replaced = false, can_replace = !args || !hit;
|
||||||
var tt = new TreeTransformer(function(node, descend) {
|
var tt = new TreeTransformer(function(node, descend) {
|
||||||
if (abort) return node;
|
if (abort) return node;
|
||||||
// Skip nodes before `candidate` as quickly as possible
|
// Skip nodes before `candidate` as quickly as possible
|
||||||
@@ -895,7 +910,8 @@ merge(Compressor.prototype, {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
// Replace variable with assignment when found
|
// Replace variable with assignment when found
|
||||||
if (!(node instanceof AST_SymbolDeclaration)
|
if (can_replace
|
||||||
|
&& !(node instanceof AST_SymbolDeclaration)
|
||||||
&& !is_lhs(node, parent)
|
&& !is_lhs(node, parent)
|
||||||
&& lhs.equivalent_to(node)) {
|
&& lhs.equivalent_to(node)) {
|
||||||
CHANGED = replaced = abort = true;
|
CHANGED = replaced = abort = true;
|
||||||
@@ -946,6 +962,12 @@ merge(Compressor.prototype, {
|
|||||||
// Skip (non-executed) functions and (leading) default case in switch statements
|
// Skip (non-executed) functions and (leading) default case in switch statements
|
||||||
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
||||||
});
|
});
|
||||||
|
if (!can_replace) {
|
||||||
|
for (var j = compressor.self().argnames.lastIndexOf(candidate.__name || candidate.name) + 1; j < args.length; j++) {
|
||||||
|
args[j].transform(tt);
|
||||||
|
}
|
||||||
|
can_replace = true;
|
||||||
|
}
|
||||||
for (var i = stat_index; !abort && i < statements.length; i++) {
|
for (var i = stat_index; !abort && i < statements.length; i++) {
|
||||||
statements[i].transform(tt);
|
statements[i].transform(tt);
|
||||||
}
|
}
|
||||||
@@ -991,9 +1013,16 @@ merge(Compressor.prototype, {
|
|||||||
})) {
|
})) {
|
||||||
var fn_strict = compressor.has_directive("use strict");
|
var fn_strict = compressor.has_directive("use strict");
|
||||||
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
||||||
|
var len = fn.argnames.length;
|
||||||
|
args = iife.args.slice(len);
|
||||||
var names = Object.create(null);
|
var names = Object.create(null);
|
||||||
for (var i = fn.argnames.length; --i >= 0;) {
|
for (var i = len; --i >= 0;) {
|
||||||
var sym = fn.argnames[i];
|
var sym = fn.argnames[i];
|
||||||
|
var arg = iife.args[i];
|
||||||
|
args.unshift(make_node(AST_VarDef, sym, {
|
||||||
|
name: sym,
|
||||||
|
value: arg
|
||||||
|
}));
|
||||||
if (sym.name in names) continue;
|
if (sym.name in names) continue;
|
||||||
names[sym.name] = true;
|
names[sym.name] = true;
|
||||||
if (sym instanceof AST_Expansion) {
|
if (sym instanceof AST_Expansion) {
|
||||||
@@ -1007,9 +1036,9 @@ merge(Compressor.prototype, {
|
|||||||
elements: elements
|
elements: elements
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
candidates[0].__name = sym;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var arg = iife.args[i];
|
|
||||||
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
|
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
|
||||||
else if (has_overlapping_symbol(fn, arg, fn_strict)) arg = null;
|
else if (has_overlapping_symbol(fn, arg, fn_strict)) arg = null;
|
||||||
if (arg) candidates.unshift(make_node(AST_VarDef, sym, {
|
if (arg) candidates.unshift(make_node(AST_VarDef, sym, {
|
||||||
@@ -2265,18 +2294,22 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
def(AST_Node, return_false);
|
def(AST_Node, return_false);
|
||||||
def(AST_Constant, return_true);
|
def(AST_Constant, return_true);
|
||||||
def(AST_Function, function(){
|
def(AST_Lambda, function(scope){
|
||||||
var self = this;
|
var self = this;
|
||||||
var result = true;
|
var result = true;
|
||||||
self.walk(new TreeWalker(function(node) {
|
self.walk(new TreeWalker(function(node) {
|
||||||
if (!result) return true;
|
if (!result) return true;
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
if (self.enclosed.indexOf(def) >= 0
|
if (member(def, self.enclosed)
|
||||||
&& self.variables.get(def.name) !== def) {
|
&& !self.variables.has(def.name)) {
|
||||||
|
if (scope) {
|
||||||
|
var scope_def = scope.find_variable(node);
|
||||||
|
if (def.undeclared ? !scope_def : scope_def === def) return true;
|
||||||
|
}
|
||||||
result = false;
|
result = false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
return result;
|
return result;
|
||||||
@@ -2439,8 +2472,11 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (assign_as_unused(node) instanceof AST_SymbolRef && scope === self
|
var sym;
|
||||||
&& !is_ref_of(node.left, AST_SymbolBlockDeclaration)) {
|
if (scope === self
|
||||||
|
&& (sym = assign_as_unused(node)) 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);
|
if (node instanceof AST_Assign) node.right.walk(tw);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2526,9 +2562,11 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
|
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
|
||||||
var keep = (node.name.definition().id in in_use_ids) || !drop_funcs && node.name.definition().global;
|
var def = node.name.definition();
|
||||||
|
var keep = (def.id in in_use_ids) || !drop_funcs && def.global;
|
||||||
if (!keep) {
|
if (!keep) {
|
||||||
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
||||||
|
drop_decl(def, node.name);
|
||||||
return make_node(AST_EmptyStatement, node);
|
return make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
@@ -2553,7 +2591,7 @@ merge(Compressor.prototype, {
|
|||||||
if (var_defs.length > 1 && !def.value) {
|
if (var_defs.length > 1 && !def.value) {
|
||||||
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
remove(var_defs, def);
|
remove(var_defs, def);
|
||||||
remove(sym.orig, def.name);
|
drop_decl(sym, def.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2586,7 +2624,7 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
|
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
}
|
}
|
||||||
remove(sym.orig, def.name);
|
drop_decl(sym, def.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
|
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
|
||||||
@@ -2595,7 +2633,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = tail.pop();
|
var def = tail.pop();
|
||||||
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
|
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
|
||||||
remove(var_defs, def);
|
remove(var_defs, def);
|
||||||
remove(def.name.definition().orig, def.name);
|
drop_decl(def.name.definition(), def.name);
|
||||||
side_effects.unshift(make_node(AST_Assign, def, {
|
side_effects.unshift(make_node(AST_Assign, def, {
|
||||||
operator: "=",
|
operator: "=",
|
||||||
left: make_node(AST_SymbolRef, def.name, def.name),
|
left: make_node(AST_SymbolRef, def.name, def.name),
|
||||||
@@ -2627,8 +2665,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = assign_as_unused(node);
|
var def = assign_as_unused(node);
|
||||||
if (def instanceof AST_SymbolRef
|
if (def instanceof AST_SymbolRef
|
||||||
&& !((def = def.definition()).id in in_use_ids)
|
&& !((def = def.definition()).id in in_use_ids)
|
||||||
&& (drop_vars || !def.global)
|
&& (drop_vars || !def.global)) {
|
||||||
&& self.variables.get(def.name) === def) {
|
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
return maintain_this_binding(parent, node, node.right.transform(tt));
|
return maintain_this_binding(parent, node, node.right.transform(tt));
|
||||||
}
|
}
|
||||||
@@ -2685,6 +2722,14 @@ merge(Compressor.prototype, {
|
|||||||
col : sym.start.col
|
col : sym.start.col
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function drop_decl(def, decl) {
|
||||||
|
remove(def.orig, decl);
|
||||||
|
if (!def.orig.length) {
|
||||||
|
def.scope.functions.del(def.name);
|
||||||
|
def.scope.variables.del(def.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
@@ -4456,46 +4501,53 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& fixed
|
&& fixed
|
||||||
&& d.references.length == 1
|
&& d.references.length == 1
|
||||||
&& (d.single_use || is_func_expr(fixed)
|
&& d.single_use) {
|
||||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
|
||||||
&& !d.scope.uses_eval
|
|
||||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope)) {
|
|
||||||
var value = fixed.optimize(compressor);
|
var value = fixed.optimize(compressor);
|
||||||
return value === fixed ? fixed.clone(true) : value;
|
return value === fixed ? fixed.clone(true) : value;
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate") && fixed) {
|
if (fixed && d.should_replace === undefined) {
|
||||||
if (d.should_replace === undefined) {
|
var init;
|
||||||
var init = fixed.evaluate(compressor);
|
if (fixed instanceof AST_This) {
|
||||||
if (init !== fixed && (compressor.option("unsafe_regexp") || !(init instanceof RegExp))) {
|
if (!(d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
init = make_node_from_constant(init, fixed);
|
&& all(d.references, function(ref) {
|
||||||
var value_length = init.optimize(compressor).print_to_string().length;
|
return d.scope === ref.scope;
|
||||||
var fn;
|
})) {
|
||||||
if (has_symbol_ref(fixed)) {
|
init = fixed;
|
||||||
fn = function() {
|
}
|
||||||
var result = init.optimize(compressor);
|
} else {
|
||||||
return result === init ? result.clone(true) : result;
|
var ev = fixed.evaluate(compressor);
|
||||||
};
|
if (ev !== fixed && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))) {
|
||||||
} else {
|
init = make_node_from_constant(ev, fixed);
|
||||||
value_length = Math.min(value_length, fixed.print_to_string().length);
|
|
||||||
fn = function() {
|
|
||||||
var result = best_of_expression(init.optimize(compressor), fixed);
|
|
||||||
return result === init || result === fixed ? result.clone(true) : result;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var name_length = d.name.length;
|
|
||||||
var overhead = 0;
|
|
||||||
if (compressor.option("unused") && !compressor.exposed(d)) {
|
|
||||||
overhead = (name_length + 2 + value_length) / d.references.length;
|
|
||||||
}
|
|
||||||
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
|
||||||
} else {
|
|
||||||
d.should_replace = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (d.should_replace) {
|
if (init) {
|
||||||
return d.should_replace();
|
var value_length = init.optimize(compressor).print_to_string().length;
|
||||||
|
var fn;
|
||||||
|
if (has_symbol_ref(fixed)) {
|
||||||
|
fn = function() {
|
||||||
|
var result = init.optimize(compressor);
|
||||||
|
return result === init ? result.clone(true) : result;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
value_length = Math.min(value_length, fixed.print_to_string().length);
|
||||||
|
fn = function() {
|
||||||
|
var result = best_of_expression(init.optimize(compressor), fixed);
|
||||||
|
return result === init || result === fixed ? result.clone(true) : result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var name_length = d.name.length;
|
||||||
|
var overhead = 0;
|
||||||
|
if (compressor.option("unused") && !compressor.exposed(d)) {
|
||||||
|
overhead = (name_length + 2 + value_length) / d.references.length;
|
||||||
|
}
|
||||||
|
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
||||||
|
} else {
|
||||||
|
d.should_replace = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (d.should_replace) {
|
||||||
|
return d.should_replace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
@@ -4832,11 +4884,11 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_lhs(self, compressor.parent())) return self;
|
if (is_lhs(self, compressor.parent())) return self;
|
||||||
if (compressor.option("properties") && key !== prop) {
|
if (key !== prop) {
|
||||||
var node = self.flatten_object(property, compressor);
|
var sub = self.flatten_object(property, compressor);
|
||||||
if (node) {
|
if (sub) {
|
||||||
expr = self.expression = node.expression;
|
expr = self.expression = sub.expression;
|
||||||
prop = self.property = node.property;
|
prop = self.property = sub.property;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("properties") && compressor.option("side_effects")
|
if (compressor.option("properties") && compressor.option("side_effects")
|
||||||
@@ -4882,7 +4934,8 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("contains_this", function() {
|
AST_Lambda.DEFMETHOD("contains_this", function(grandparent) {
|
||||||
|
if (grandparent instanceof AST_New) return false;
|
||||||
var result;
|
var result;
|
||||||
var self = this;
|
var self = this;
|
||||||
self.walk(new TreeWalker(function(node) {
|
self.walk(new TreeWalker(function(node) {
|
||||||
@@ -4894,6 +4947,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
|
AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
|
||||||
|
if (!compressor.option("properties")) return;
|
||||||
var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 6;
|
var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 6;
|
||||||
var expr = this.expression;
|
var expr = this.expression;
|
||||||
if (expr instanceof AST_Object) {
|
if (expr instanceof AST_Object) {
|
||||||
@@ -4907,7 +4961,7 @@ merge(Compressor.prototype, {
|
|||||||
})) break;
|
})) break;
|
||||||
var value = prop.value;
|
var value = prop.value;
|
||||||
if ((value instanceof AST_Accessor || value instanceof AST_Function)
|
if ((value instanceof AST_Accessor || value instanceof AST_Function)
|
||||||
&& value.contains_this()) break;
|
&& value.contains_this(compressor.parent())) break;
|
||||||
return make_node(AST_Sub, this, {
|
return make_node(AST_Sub, this, {
|
||||||
expression: make_node(AST_Array, expr, {
|
expression: make_node(AST_Array, expr, {
|
||||||
elements: props.map(function(prop) {
|
elements: props.map(function(prop) {
|
||||||
@@ -4957,10 +5011,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_lhs(self, compressor.parent())) return self;
|
if (is_lhs(self, compressor.parent())) return self;
|
||||||
if (compressor.option("properties")) {
|
var sub = self.flatten_object(self.property, compressor);
|
||||||
var node = self.flatten_object(self.property, compressor);
|
if (sub) return sub.optimize(compressor);
|
||||||
if (node) return node.optimize(compressor);
|
|
||||||
}
|
|
||||||
var ev = self.evaluate(compressor);
|
var ev = self.evaluate(compressor);
|
||||||
if (ev !== self) {
|
if (ev !== self) {
|
||||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.1.6",
|
"version": "3.1.7",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -314,17 +314,12 @@ issue_2105_1: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(() => {
|
({
|
||||||
var quux = () => {
|
prop() {
|
||||||
|
console.log;
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
};
|
}
|
||||||
return {
|
}).prop();
|
||||||
prop() {
|
|
||||||
console.log;
|
|
||||||
quux();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})().prop();
|
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
@@ -360,17 +355,12 @@ issue_2105_2: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(() => {
|
({
|
||||||
var quux = () => {
|
prop: () => {
|
||||||
|
console.log;
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
};
|
}
|
||||||
return {
|
}).prop();
|
||||||
prop: () => {
|
|
||||||
console.log;
|
|
||||||
quux();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})().prop();
|
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
|
|||||||
@@ -3223,3 +3223,69 @@ conditional_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "5 5"
|
expect_stdout: "5 5"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2425_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "15"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2425_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b, c) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b, c) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "15"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2425_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b, b) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b, b) {
|
||||||
|
(a |= 10).toString();
|
||||||
|
})(--a);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "15"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1294,11 +1294,11 @@ issue_2063: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_2105: {
|
issue_2105_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 3,
|
passes: 2,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -1324,17 +1324,50 @@ issue_2105: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function() {
|
({
|
||||||
var quux = function() {
|
prop: function() {
|
||||||
|
console.log;
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
};
|
}
|
||||||
return {
|
}).prop();
|
||||||
prop: function() {
|
}
|
||||||
console.log;
|
expect_stdout: "PASS"
|
||||||
quux();
|
}
|
||||||
|
|
||||||
|
issue_2105_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function(factory) {
|
||||||
|
factory();
|
||||||
|
}( function() {
|
||||||
|
return function(fn) {
|
||||||
|
fn()().prop();
|
||||||
|
}( function() {
|
||||||
|
function bar() {
|
||||||
|
var quux = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}, foo = function() {
|
||||||
|
console.log;
|
||||||
|
quux();
|
||||||
|
};
|
||||||
|
return { prop: foo };
|
||||||
}
|
}
|
||||||
};
|
return bar;
|
||||||
})().prop();
|
} );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -483,3 +483,31 @@ hoist_function_with_call: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "Foo true 10 20"
|
expect_stdout: "Foo true 10 20"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_this: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
f: function(a) {
|
||||||
|
this.b = a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(new o.f(o.a).b, o.b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(new function(a) {
|
||||||
|
this.b = a;
|
||||||
|
}(1).b, 2);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1282,3 +1282,22 @@ computed_property: {
|
|||||||
]
|
]
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_this: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
new {
|
||||||
|
f: function(a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
}.f(42);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
new function(a) {
|
||||||
|
this.a = a;
|
||||||
|
}(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3537,3 +3537,293 @@ escaped_prop: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "2"
|
expect_stdout: "2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2420_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function run() {
|
||||||
|
var self = this;
|
||||||
|
if (self.count++)
|
||||||
|
self.foo();
|
||||||
|
else
|
||||||
|
self.bar();
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
count: 0,
|
||||||
|
foo: function() { console.log("foo"); },
|
||||||
|
bar: function() { console.log("bar"); },
|
||||||
|
};
|
||||||
|
run.call(o);
|
||||||
|
run.call(o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function run() {
|
||||||
|
if (this.count++)
|
||||||
|
this.foo();
|
||||||
|
else
|
||||||
|
this.bar();
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
count: 0,
|
||||||
|
foo: function() { console.log("foo"); },
|
||||||
|
bar: function() { console.log("bar"); },
|
||||||
|
};
|
||||||
|
run.call(o);
|
||||||
|
run.call(o);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"bar",
|
||||||
|
"foo",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2420_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var that = this;
|
||||||
|
if (that.bar)
|
||||||
|
that.foo();
|
||||||
|
else
|
||||||
|
!function(that, self) {
|
||||||
|
console.log(this === that, self === this, that === self);
|
||||||
|
}(that, this);
|
||||||
|
}
|
||||||
|
f.call({
|
||||||
|
bar: 1,
|
||||||
|
foo: function() { console.log("foo", this.bar); },
|
||||||
|
});
|
||||||
|
f.call({});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
if (this.bar)
|
||||||
|
this.foo();
|
||||||
|
else
|
||||||
|
!function(that, self) {
|
||||||
|
console.log(this === that, self === this, that === self);
|
||||||
|
}(this, this);
|
||||||
|
}
|
||||||
|
f.call({
|
||||||
|
bar: 1,
|
||||||
|
foo: function() { console.log("foo", this.bar); },
|
||||||
|
});
|
||||||
|
f.call({});
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo 1",
|
||||||
|
"false false true",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2420_3: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var that = this;
|
||||||
|
if (that.bar)
|
||||||
|
that.foo();
|
||||||
|
else
|
||||||
|
((that, self) => {
|
||||||
|
console.log(this === that, self === this, that === self);
|
||||||
|
})(that, this);
|
||||||
|
}
|
||||||
|
f.call({
|
||||||
|
bar: 1,
|
||||||
|
foo: function() { console.log("foo", this.bar); },
|
||||||
|
});
|
||||||
|
f.call({});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
if (this.bar)
|
||||||
|
this.foo();
|
||||||
|
else
|
||||||
|
((that, self) => {
|
||||||
|
console.log(this === that, self === this, that === self);
|
||||||
|
})(this, this);
|
||||||
|
}
|
||||||
|
f.call({
|
||||||
|
bar: 1,
|
||||||
|
foo: function() { console.log("foo", this.bar); },
|
||||||
|
});
|
||||||
|
f.call({});
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo 1",
|
||||||
|
"true true true",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2423_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function c() { return 1; }
|
||||||
|
function p() { console.log(c()); }
|
||||||
|
p();
|
||||||
|
p();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function p() { console.log(function() { return 1; }()); }
|
||||||
|
p();
|
||||||
|
p();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2423_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function c() { return 1; }
|
||||||
|
function p() { console.log(c()); }
|
||||||
|
p();
|
||||||
|
p();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function p() { console.log(1); }
|
||||||
|
p();
|
||||||
|
p();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2423_3: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function c() { return 1; }
|
||||||
|
function p() { console.log(c()); }
|
||||||
|
p();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() { console.log(function() { return 1; }()); })();
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2423_4: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function c() { return 1; }
|
||||||
|
function p() { console.log(c()); }
|
||||||
|
p();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2423_5: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
y();
|
||||||
|
}
|
||||||
|
function y() {
|
||||||
|
console.log(1);
|
||||||
|
}
|
||||||
|
function z() {
|
||||||
|
function y() {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
z();
|
||||||
|
z();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function z() {
|
||||||
|
console.log(1);
|
||||||
|
}
|
||||||
|
z();
|
||||||
|
z();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2423_6: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
y();
|
||||||
|
}
|
||||||
|
function y() {
|
||||||
|
console.log(1);
|
||||||
|
}
|
||||||
|
function z() {
|
||||||
|
function y() {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
x();
|
||||||
|
y();
|
||||||
|
}
|
||||||
|
z();
|
||||||
|
z();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function z(){
|
||||||
|
console.log(1);
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
z();
|
||||||
|
z();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ var VALUES = [
|
|||||||
'"object"',
|
'"object"',
|
||||||
'"number"',
|
'"number"',
|
||||||
'"function"',
|
'"function"',
|
||||||
|
'this',
|
||||||
];
|
];
|
||||||
|
|
||||||
var BINARY_OPS_NO_COMMA = [
|
var BINARY_OPS_NO_COMMA = [
|
||||||
@@ -349,10 +350,10 @@ function createParams() {
|
|||||||
return params.join(', ');
|
return params.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
function createArgs() {
|
function createArgs(recurmax, stmtDepth, canThrow) {
|
||||||
var args = [];
|
var args = [];
|
||||||
for (var n = rng(4); --n >= 0;) {
|
for (var n = rng(4); --n >= 0;) {
|
||||||
args.push(createValue());
|
args.push(rng(2) ? createValue() : createExpression(recurmax - 1, COMMA_OK, stmtDepth, canThrow));
|
||||||
}
|
}
|
||||||
return args.join(', ');
|
return args.join(', ');
|
||||||
}
|
}
|
||||||
@@ -390,9 +391,10 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
|
|||||||
|
|
||||||
VAR_NAMES.length = namesLenBefore;
|
VAR_NAMES.length = namesLenBefore;
|
||||||
|
|
||||||
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s + '(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ');';
|
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s;
|
||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');';
|
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name;
|
||||||
|
s += '(' + createArgs(recurmax, stmtDepth, canThrow) + ');';
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -626,6 +628,9 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
return createValue();
|
return createValue();
|
||||||
|
case p++:
|
||||||
|
case p++:
|
||||||
|
return getVarName();
|
||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
|
|||||||
Reference in New Issue
Block a user