speed up compress (#5219)
This commit is contained in:
113
lib/compress.js
113
lib/compress.js
@@ -1818,27 +1818,34 @@ Compressor.prototype.compress = function(node) {
|
||||
function tighten_body(statements, compressor) {
|
||||
var in_loop, in_try, scope;
|
||||
find_loop_scope_try();
|
||||
var CHANGED, max_iter = 10;
|
||||
var changed, last_changed, max_iter = 10;
|
||||
do {
|
||||
CHANGED = false;
|
||||
eliminate_spurious_blocks(statements);
|
||||
last_changed = changed;
|
||||
changed = 0;
|
||||
if (eliminate_spurious_blocks(statements)) changed = 1;
|
||||
if (!changed && last_changed == 1) break;
|
||||
if (compressor.option("dead_code")) {
|
||||
eliminate_dead_code(statements, compressor);
|
||||
if (eliminate_dead_code(statements, compressor)) changed = 2;
|
||||
if (!changed && last_changed == 2) break;
|
||||
}
|
||||
if (compressor.option("if_return")) {
|
||||
handle_if_return(statements, compressor);
|
||||
if (handle_if_return(statements, compressor)) changed = 3;
|
||||
if (!changed && last_changed == 3) break;
|
||||
}
|
||||
if (compressor.sequences_limit > 0) {
|
||||
sequencesize(statements, compressor);
|
||||
sequencesize_2(statements, compressor);
|
||||
if (sequencesize(statements, compressor)) changed = 4;
|
||||
if (!changed && last_changed == 4) break;
|
||||
if (sequencesize_2(statements, compressor)) changed = 5;
|
||||
if (!changed && last_changed == 5) break;
|
||||
}
|
||||
if (compressor.option("join_vars")) {
|
||||
join_consecutive_vars(statements);
|
||||
if (join_consecutive_vars(statements)) changed = 6;
|
||||
if (!changed && last_changed == 6) break;
|
||||
}
|
||||
if (compressor.option("collapse_vars")) {
|
||||
collapse(statements, compressor);
|
||||
if (collapse(statements, compressor)) changed = 7;
|
||||
}
|
||||
} while (CHANGED && max_iter-- > 0);
|
||||
} while (changed && max_iter-- > 0);
|
||||
return statements;
|
||||
|
||||
function find_loop_scope_try() {
|
||||
@@ -1874,10 +1881,11 @@ Compressor.prototype.compress = function(node) {
|
||||
// Will not attempt to collapse assignments into or past code blocks
|
||||
// which are not sequentially executed, e.g. loops and conditionals.
|
||||
function collapse(statements, compressor) {
|
||||
if (scope.pinned()) return statements;
|
||||
if (scope.pinned()) return;
|
||||
var args;
|
||||
var assignments = new Dictionary();
|
||||
var candidates = [];
|
||||
var changed = false;
|
||||
var declare_only = new Dictionary();
|
||||
var force_single;
|
||||
var stat_index = statements.length;
|
||||
@@ -1924,7 +1932,7 @@ Compressor.prototype.compress = function(node) {
|
||||
} else {
|
||||
replaced++;
|
||||
}
|
||||
CHANGED = abort = true;
|
||||
changed = abort = true;
|
||||
AST_Node.info("Collapsing {node} [{file}:{line},{col}]", {
|
||||
node: node,
|
||||
file: node.start.file,
|
||||
@@ -2137,11 +2145,12 @@ Compressor.prototype.compress = function(node) {
|
||||
&& !compressor.exposed(def);
|
||||
value_def.last_ref = false;
|
||||
value_def.single_use = false;
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
}
|
||||
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
|
||||
function signal_abort(node) {
|
||||
if (abort) return node;
|
||||
@@ -3094,12 +3103,12 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
|
||||
function eliminate_spurious_blocks(statements) {
|
||||
var seen_dirs = [];
|
||||
var changed = false, seen_dirs = [];
|
||||
for (var i = 0; i < statements.length;) {
|
||||
var stat = statements[i];
|
||||
if (stat instanceof AST_BlockStatement) {
|
||||
if (all(stat.body, safe_to_trim)) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
eliminate_spurious_blocks(stat.body);
|
||||
[].splice.apply(statements, [i, 1].concat(stat.body));
|
||||
i += stat.body.length;
|
||||
@@ -3108,22 +3117,24 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
if (stat instanceof AST_Directive) {
|
||||
if (member(stat.value, seen_dirs)) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
statements.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
seen_dirs.push(stat.value);
|
||||
}
|
||||
if (stat instanceof AST_EmptyStatement) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
statements.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
function handle_if_return(statements, compressor) {
|
||||
var changed = false;
|
||||
var self = compressor.self();
|
||||
var parent = compressor.parent();
|
||||
var in_lambda = last_of(function(node) {
|
||||
@@ -3138,13 +3149,13 @@ Compressor.prototype.compress = function(node) {
|
||||
|
||||
if (in_lambda && !next && stat instanceof AST_Return) {
|
||||
if (!stat.value) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
statements.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
var tail = stat.value.tail_node();
|
||||
if (tail instanceof AST_UnaryPrefix && tail.operator == "void") {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
var body;
|
||||
if (tail === stat.value) {
|
||||
body = tail.expression;
|
||||
@@ -3163,7 +3174,7 @@ Compressor.prototype.compress = function(node) {
|
||||
var ab = aborts(stat.body);
|
||||
if (can_merge_flow(ab)) {
|
||||
if (ab.label) remove(ab.label.thedef.references, ab);
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
stat = stat.clone();
|
||||
stat.condition = stat.condition.negate(compressor);
|
||||
var body = as_statement_array_with_return(stat.body, ab);
|
||||
@@ -3181,7 +3192,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (ab && !stat.alternative && stat.body instanceof AST_BlockStatement && next instanceof AST_Jump) {
|
||||
var negated = stat.condition.negate(compressor);
|
||||
if (negated.print_to_string().length <= stat.condition.print_to_string().length) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
stat = stat.clone();
|
||||
stat.condition = negated;
|
||||
statements[j] = stat.body;
|
||||
@@ -3195,7 +3206,7 @@ Compressor.prototype.compress = function(node) {
|
||||
var alt = aborts(stat.alternative);
|
||||
if (can_merge_flow(alt)) {
|
||||
if (alt.label) remove(alt.label.thedef.references, alt);
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
stat = stat.clone();
|
||||
stat.body = make_node(AST_BlockStatement, stat.body, {
|
||||
body: as_statement_array(stat.body).concat(extract_functions())
|
||||
@@ -3231,7 +3242,7 @@ Compressor.prototype.compress = function(node) {
|
||||
// if (foo()) return; return; ---> foo(); return;
|
||||
if (!value && !stat.alternative
|
||||
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
statements[i] = make_node(AST_SimpleStatement, stat.condition, {
|
||||
body: stat.condition
|
||||
});
|
||||
@@ -3240,7 +3251,7 @@ Compressor.prototype.compress = function(node) {
|
||||
//---
|
||||
// if (foo()) return x; return y; ---> return foo() ? x : y;
|
||||
if (!stat.alternative && next instanceof AST_Return) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = next;
|
||||
statements.splice(i, 1, stat.transform(compressor));
|
||||
@@ -3250,7 +3261,7 @@ Compressor.prototype.compress = function(node) {
|
||||
//---
|
||||
// if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined;
|
||||
if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = make_node(AST_Return, stat, {
|
||||
value: null
|
||||
@@ -3268,7 +3279,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (compressor.option("sequences") && in_lambda && !stat.alternative
|
||||
&& (!prev && in_iife || prev instanceof AST_If && prev.body instanceof AST_Return)
|
||||
&& next_index(j) == statements.length && next instanceof AST_SimpleStatement) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = make_node(AST_BlockStatement, next, {
|
||||
body: [
|
||||
@@ -3284,6 +3295,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
|
||||
function has_multiple_if_returns(statements) {
|
||||
var n = 0;
|
||||
@@ -3411,7 +3423,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (has_quit) has_quit.forEach(function(stat) {
|
||||
extract_declarations_from_unreachable_code(compressor, stat, statements);
|
||||
});
|
||||
CHANGED = statements.length != len;
|
||||
return statements.length != len;
|
||||
}
|
||||
|
||||
function sequencesize(statements, compressor) {
|
||||
@@ -3439,7 +3451,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
push_seq();
|
||||
statements.length = n;
|
||||
if (n != len) CHANGED = true;
|
||||
return n != len;
|
||||
}
|
||||
|
||||
function to_simple_statement(block, decls) {
|
||||
@@ -3459,13 +3471,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
|
||||
function sequencesize_2(statements, compressor) {
|
||||
function cons_seq(right) {
|
||||
n--;
|
||||
CHANGED = true;
|
||||
var left = prev.body;
|
||||
return make_sequence(left, [ left, right ]);
|
||||
}
|
||||
var n = 0, prev;
|
||||
var changed = false, n = 0, prev;
|
||||
for (var i = 0; i < statements.length; i++) {
|
||||
var stat = statements[i];
|
||||
if (prev) {
|
||||
@@ -3488,7 +3494,7 @@ Compressor.prototype.compress = function(node) {
|
||||
else {
|
||||
stat.init = prev.body;
|
||||
n--;
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3518,7 +3524,7 @@ Compressor.prototype.compress = function(node) {
|
||||
i += len;
|
||||
n += len + 1;
|
||||
prev = null;
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -3526,6 +3532,14 @@ Compressor.prototype.compress = function(node) {
|
||||
prev = stat instanceof AST_SimpleStatement ? stat : null;
|
||||
}
|
||||
statements.length = n;
|
||||
return changed;
|
||||
|
||||
function cons_seq(right) {
|
||||
n--;
|
||||
changed = true;
|
||||
var left = prev.body;
|
||||
return make_sequence(left, [ left, right ]);
|
||||
}
|
||||
}
|
||||
|
||||
function extract_exprs(body) {
|
||||
@@ -3680,17 +3694,17 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
|
||||
function join_consecutive_vars(statements) {
|
||||
var defs;
|
||||
var changed = false, defs;
|
||||
for (var i = 0, j = -1; i < statements.length; i++) {
|
||||
var stat = statements[i];
|
||||
var prev = statements[j];
|
||||
if (stat instanceof AST_Definitions) {
|
||||
if (prev && prev.TYPE == stat.TYPE) {
|
||||
prev.definitions = prev.definitions.concat(stat.definitions);
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
} else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
|
||||
defs.definitions = defs.definitions.concat(stat.definitions);
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
} else if (stat instanceof AST_Var) {
|
||||
var exprs = merge_assigns(prev, stat);
|
||||
if (exprs) {
|
||||
@@ -3698,7 +3712,7 @@ Compressor.prototype.compress = function(node) {
|
||||
prev.body = make_sequence(prev, exprs);
|
||||
j++;
|
||||
}
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
} else {
|
||||
j++;
|
||||
}
|
||||
@@ -3712,7 +3726,7 @@ Compressor.prototype.compress = function(node) {
|
||||
} else if (stat instanceof AST_For) {
|
||||
var exprs = join_assigns(prev, stat.init);
|
||||
if (exprs) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
|
||||
} else if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
||||
if (stat.init) {
|
||||
@@ -3720,17 +3734,17 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
defs = stat.init = prev;
|
||||
statements[j] = merge_defns(stat);
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
continue;
|
||||
} else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
|
||||
defs.definitions = defs.definitions.concat(stat.init.definitions);
|
||||
stat.init = null;
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
} else if (stat.init instanceof AST_Var) {
|
||||
defs = stat.init;
|
||||
exprs = merge_assigns(prev, stat.init);
|
||||
if (exprs) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
if (exprs.length == 0) {
|
||||
statements[j] = merge_defns(stat);
|
||||
continue;
|
||||
@@ -3749,7 +3763,7 @@ Compressor.prototype.compress = function(node) {
|
||||
name.definition().references.push(ref);
|
||||
});
|
||||
defs.definitions = defns;
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
}
|
||||
stat.object = join_assigns_expr(stat.object);
|
||||
} else if (stat instanceof AST_If) {
|
||||
@@ -3757,7 +3771,7 @@ Compressor.prototype.compress = function(node) {
|
||||
} else if (stat instanceof AST_SimpleStatement) {
|
||||
var exprs = join_assigns(prev, stat.body);
|
||||
if (exprs) {
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
if (!exprs.length) continue;
|
||||
stat.body = make_sequence(stat.body, exprs);
|
||||
}
|
||||
@@ -3769,11 +3783,12 @@ Compressor.prototype.compress = function(node) {
|
||||
statements[++j] = defs ? merge_defns(stat) : stat;
|
||||
}
|
||||
statements.length = j + 1;
|
||||
return changed;
|
||||
|
||||
function join_assigns_expr(value) {
|
||||
var exprs = join_assigns(prev, value, 1);
|
||||
if (!exprs) return value;
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
var tail = value.tail_node();
|
||||
if (exprs[exprs.length - 1] !== tail) exprs.push(tail.left);
|
||||
return make_sequence(value, exprs);
|
||||
@@ -3788,7 +3803,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (parent instanceof AST_ForEnumeration && parent.init === node) return node;
|
||||
if (!declarations_only(node)) return node;
|
||||
defs.definitions = defs.definitions.concat(node.definitions);
|
||||
CHANGED = true;
|
||||
changed = true;
|
||||
if (parent instanceof AST_For && parent.init === node) return null;
|
||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user