enhance functions & reduce_vars (#5045)
This commit is contained in:
333
lib/compress.js
333
lib/compress.js
@@ -484,9 +484,21 @@ merge(Compressor.prototype, {
|
|||||||
def.single_use = undefined;
|
def.single_use = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset_variables(tw, compressor, scope) {
|
function reset_block_variables(tw, compressor, scope) {
|
||||||
scope.variables.each(function(def) {
|
scope.variables.each(function(def) {
|
||||||
reset_def(tw, compressor, def);
|
reset_def(tw, compressor, def);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset_variables(tw, compressor, scope) {
|
||||||
|
scope.fn_defs = [];
|
||||||
|
scope.variables.each(function(def) {
|
||||||
|
reset_def(tw, compressor, def);
|
||||||
|
var init = def.init;
|
||||||
|
if (init instanceof AST_LambdaDefinition) {
|
||||||
|
scope.fn_defs.push(init);
|
||||||
|
init.safe_ids = null;
|
||||||
|
}
|
||||||
if (def.fixed === null) {
|
if (def.fixed === null) {
|
||||||
def.safe_ids = tw.safe_ids;
|
def.safe_ids = tw.safe_ids;
|
||||||
mark(tw, def);
|
mark(tw, def);
|
||||||
@@ -496,13 +508,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
scope.may_call_this = function() {
|
scope.may_call_this = function() {
|
||||||
scope.may_call_this = noop;
|
scope.may_call_this = scope.contains_this() ? return_true : return_false;
|
||||||
if (!scope.contains_this()) return;
|
|
||||||
scope.functions.each(function(def) {
|
|
||||||
if (def.init instanceof AST_LambdaDefinition && !(def.id in tw.defun_ids)) {
|
|
||||||
tw.defun_ids[def.id] = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
if (scope.uses_arguments) scope.each_argname(function(node) {
|
if (scope.uses_arguments) scope.each_argname(function(node) {
|
||||||
node.definition().last_ref = false;
|
node.definition().last_ref = false;
|
||||||
@@ -513,39 +519,56 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function mark_defun(tw, def) {
|
function mark_fn_def(tw, def, fn) {
|
||||||
if (def.id in tw.defun_ids) {
|
if (!HOP(fn, "safe_ids")) return;
|
||||||
var marker = tw.defun_ids[def.id];
|
var marker = fn.safe_ids;
|
||||||
if (!marker) return;
|
if (marker === false) return;
|
||||||
var visited = tw.defun_visited[def.id];
|
if (fn.parent_scope.resolve().may_call_this === return_true) return;
|
||||||
if (marker === tw.safe_ids) return !visited && def.fixed;
|
if (marker) {
|
||||||
|
var visited = member(fn, tw.fn_visited);
|
||||||
|
if (marker === tw.safe_ids) return !visited && fn;
|
||||||
if (visited) {
|
if (visited) {
|
||||||
def.init.enclosed.forEach(function(d) {
|
fn.enclosed.forEach(function(d) {
|
||||||
if (def.init.variables.get(d.name) === d) return;
|
if (fn.variables.get(d.name) === d) return;
|
||||||
if (!safe_to_read(tw, d)) d.fixed = false;
|
if (safe_to_read(tw, d)) return;
|
||||||
|
d.single_use = false;
|
||||||
|
if (d.fixed instanceof AST_LambdaDefinition) return;
|
||||||
|
d.fixed = false;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (!tw.in_loop) {
|
} else if (!tw.in_loop && !(tw.fn_scanning && tw.fn_scanning !== def.scope.resolve())) {
|
||||||
var scope = def.scope;
|
fn.safe_ids = tw.safe_ids;
|
||||||
var s = tw.find_parent(AST_Scope);
|
return fn;
|
||||||
do {
|
|
||||||
if (s === scope) {
|
|
||||||
tw.defun_ids[def.id] = tw.safe_ids;
|
|
||||||
return def.fixed;
|
|
||||||
}
|
}
|
||||||
} while (s instanceof AST_LambdaExpression && (s = s.parent_scope.resolve()));
|
fn.safe_ids = false;
|
||||||
}
|
|
||||||
tw.defun_ids[def.id] = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function walk_defuns(tw, scope) {
|
function walk_fn_def(tw, fn) {
|
||||||
scope.functions.each(function(def) {
|
var was_scanning = tw.fn_scanning;
|
||||||
if (def.init instanceof AST_LambdaDefinition && !tw.defun_visited[def.id]) {
|
tw.fn_scanning = fn;
|
||||||
tw.defun_ids[def.id] = tw.safe_ids;
|
fn.walk(tw);
|
||||||
def.init.walk(tw);
|
tw.fn_scanning = was_scanning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pop_scope(tw, scope) {
|
||||||
|
var fn_defs = scope.fn_defs;
|
||||||
|
var tangled = scope.may_call_this === return_true ? fn_defs : fn_defs.filter(function(fn) {
|
||||||
|
if (fn.safe_ids === false) return true;
|
||||||
|
fn.safe_ids = tw.safe_ids;
|
||||||
|
walk_fn_def(tw, fn);
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
pop(tw);
|
||||||
|
tangled.forEach(function(fn) {
|
||||||
|
fn.safe_ids = tw.safe_ids;
|
||||||
|
walk_fn_def(tw, fn);
|
||||||
|
});
|
||||||
|
fn_defs.forEach(function(fn) {
|
||||||
|
delete fn.safe_ids;
|
||||||
|
});
|
||||||
|
delete scope.fn_defs;
|
||||||
|
delete scope.may_call_this;
|
||||||
}
|
}
|
||||||
|
|
||||||
function push(tw) {
|
function push(tw) {
|
||||||
@@ -592,13 +615,13 @@ merge(Compressor.prototype, {
|
|||||||
if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
|
if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolLet);
|
return !(sym instanceof AST_SymbolLet);
|
||||||
});
|
});
|
||||||
if (def.fixed === null && def.safe_ids) {
|
|
||||||
def.safe_ids[def.id] = false;
|
|
||||||
delete def.safe_ids;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (def.fixed === false) return false;
|
if (def.fixed === false) return false;
|
||||||
var safe = tw.safe_ids[def.id];
|
var safe = tw.safe_ids[def.id];
|
||||||
|
if (def.safe_ids) {
|
||||||
|
def.safe_ids[def.id] = false;
|
||||||
|
delete def.safe_ids;
|
||||||
|
return def.fixed === null || HOP(tw.safe_ids, def.id) && !safe.read;
|
||||||
|
}
|
||||||
if (!HOP(tw.safe_ids, def.id)) {
|
if (!HOP(tw.safe_ids, def.id)) {
|
||||||
if (!safe) return false;
|
if (!safe) return false;
|
||||||
if (safe.read) {
|
if (safe.read) {
|
||||||
@@ -813,8 +836,7 @@ merge(Compressor.prototype, {
|
|||||||
}, visit);
|
}, visit);
|
||||||
walk_lambda(fn, tw);
|
walk_lambda(fn, tw);
|
||||||
var safe_ids = tw.safe_ids;
|
var safe_ids = tw.safe_ids;
|
||||||
pop(tw);
|
pop_scope(tw, fn);
|
||||||
walk_defuns(tw, fn);
|
|
||||||
if (!aborts) tw.safe_ids = safe_ids;
|
if (!aborts) tw.safe_ids = safe_ids;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -835,7 +857,8 @@ merge(Compressor.prototype, {
|
|||||||
var node = this;
|
var node = this;
|
||||||
var left = node.left;
|
var left = node.left;
|
||||||
var right = node.right;
|
var right = node.right;
|
||||||
var scan = left instanceof AST_Destructured || left instanceof AST_SymbolRef;
|
var ld = left instanceof AST_SymbolRef && left.definition();
|
||||||
|
var scan = ld || left instanceof AST_Destructured;
|
||||||
switch (node.operator) {
|
switch (node.operator) {
|
||||||
case "=":
|
case "=":
|
||||||
if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
|
if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
|
||||||
@@ -844,7 +867,17 @@ merge(Compressor.prototype, {
|
|||||||
node.__drop = true;
|
node.__drop = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (scan) {
|
if (ld && right instanceof AST_LambdaExpression) {
|
||||||
|
walk_assign();
|
||||||
|
if (ld.escaped.length) {
|
||||||
|
right.walk(tw);
|
||||||
|
} else {
|
||||||
|
right.parent_scope.resolve().fn_defs.push(right);
|
||||||
|
right.safe_ids = null;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (scan) {
|
||||||
|
right.walk(tw);
|
||||||
walk_assign();
|
walk_assign();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -856,6 +889,7 @@ merge(Compressor.prototype, {
|
|||||||
left.walk(tw);
|
left.walk(tw);
|
||||||
push(tw);
|
push(tw);
|
||||||
if (scan) {
|
if (scan) {
|
||||||
|
right.walk(tw);
|
||||||
walk_assign();
|
walk_assign();
|
||||||
} else {
|
} else {
|
||||||
mark_assignment_to_arguments(left);
|
mark_assignment_to_arguments(left);
|
||||||
@@ -868,20 +902,19 @@ merge(Compressor.prototype, {
|
|||||||
mark_assignment_to_arguments(left);
|
mark_assignment_to_arguments(left);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var d = left.definition();
|
ld.assignments++;
|
||||||
d.assignments++;
|
var fixed = ld.fixed;
|
||||||
var fixed = d.fixed;
|
|
||||||
if (is_modified(compressor, tw, node, node, 0)) {
|
if (is_modified(compressor, tw, node, node, 0)) {
|
||||||
d.fixed = false;
|
ld.fixed = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var safe = safe_to_read(tw, d);
|
var safe = safe_to_read(tw, ld);
|
||||||
right.walk(tw);
|
right.walk(tw);
|
||||||
if (safe && !left.in_arg && safe_to_assign(tw, d)) {
|
if (safe && !left.in_arg && safe_to_assign(tw, ld)) {
|
||||||
push_ref(d, left);
|
push_ref(ld, left);
|
||||||
mark(tw, d);
|
mark(tw, ld);
|
||||||
if (d.single_use) d.single_use = false;
|
if (ld.single_use) ld.single_use = false;
|
||||||
left.fixed = d.fixed = function() {
|
left.fixed = ld.fixed = function() {
|
||||||
return make_node(AST_Binary, node, {
|
return make_node(AST_Binary, node, {
|
||||||
operator: node.operator.slice(0, -1),
|
operator: node.operator.slice(0, -1),
|
||||||
left: make_ref(left, fixed),
|
left: make_ref(left, fixed),
|
||||||
@@ -892,7 +925,7 @@ merge(Compressor.prototype, {
|
|||||||
left.fixed.assigns.push(node);
|
left.fixed.assigns.push(node);
|
||||||
} else {
|
} else {
|
||||||
left.walk(tw);
|
left.walk(tw);
|
||||||
d.fixed = false;
|
ld.fixed = false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -920,8 +953,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function walk_assign() {
|
function walk_assign() {
|
||||||
right.walk(tw);
|
var recursive = ld && recursive_ref(tw, ld);
|
||||||
var modified = is_modified(compressor, tw, node, right, 0, is_immutable(right), recursive_ref(tw, d));
|
var modified = is_modified(compressor, tw, node, right, 0, is_immutable(right), recursive);
|
||||||
scan_declaration(tw, compressor, left, function() {
|
scan_declaration(tw, compressor, left, function() {
|
||||||
return node.right;
|
return node.right;
|
||||||
}, function(sym, fixed, walk) {
|
}, function(sym, fixed, walk) {
|
||||||
@@ -956,9 +989,7 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_BlockScope, function(tw, descend, compressor) {
|
def(AST_BlockScope, function(tw, descend, compressor) {
|
||||||
this.variables.each(function(def) {
|
reset_block_variables(tw, compressor, this);
|
||||||
reset_def(tw, compressor, def);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
def(AST_Call, function(tw, descend) {
|
def(AST_Call, function(tw, descend) {
|
||||||
var node = this;
|
var node = this;
|
||||||
@@ -969,43 +1000,43 @@ merge(Compressor.prototype, {
|
|||||||
arg.walk(tw);
|
arg.walk(tw);
|
||||||
if (arg instanceof AST_Spread) iife = false;
|
if (arg instanceof AST_Spread) iife = false;
|
||||||
});
|
});
|
||||||
if (iife) exp.reduce_vars = reduce_iife;
|
if (iife) {
|
||||||
|
exp.reduce_vars = reduce_iife;
|
||||||
|
} else {
|
||||||
|
exp.safe_ids = tw.safe_ids;
|
||||||
|
}
|
||||||
exp.walk(tw);
|
exp.walk(tw);
|
||||||
if (iife) delete exp.reduce_vars;
|
if (iife) delete exp.reduce_vars;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var def = exp instanceof AST_SymbolRef && exp.definition();
|
|
||||||
if (node.TYPE == "Call" && tw.in_boolean_context()) {
|
if (node.TYPE == "Call" && tw.in_boolean_context()) {
|
||||||
if (def) {
|
if (exp instanceof AST_SymbolRef) {
|
||||||
def.bool_fn++;
|
exp.definition().bool_fn++;
|
||||||
} else if (exp instanceof AST_Assign && exp.operator == "=" && exp.left instanceof AST_SymbolRef) {
|
} else if (exp instanceof AST_Assign && exp.operator == "=" && exp.left instanceof AST_SymbolRef) {
|
||||||
exp.left.definition().bool_fn++;
|
exp.left.definition().bool_fn++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (def && def.fixed instanceof AST_LambdaDefinition) {
|
exp.walk(tw);
|
||||||
var defun = mark_defun(tw, def);
|
var fixed = exp instanceof AST_SymbolRef && exp.fixed_value();
|
||||||
if (defun) {
|
var optional = node.optional;
|
||||||
descend();
|
var fn;
|
||||||
defun.walk(tw);
|
if (fixed instanceof AST_Lambda) {
|
||||||
return true;
|
fn = mark_fn_def(tw, exp.definition(), fixed);
|
||||||
}
|
optional = false;
|
||||||
} else {
|
} else {
|
||||||
tw.find_parent(AST_Scope).may_call_this();
|
tw.find_parent(AST_Scope).may_call_this();
|
||||||
}
|
}
|
||||||
if (!node.optional) return;
|
if (optional) push(tw);
|
||||||
exp.walk(tw);
|
|
||||||
push(tw);
|
|
||||||
node.args.forEach(function(arg) {
|
node.args.forEach(function(arg) {
|
||||||
arg.walk(tw);
|
arg.walk(tw);
|
||||||
});
|
});
|
||||||
pop(tw);
|
if (optional) pop(tw);
|
||||||
|
if (fn) walk_fn_def(tw, fn);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Class, function(tw, descend, compressor) {
|
def(AST_Class, function(tw, descend, compressor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
node.variables.each(function(def) {
|
reset_block_variables(tw, compressor, node);
|
||||||
reset_def(tw, compressor, def);
|
|
||||||
});
|
|
||||||
if (node.extends) node.extends.walk(tw);
|
if (node.extends) node.extends.walk(tw);
|
||||||
var props = node.properties.filter(function(prop) {
|
var props = node.properties.filter(function(prop) {
|
||||||
reset_flags(prop);
|
reset_flags(prop);
|
||||||
@@ -1057,7 +1088,7 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Do, function(tw) {
|
def(AST_Do, function(tw) {
|
||||||
var saved_loop = tw.in_loop;
|
var save_loop = tw.in_loop;
|
||||||
tw.in_loop = this;
|
tw.in_loop = this;
|
||||||
push(tw);
|
push(tw);
|
||||||
this.body.walk(tw);
|
this.body.walk(tw);
|
||||||
@@ -1067,39 +1098,37 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
this.condition.walk(tw);
|
this.condition.walk(tw);
|
||||||
pop(tw);
|
pop(tw);
|
||||||
tw.in_loop = saved_loop;
|
tw.in_loop = save_loop;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_For, function(tw, descend, compressor) {
|
def(AST_For, function(tw, descend, compressor) {
|
||||||
this.variables.each(function(def) {
|
var node = this;
|
||||||
reset_def(tw, compressor, def);
|
reset_block_variables(tw, compressor, node);
|
||||||
});
|
if (node.init) node.init.walk(tw);
|
||||||
if (this.init) this.init.walk(tw);
|
var save_loop = tw.in_loop;
|
||||||
var saved_loop = tw.in_loop;
|
tw.in_loop = node;
|
||||||
tw.in_loop = this;
|
|
||||||
push(tw);
|
push(tw);
|
||||||
if (this.condition) this.condition.walk(tw);
|
if (node.condition) node.condition.walk(tw);
|
||||||
this.body.walk(tw);
|
node.body.walk(tw);
|
||||||
if (this.step) {
|
if (node.step) {
|
||||||
if (has_loop_control(this, tw.parent())) {
|
if (has_loop_control(node, tw.parent())) {
|
||||||
pop(tw);
|
pop(tw);
|
||||||
push(tw);
|
push(tw);
|
||||||
}
|
}
|
||||||
this.step.walk(tw);
|
node.step.walk(tw);
|
||||||
}
|
}
|
||||||
pop(tw);
|
pop(tw);
|
||||||
tw.in_loop = saved_loop;
|
tw.in_loop = save_loop;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_ForEnumeration, function(tw, descend, compressor) {
|
def(AST_ForEnumeration, function(tw, descend, compressor) {
|
||||||
this.variables.each(function(def) {
|
var node = this;
|
||||||
reset_def(tw, compressor, def);
|
reset_block_variables(tw, compressor, node);
|
||||||
});
|
node.object.walk(tw);
|
||||||
this.object.walk(tw);
|
var save_loop = tw.in_loop;
|
||||||
var saved_loop = tw.in_loop;
|
tw.in_loop = node;
|
||||||
tw.in_loop = this;
|
|
||||||
push(tw);
|
push(tw);
|
||||||
var init = this.init;
|
var init = node.init;
|
||||||
if (init instanceof AST_Definitions) {
|
if (init instanceof AST_Definitions) {
|
||||||
init.definitions[0].name.mark_symbol(function(node) {
|
init.definitions[0].name.mark_symbol(function(node) {
|
||||||
if (node instanceof AST_SymbolDeclaration) {
|
if (node instanceof AST_SymbolDeclaration) {
|
||||||
@@ -1120,9 +1149,9 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
init.walk(tw);
|
init.walk(tw);
|
||||||
}
|
}
|
||||||
this.body.walk(tw);
|
node.body.walk(tw);
|
||||||
pop(tw);
|
pop(tw);
|
||||||
tw.in_loop = saved_loop;
|
tw.in_loop = save_loop;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_If, function(tw) {
|
def(AST_If, function(tw) {
|
||||||
@@ -1145,13 +1174,14 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Lambda, function(tw, descend, compressor) {
|
def(AST_Lambda, function(tw, descend, compressor) {
|
||||||
var fn = this;
|
var fn = this;
|
||||||
|
if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true;
|
||||||
|
if (!push_uniq(tw.fn_visited, fn)) return true;
|
||||||
fn.inlined = false;
|
fn.inlined = false;
|
||||||
push(tw);
|
push(tw);
|
||||||
reset_variables(tw, compressor, fn);
|
reset_variables(tw, compressor, fn);
|
||||||
descend();
|
descend();
|
||||||
pop(tw);
|
pop_scope(tw, fn);
|
||||||
if (fn.name) mark_escaped(tw, fn.name.definition(), fn, fn.name, fn, 0, 1);
|
if (fn.name) mark_escaped(tw, fn.name.definition(), fn, fn.name, fn, 0, 1);
|
||||||
walk_defuns(tw, fn);
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_LambdaDefinition, function(tw, descend, compressor) {
|
def(AST_LambdaDefinition, function(tw, descend, compressor) {
|
||||||
@@ -1159,15 +1189,13 @@ merge(Compressor.prototype, {
|
|||||||
var def = fn.name.definition();
|
var def = fn.name.definition();
|
||||||
var parent = tw.parent();
|
var parent = tw.parent();
|
||||||
if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false;
|
if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false;
|
||||||
if (tw.defun_visited[def.id]) return true;
|
if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true;
|
||||||
if (def.init === fn && tw.defun_ids[def.id] !== tw.safe_ids) return true;
|
if (!push_uniq(tw.fn_visited, fn)) return true;
|
||||||
tw.defun_visited[def.id] = true;
|
|
||||||
fn.inlined = false;
|
fn.inlined = false;
|
||||||
push(tw);
|
push(tw);
|
||||||
reset_variables(tw, compressor, fn);
|
reset_variables(tw, compressor, fn);
|
||||||
descend();
|
descend();
|
||||||
pop(tw);
|
pop_scope(tw, fn);
|
||||||
walk_defuns(tw, fn);
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Sub, function(tw) {
|
def(AST_Sub, function(tw) {
|
||||||
@@ -1179,12 +1207,11 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Switch, function(tw, descend, compressor) {
|
def(AST_Switch, function(tw, descend, compressor) {
|
||||||
this.variables.each(function(def) {
|
var node = this;
|
||||||
reset_def(tw, compressor, def);
|
reset_block_variables(tw, compressor, node);
|
||||||
});
|
node.expression.walk(tw);
|
||||||
this.expression.walk(tw);
|
|
||||||
var first = true;
|
var first = true;
|
||||||
this.body.forEach(function(branch) {
|
node.body.forEach(function(branch) {
|
||||||
if (branch instanceof AST_Default) return;
|
if (branch instanceof AST_Default) return;
|
||||||
branch.expression.walk(tw);
|
branch.expression.walk(tw);
|
||||||
if (first) {
|
if (first) {
|
||||||
@@ -1193,7 +1220,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (!first) pop(tw);
|
if (!first) pop(tw);
|
||||||
walk_body(this, tw);
|
walk_body(node, tw);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_SwitchBranch, function(tw) {
|
def(AST_SwitchBranch, function(tw) {
|
||||||
@@ -1258,36 +1285,62 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (!this.fixed) this.fixed = d.fixed;
|
if (!this.fixed) this.fixed = d.fixed;
|
||||||
var parent;
|
var parent;
|
||||||
if (d.fixed instanceof AST_LambdaDefinition
|
if (value instanceof AST_Lambda
|
||||||
&& !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
|
&& !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
|
||||||
var defun = mark_defun(tw, d);
|
var fn = mark_fn_def(tw, d, value);
|
||||||
if (defun) defun.walk(tw);
|
if (fn) walk_fn_def(tw, fn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
def(AST_Template, function(tw, descend) {
|
||||||
|
var node = this;
|
||||||
|
var tag = node.tag;
|
||||||
|
if (!tag) return;
|
||||||
|
if (tag instanceof AST_LambdaExpression) {
|
||||||
|
node.expressions.forEach(function(exp) {
|
||||||
|
exp.walk(tw);
|
||||||
|
});
|
||||||
|
tag.safe_ids = tw.safe_ids;
|
||||||
|
tag.walk(tw);
|
||||||
|
delete tag.reduce_vars;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
tag.walk(tw);
|
||||||
|
var fixed = tag instanceof AST_SymbolRef && tag.fixed_value();
|
||||||
|
var fn;
|
||||||
|
if (fixed instanceof AST_Lambda) {
|
||||||
|
fn = mark_fn_def(tw, tag.definition(), fixed);
|
||||||
|
} else {
|
||||||
|
tw.find_parent(AST_Scope).may_call_this();
|
||||||
|
}
|
||||||
|
node.expressions.forEach(function(exp) {
|
||||||
|
exp.walk(tw);
|
||||||
|
});
|
||||||
|
if (fn) walk_fn_def(tw, fn);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
def(AST_Toplevel, function(tw, descend, compressor) {
|
def(AST_Toplevel, function(tw, descend, compressor) {
|
||||||
this.globals.each(function(def) {
|
var node = this;
|
||||||
|
node.globals.each(function(def) {
|
||||||
reset_def(tw, compressor, def);
|
reset_def(tw, compressor, def);
|
||||||
});
|
});
|
||||||
push(tw);
|
push(tw);
|
||||||
reset_variables(tw, compressor, this);
|
reset_variables(tw, compressor, node);
|
||||||
descend();
|
descend();
|
||||||
pop(tw);
|
pop_scope(tw, node);
|
||||||
walk_defuns(tw, this);
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Try, function(tw, descend, compressor) {
|
def(AST_Try, function(tw, descend, compressor) {
|
||||||
this.variables.each(function(def) {
|
var node = this;
|
||||||
reset_def(tw, compressor, def);
|
reset_block_variables(tw, compressor, node);
|
||||||
});
|
|
||||||
push(tw);
|
push(tw);
|
||||||
walk_body(this, tw);
|
walk_body(node, tw);
|
||||||
pop(tw);
|
pop(tw);
|
||||||
if (this.bcatch) {
|
if (node.bcatch) {
|
||||||
push(tw);
|
push(tw);
|
||||||
this.bcatch.walk(tw);
|
node.bcatch.walk(tw);
|
||||||
pop(tw);
|
pop(tw);
|
||||||
}
|
}
|
||||||
if (this.bfinally) this.bfinally.walk(tw);
|
if (node.bfinally) node.bfinally.walk(tw);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Unary, function(tw, descend) {
|
def(AST_Unary, function(tw, descend) {
|
||||||
@@ -1338,8 +1391,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_VarDef, function(tw, descend, compressor) {
|
def(AST_VarDef, function(tw, descend, compressor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
if (node.value) {
|
var value = node.value;
|
||||||
node.value.walk(tw);
|
if (value instanceof AST_LambdaExpression && node.name instanceof AST_SymbolDeclaration) {
|
||||||
|
value.parent_scope.resolve().fn_defs.push(value);
|
||||||
|
value.safe_ids = null;
|
||||||
|
} else if (value) {
|
||||||
|
value.walk(tw);
|
||||||
} else if (!(tw.parent() instanceof AST_Let)) {
|
} else if (!(tw.parent() instanceof AST_Let)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1363,12 +1420,12 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_While, function(tw, descend) {
|
def(AST_While, function(tw, descend) {
|
||||||
var saved_loop = tw.in_loop;
|
var save_loop = tw.in_loop;
|
||||||
tw.in_loop = this;
|
tw.in_loop = this;
|
||||||
push(tw);
|
push(tw);
|
||||||
descend();
|
descend();
|
||||||
pop(tw);
|
pop(tw);
|
||||||
tw.in_loop = saved_loop;
|
tw.in_loop = save_loop;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
@@ -1387,9 +1444,9 @@ merge(Compressor.prototype, {
|
|||||||
reset_flags(node);
|
reset_flags(node);
|
||||||
return node.reduce_vars(tw, descend, compressor);
|
return node.reduce_vars(tw, descend, compressor);
|
||||||
} : reset_flags);
|
} : reset_flags);
|
||||||
// Flow control for visiting `AST_Defun`s
|
// Flow control for visiting lambda definitions
|
||||||
tw.defun_ids = Object.create(null);
|
tw.fn_scanning = null;
|
||||||
tw.defun_visited = Object.create(null);
|
tw.fn_visited = [];
|
||||||
// Record the loop body in which `AST_SymbolDeclaration` is first encountered
|
// Record the loop body in which `AST_SymbolDeclaration` is first encountered
|
||||||
tw.in_loop = null;
|
tw.in_loop = null;
|
||||||
tw.loop_ids = Object.create(null);
|
tw.loop_ids = Object.create(null);
|
||||||
@@ -1642,9 +1699,7 @@ merge(Compressor.prototype, {
|
|||||||
return all(block.body, function(stat) {
|
return all(block.body, function(stat) {
|
||||||
return is_empty(stat)
|
return is_empty(stat)
|
||||||
|| stat instanceof AST_Defun
|
|| stat instanceof AST_Defun
|
||||||
|| stat instanceof AST_Var && all(stat.definitions, function(var_def) {
|
|| stat instanceof AST_Var && declarations_only(stat);
|
||||||
return !var_def.value;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6468,7 +6523,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
} else if (compressor.option("functions")
|
} else if (compressor.option("functions")
|
||||||
&& !compressor.option("ie8")
|
&& !compressor.option("ie8")
|
||||||
&& node instanceof AST_Var
|
&& drop_sym
|
||||||
&& var_defs[sym.id] == 1
|
&& var_defs[sym.id] == 1
|
||||||
&& sym.assignments == 0
|
&& sym.assignments == 0
|
||||||
&& value instanceof AST_LambdaExpression
|
&& value instanceof AST_LambdaExpression
|
||||||
@@ -6542,7 +6597,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function can_declare_defun(fn) {
|
function can_declare_defun(fn) {
|
||||||
if (compressor.has_directive("use strict") || !(fn instanceof AST_Function)) {
|
if (!is_var || compressor.has_directive("use strict") || !(fn instanceof AST_Function)) {
|
||||||
return parent instanceof AST_Scope;
|
return parent instanceof AST_Scope;
|
||||||
}
|
}
|
||||||
return parent instanceof AST_Block
|
return parent instanceof AST_Block
|
||||||
@@ -9501,9 +9556,7 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
var line = fn.body[i];
|
var line = fn.body[i];
|
||||||
if (line instanceof AST_Var) {
|
if (line instanceof AST_Var) {
|
||||||
var assigned = var_assigned || !all(line.definitions, function(var_def) {
|
var assigned = var_assigned || !declarations_only(line);
|
||||||
return !var_def.value;
|
|
||||||
});
|
|
||||||
if (assigned) {
|
if (assigned) {
|
||||||
var_assigned = true;
|
var_assigned = true;
|
||||||
if (stat) return false;
|
if (stat) return false;
|
||||||
|
|||||||
@@ -556,6 +556,38 @@ reduce_iife_3: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduce_lambda: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var f = () => {
|
||||||
|
console.log(a, b);
|
||||||
|
};
|
||||||
|
var a = "foo", b = 42;
|
||||||
|
f();
|
||||||
|
b = "bar";
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var f = () => {
|
||||||
|
console.log("foo", b);
|
||||||
|
};
|
||||||
|
var b = 42;
|
||||||
|
f();
|
||||||
|
b = "bar";
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo 42",
|
||||||
|
"foo bar",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
single_use_recursive: {
|
single_use_recursive: {
|
||||||
options = {
|
options = {
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
|||||||
@@ -3081,7 +3081,8 @@ issue_4235: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
void function() {
|
void function() {
|
||||||
var f = console.log(f);
|
var f;
|
||||||
|
console.log(f);
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
|
|||||||
@@ -2905,6 +2905,7 @@ issue_2437: {
|
|||||||
issue_2485_1: {
|
issue_2485_1: {
|
||||||
options = {
|
options = {
|
||||||
functions: true,
|
functions: true,
|
||||||
|
passes: 2,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -2955,6 +2956,7 @@ issue_2485_2: {
|
|||||||
options = {
|
options = {
|
||||||
functions: true,
|
functions: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
|
|||||||
@@ -152,7 +152,8 @@ issue_4487: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function a() {
|
function a() {
|
||||||
var f = console.log(typeof f);
|
var f;
|
||||||
|
console.log(typeof f);
|
||||||
}
|
}
|
||||||
a();
|
a();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -494,6 +494,41 @@ reduce_vars_3: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduce_lambda: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let f = function() {
|
||||||
|
console.log(a, b);
|
||||||
|
};
|
||||||
|
let a = "foo", b = 42;
|
||||||
|
f();
|
||||||
|
b = "bar";
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
function f() {
|
||||||
|
console.log("foo", b);
|
||||||
|
}
|
||||||
|
let b = 42;
|
||||||
|
f();
|
||||||
|
b = "bar";
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo 42",
|
||||||
|
"foo bar",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
hoist_props: {
|
hoist_props: {
|
||||||
options = {
|
options = {
|
||||||
hoist_props: true,
|
hoist_props: true,
|
||||||
|
|||||||
@@ -1320,6 +1320,7 @@ issue_2878: {
|
|||||||
|
|
||||||
issue_3427: {
|
issue_3427: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
pure_getters: "strict",
|
pure_getters: "strict",
|
||||||
|
|||||||
@@ -3092,7 +3092,7 @@ accessor_1: {
|
|||||||
a = 2;
|
a = 2;
|
||||||
return a;
|
return a;
|
||||||
},
|
},
|
||||||
b: 1
|
b: 1,
|
||||||
}.b, a);
|
}.b, a);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
@@ -3102,7 +3102,7 @@ accessor_1: {
|
|||||||
a = 2;
|
a = 2;
|
||||||
return a;
|
return a;
|
||||||
},
|
},
|
||||||
b: 1
|
b: 1,
|
||||||
}.b, a);
|
}.b, a);
|
||||||
}
|
}
|
||||||
expect_stdout: "1 1"
|
expect_stdout: "1 1"
|
||||||
@@ -3122,7 +3122,7 @@ accessor_2: {
|
|||||||
var B = {
|
var B = {
|
||||||
get c() {
|
get c() {
|
||||||
console.log(A);
|
console.log(A);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
B.c;
|
B.c;
|
||||||
}
|
}
|
||||||
@@ -3130,7 +3130,7 @@ accessor_2: {
|
|||||||
({
|
({
|
||||||
get c() {
|
get c() {
|
||||||
console.log(1);
|
console.log(1);
|
||||||
}
|
},
|
||||||
}).c;
|
}).c;
|
||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
@@ -3176,7 +3176,7 @@ obj_var_1: {
|
|||||||
var obj = {
|
var obj = {
|
||||||
bar: function() {
|
bar: function() {
|
||||||
return C + C;
|
return C + C;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
console.log(obj.bar());
|
console.log(obj.bar());
|
||||||
}
|
}
|
||||||
@@ -3184,7 +3184,7 @@ obj_var_1: {
|
|||||||
console.log({
|
console.log({
|
||||||
bar: function() {
|
bar: function() {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
},
|
||||||
}.bar());
|
}.bar());
|
||||||
}
|
}
|
||||||
expect_stdout: "2"
|
expect_stdout: "2"
|
||||||
@@ -3208,7 +3208,7 @@ obj_var_2: {
|
|||||||
var obj = {
|
var obj = {
|
||||||
bar: function() {
|
bar: function() {
|
||||||
return C + C;
|
return C + C;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
console.log(obj.bar());
|
console.log(obj.bar());
|
||||||
}
|
}
|
||||||
@@ -4422,6 +4422,7 @@ perf_2: {
|
|||||||
|
|
||||||
perf_3: {
|
perf_3: {
|
||||||
options = {
|
options = {
|
||||||
|
passes: 2,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
@@ -4430,10 +4431,10 @@ perf_3: {
|
|||||||
input: {
|
input: {
|
||||||
var foo = function(x, y, z) {
|
var foo = function(x, y, z) {
|
||||||
return x < y ? x * y + z : x * z - y;
|
return x < y ? x * y + z : x * z - y;
|
||||||
}
|
};
|
||||||
var indirect_foo = function(x, y, z) {
|
var indirect_foo = function(x, y, z) {
|
||||||
return foo(x, y, z);
|
return foo(x, y, z);
|
||||||
}
|
};
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var i = 0; i < 100; ++i)
|
for (var i = 0; i < 100; ++i)
|
||||||
sum += indirect_foo(i, i + 1, 3 * i);
|
sum += indirect_foo(i, i + 1, 3 * i);
|
||||||
@@ -4462,10 +4463,10 @@ perf_4: {
|
|||||||
input: {
|
input: {
|
||||||
var foo = function(x, y, z) {
|
var foo = function(x, y, z) {
|
||||||
return x < y ? x * y + z : x * z - y;
|
return x < y ? x * y + z : x * z - y;
|
||||||
}
|
};
|
||||||
var indirect_foo = function(x, y, z) {
|
var indirect_foo = function(x, y, z) {
|
||||||
return foo(x, y, z);
|
return foo(x, y, z);
|
||||||
}
|
};
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var i = 0; i < 100; ++i)
|
for (var i = 0; i < 100; ++i)
|
||||||
sum += indirect_foo(i, i + 1, 3 * i);
|
sum += indirect_foo(i, i + 1, 3 * i);
|
||||||
@@ -4474,10 +4475,10 @@ perf_4: {
|
|||||||
expect: {
|
expect: {
|
||||||
var foo = function(x, y, z) {
|
var foo = function(x, y, z) {
|
||||||
return x < y ? x * y + z : x * z - y;
|
return x < y ? x * y + z : x * z - y;
|
||||||
}
|
};
|
||||||
var indirect_foo = function(x, y, z) {
|
var indirect_foo = function(x, y, z) {
|
||||||
return foo(x, y, z);
|
return foo(x, y, z);
|
||||||
}
|
};
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var i = 0; i < 100; ++i)
|
for (var i = 0; i < 100; ++i)
|
||||||
sum += indirect_foo(i, i + 1, 3 * i);
|
sum += indirect_foo(i, i + 1, 3 * i);
|
||||||
@@ -4566,9 +4567,9 @@ perf_7: {
|
|||||||
var indirect_foo = function(x, y, z) {
|
var indirect_foo = function(x, y, z) {
|
||||||
var foo = function(x, y, z) {
|
var foo = function(x, y, z) {
|
||||||
return x < y ? x * y + z : x * z - y;
|
return x < y ? x * y + z : x * z - y;
|
||||||
}
|
};
|
||||||
return foo(x, y, z);
|
return foo(x, y, z);
|
||||||
}
|
};
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var i = 0; i < 100; ++i)
|
for (var i = 0; i < 100; ++i)
|
||||||
sum += indirect_foo(i, i + 1, 3 * i);
|
sum += indirect_foo(i, i + 1, 3 * i);
|
||||||
@@ -4598,9 +4599,9 @@ perf_8: {
|
|||||||
var indirect_foo = function(x, y, z) {
|
var indirect_foo = function(x, y, z) {
|
||||||
var foo = function(x, y, z) {
|
var foo = function(x, y, z) {
|
||||||
return x < y ? x * y + z : x * z - y;
|
return x < y ? x * y + z : x * z - y;
|
||||||
}
|
};
|
||||||
return foo(x, y, z);
|
return foo(x, y, z);
|
||||||
}
|
};
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var i = 0; i < 100; ++i)
|
for (var i = 0; i < 100; ++i)
|
||||||
sum += indirect_foo(i, i + 1, 3 * i);
|
sum += indirect_foo(i, i + 1, 3 * i);
|
||||||
@@ -4611,7 +4612,7 @@ perf_8: {
|
|||||||
return function(x, y, z) {
|
return function(x, y, z) {
|
||||||
return x < y ? x * y + z : x * z - y;
|
return x < y ? x * y + z : x * z - y;
|
||||||
}(x, y, z);
|
}(x, y, z);
|
||||||
}
|
};
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var i = 0; i < 100; ++i)
|
for (var i = 0; i < 100; ++i)
|
||||||
sum += indirect_foo(i, i + 1, 3 * i);
|
sum += indirect_foo(i, i + 1, 3 * i);
|
||||||
|
|||||||
@@ -726,7 +726,7 @@ function to_statement_init(node) {
|
|||||||
return node instanceof U.AST_Const || node instanceof U.AST_Let ? new U.AST_BlockStatement({
|
return node instanceof U.AST_Const || node instanceof U.AST_Let ? new U.AST_BlockStatement({
|
||||||
body: [ node ],
|
body: [ node ],
|
||||||
start: {},
|
start: {},
|
||||||
}) : to_statement(node);;
|
}) : to_statement(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrap_with_console_log(node) {
|
function wrap_with_console_log(node) {
|
||||||
|
|||||||
Reference in New Issue
Block a user