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