Merge branch 'master' into harmony-v3.3.5
This commit is contained in:
520
lib/compress.js
520
lib/compress.js
@@ -105,6 +105,7 @@ function Compressor(options, false_by_default) {
|
||||
});
|
||||
}
|
||||
}
|
||||
if (this.options["inline"] === true) this.options["inline"] = 3;
|
||||
var pure_funcs = this.options["pure_funcs"];
|
||||
if (typeof pure_funcs == "function") {
|
||||
this.pure_funcs = pure_funcs;
|
||||
@@ -317,12 +318,13 @@ merge(Compressor.prototype, {
|
||||
def(AST_Node, noop);
|
||||
|
||||
function reset_def(compressor, def) {
|
||||
def.assignments = 0;
|
||||
def.direct_access = false;
|
||||
def.escaped = false;
|
||||
if (def.scope.uses_eval || def.scope.uses_with) {
|
||||
def.fixed = false;
|
||||
} else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
|
||||
def.fixed = undefined;
|
||||
def.fixed = def.init;
|
||||
} else {
|
||||
def.fixed = false;
|
||||
}
|
||||
@@ -332,9 +334,16 @@ merge(Compressor.prototype, {
|
||||
def.single_use = undefined;
|
||||
}
|
||||
|
||||
function reset_variables(compressor, node) {
|
||||
function reset_variables(tw, compressor, node) {
|
||||
node.variables.each(function(def) {
|
||||
reset_def(compressor, def);
|
||||
if (def.fixed === null) {
|
||||
def.safe_ids = tw.safe_ids;
|
||||
mark(tw, def, true);
|
||||
} else if (def.fixed) {
|
||||
tw.loop_ids[def.id] = tw.in_loop;
|
||||
mark(tw, def, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -369,10 +378,16 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function safe_to_assign(tw, def, value) {
|
||||
if (def.fixed === undefined) return true;
|
||||
if (def.fixed === null && def.safe_ids) {
|
||||
def.safe_ids[def.id] = false;
|
||||
delete def.safe_ids;
|
||||
return true;
|
||||
}
|
||||
if (!HOP(tw.safe_ids, def.id)) return false;
|
||||
if (!safe_to_read(tw, def)) return false;
|
||||
if (def.fixed === false) return false;
|
||||
if (def.fixed != null && (!value || def.references.length > 0)) return false;
|
||||
if (def.fixed != null && (!value || def.references.length > def.assignments)) return false;
|
||||
return all(def.orig, function(sym) {
|
||||
return !(sym instanceof AST_SymbolConst
|
||||
|| sym instanceof AST_SymbolDefun
|
||||
@@ -489,11 +504,9 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
|
||||
var d = node.left.definition();
|
||||
if (safe_to_assign(tw, d, node.right)
|
||||
|| d.fixed === undefined && all(d.orig, function(sym) {
|
||||
return sym instanceof AST_SymbolVar;
|
||||
})) {
|
||||
if (safe_to_assign(tw, d, node.right)) {
|
||||
d.references.push(node.left);
|
||||
d.assignments++;
|
||||
d.fixed = function() {
|
||||
return node.right;
|
||||
};
|
||||
@@ -533,19 +546,10 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
function mark_def_node(tw, descend, compressor) {
|
||||
reset_variables(compressor, this);
|
||||
this.inlined = false;
|
||||
var d = this.name.definition();
|
||||
if (compressor.exposed(d) || safe_to_read(tw, d)) {
|
||||
d.fixed = false;
|
||||
} else {
|
||||
d.fixed = this;
|
||||
d.single_use = ref_once(tw, compressor, d);
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, true);
|
||||
}
|
||||
var save_ids = tw.safe_ids;
|
||||
tw.safe_ids = Object.create(null);
|
||||
reset_variables(tw, compressor, this);
|
||||
descend();
|
||||
tw.safe_ids = save_ids;
|
||||
return true;
|
||||
@@ -600,9 +604,9 @@ merge(Compressor.prototype, {
|
||||
|
||||
function mark_func_expr(tw, descend, compressor) {
|
||||
var node = this;
|
||||
reset_variables(compressor, node);
|
||||
node.inlined = false;
|
||||
push(tw);
|
||||
reset_variables(tw, compressor, node);
|
||||
var iife;
|
||||
if (!node.name
|
||||
&& (iife = tw.parent()) instanceof AST_Call
|
||||
@@ -693,7 +697,7 @@ merge(Compressor.prototype, {
|
||||
this.globals.each(function(def) {
|
||||
reset_def(compressor, def);
|
||||
});
|
||||
reset_variables(compressor, this);
|
||||
reset_variables(tw, compressor, this);
|
||||
});
|
||||
def(AST_Try, function(tw, descend, compressor) {
|
||||
reset_block_variables(compressor, this);
|
||||
@@ -715,7 +719,7 @@ merge(Compressor.prototype, {
|
||||
return;
|
||||
}
|
||||
var d = node.name.definition();
|
||||
if (d.fixed === undefined || safe_to_assign(tw, d, node.value)) {
|
||||
if (safe_to_assign(tw, d, node.value)) {
|
||||
if (node.value) {
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
@@ -723,8 +727,6 @@ merge(Compressor.prototype, {
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, false);
|
||||
descend();
|
||||
} else {
|
||||
d.fixed = null;
|
||||
}
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
@@ -957,6 +959,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (compressor.sequences_limit > 0) {
|
||||
sequencesize(statements, compressor);
|
||||
sequencesize_2(statements, compressor);
|
||||
}
|
||||
if (compressor.option("join_vars")) {
|
||||
join_consecutive_vars(statements, compressor);
|
||||
@@ -1259,10 +1262,10 @@ merge(Compressor.prototype, {
|
||||
if (!expr.left.has_side_effects(compressor)) {
|
||||
candidates.push(hit_stack.slice());
|
||||
}
|
||||
} else if (expr instanceof AST_Unary) {
|
||||
if (expr.operator == "++" || expr.operator == "--") {
|
||||
candidates.push(hit_stack.slice());
|
||||
}
|
||||
extract_candidates(expr.right);
|
||||
} else if (expr instanceof AST_Binary) {
|
||||
extract_candidates(expr.left);
|
||||
extract_candidates(expr.right);
|
||||
} else if (expr instanceof AST_Call) {
|
||||
extract_candidates(expr.expression);
|
||||
expr.args.forEach(extract_candidates);
|
||||
@@ -1275,10 +1278,14 @@ merge(Compressor.prototype, {
|
||||
} else if (expr instanceof AST_Definitions
|
||||
&& (compressor.option("unused") || !(expr instanceof AST_Const))) {
|
||||
expr.definitions.forEach(extract_candidates);
|
||||
} else if (expr instanceof AST_DWLoop) {
|
||||
extract_candidates(expr.condition);
|
||||
} else if (expr instanceof AST_Exit) {
|
||||
if (expr.value) extract_candidates(expr.value);
|
||||
} else if (expr instanceof AST_For) {
|
||||
if (expr.init) extract_candidates(expr.init);
|
||||
if (expr.condition) extract_candidates(expr.condition);
|
||||
if (expr.step) extract_candidates(expr.step);
|
||||
} else if (expr instanceof AST_If) {
|
||||
extract_candidates(expr.condition);
|
||||
} else if (expr instanceof AST_Sequence) {
|
||||
@@ -1288,21 +1295,31 @@ merge(Compressor.prototype, {
|
||||
} else if (expr instanceof AST_Switch) {
|
||||
extract_candidates(expr.expression);
|
||||
expr.body.forEach(extract_candidates);
|
||||
} else if (expr instanceof AST_Unary) {
|
||||
if (expr.operator == "++" || expr.operator == "--") {
|
||||
candidates.push(hit_stack.slice());
|
||||
}
|
||||
} else if (expr instanceof AST_VarDef) {
|
||||
if (expr.value) candidates.push(hit_stack.slice());
|
||||
if (expr.value) {
|
||||
candidates.push(hit_stack.slice());
|
||||
extract_candidates(expr.value);
|
||||
}
|
||||
}
|
||||
hit_stack.pop();
|
||||
}
|
||||
|
||||
function find_stop(node, level) {
|
||||
var parent = scanner.parent(level);
|
||||
if (parent instanceof AST_Binary) return node;
|
||||
if (parent instanceof AST_Call) return node;
|
||||
if (parent instanceof AST_Case) return node;
|
||||
if (parent instanceof AST_Conditional) return node;
|
||||
if (parent instanceof AST_Exit) return node;
|
||||
if (parent instanceof AST_If) return node;
|
||||
if (parent instanceof AST_IterationStatement) return node;
|
||||
if (parent instanceof AST_Sequence) return find_stop(parent, level + 1);
|
||||
if (parent instanceof AST_Switch) return node;
|
||||
if (parent instanceof AST_VarDef) return node;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1450,12 +1467,13 @@ merge(Compressor.prototype, {
|
||||
var in_lambda = self instanceof AST_Lambda;
|
||||
for (var i = statements.length; --i >= 0;) {
|
||||
var stat = statements[i];
|
||||
var next = statements[i + 1];
|
||||
var j = next_index(i);
|
||||
var next = statements[j];
|
||||
|
||||
if (in_lambda && !next && stat instanceof AST_Return) {
|
||||
if (!stat.value) {
|
||||
CHANGED = true;
|
||||
statements.length--;
|
||||
statements.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
if (stat.value instanceof AST_UnaryPrefix && stat.value.operator == "void") {
|
||||
@@ -1525,19 +1543,22 @@ merge(Compressor.prototype, {
|
||||
CHANGED = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = next;
|
||||
statements.splice(i, 2, stat.transform(compressor));
|
||||
statements.splice(i, 1, stat.transform(compressor));
|
||||
statements.splice(j, 1);
|
||||
continue;
|
||||
}
|
||||
//---
|
||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||
if (multiple_if_returns && in_lambda && value && !stat.alternative
|
||||
&& (!next || next instanceof AST_Return)) {
|
||||
if (value && !stat.alternative
|
||||
&& (!next && in_lambda && multiple_if_returns
|
||||
|| next instanceof AST_Return)) {
|
||||
CHANGED = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = next || make_node(AST_Return, stat, {
|
||||
value: null
|
||||
});
|
||||
statements.splice(i, next ? 2 : 1, stat.transform(compressor));
|
||||
statements.splice(i, 1, stat.transform(compressor));
|
||||
if (next) statements.splice(j, 1);
|
||||
continue;
|
||||
}
|
||||
//---
|
||||
@@ -1546,10 +1567,10 @@ merge(Compressor.prototype, {
|
||||
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
||||
// however, with sequences on this helps producing slightly better output for
|
||||
// the example code.
|
||||
var prev = statements[i - 1];
|
||||
var prev = statements[prev_index(i)];
|
||||
if (compressor.option("sequences") && in_lambda && !stat.alternative
|
||||
&& prev instanceof AST_If && prev.body instanceof AST_Return
|
||||
&& i + 2 == statements.length && next instanceof AST_SimpleStatement) {
|
||||
&& next_index(j) == statements.length && next instanceof AST_SimpleStatement) {
|
||||
CHANGED = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = make_node(AST_BlockStatement, next, {
|
||||
@@ -1560,7 +1581,8 @@ merge(Compressor.prototype, {
|
||||
})
|
||||
]
|
||||
});
|
||||
statements.splice(i, 2, stat.transform(compressor));
|
||||
statements.splice(i, 1, stat.transform(compressor));
|
||||
statements.splice(j, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1614,6 +1636,26 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
function next_index(i) {
|
||||
for (var j = i + 1, len = statements.length; j < len; j++) {
|
||||
var stat = statements[j];
|
||||
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
function prev_index(i) {
|
||||
for (var j = i; --j >= 0;) {
|
||||
var stat = statements[j];
|
||||
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
function eliminate_dead_code(statements, compressor) {
|
||||
@@ -1649,6 +1691,12 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
|
||||
function declarations_only(node) {
|
||||
return all(node.definitions, function(var_def) {
|
||||
return !var_def.value;
|
||||
});
|
||||
}
|
||||
|
||||
function sequencesize(statements, compressor) {
|
||||
if (statements.length < 2) return;
|
||||
var seq = [], n = 0;
|
||||
@@ -1665,6 +1713,9 @@ merge(Compressor.prototype, {
|
||||
var body = stat.body;
|
||||
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
|
||||
if (body) merge_sequence(seq, body);
|
||||
} else if (stat instanceof AST_Definitions && declarations_only(stat)
|
||||
|| stat instanceof AST_Defun) {
|
||||
statements[n++] = stat;
|
||||
} else {
|
||||
push_seq();
|
||||
statements[n++] = stat;
|
||||
@@ -1672,18 +1723,34 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
push_seq();
|
||||
statements.length = n;
|
||||
sequencesize_2(statements, compressor);
|
||||
CHANGED = statements.length != len;
|
||||
if (n != len) CHANGED = true;
|
||||
}
|
||||
|
||||
function to_simple_statement(block, decls) {
|
||||
if (!(block instanceof AST_BlockStatement)) return block;
|
||||
var stat = null;
|
||||
for (var i = 0, len = block.body.length; i < len; i++) {
|
||||
var line = block.body[i];
|
||||
if (line instanceof AST_Definitions && declarations_only(line)) {
|
||||
decls.push(line);
|
||||
} else if (stat) {
|
||||
return false;
|
||||
} else {
|
||||
stat = line;
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
function sequencesize_2(statements, compressor) {
|
||||
function cons_seq(right) {
|
||||
n--;
|
||||
CHANGED = true;
|
||||
var left = prev.body;
|
||||
return make_sequence(left, [ left, right ]).transform(compressor);
|
||||
};
|
||||
var n = 0, prev;
|
||||
for (var i = 0, len = statements.length; i < len; i++) {
|
||||
for (var i = 0; i < statements.length; i++) {
|
||||
var stat = statements[i];
|
||||
if (prev) {
|
||||
if (stat instanceof AST_For && !(stat.init instanceof AST_Definitions)) {
|
||||
@@ -1700,6 +1767,7 @@ merge(Compressor.prototype, {
|
||||
else {
|
||||
stat.init = prev.body;
|
||||
n--;
|
||||
CHANGED = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1719,6 +1787,26 @@ merge(Compressor.prototype, {
|
||||
stat.expression = cons_seq(stat.expression);
|
||||
}
|
||||
}
|
||||
if (compressor.option("conditionals") && stat instanceof AST_If) {
|
||||
var decls = [];
|
||||
var body = to_simple_statement(stat.body, decls);
|
||||
var alt = to_simple_statement(stat.alternative, decls);
|
||||
if (body !== false && alt !== false && decls.length > 0) {
|
||||
var len = decls.length;
|
||||
decls.push(make_node(AST_If, stat, {
|
||||
condition: stat.condition,
|
||||
body: body || make_node(AST_EmptyStatement, stat.body),
|
||||
alternative: alt
|
||||
}));
|
||||
decls.unshift(n, 1);
|
||||
[].splice.apply(statements, decls);
|
||||
i += len;
|
||||
n += len + 1;
|
||||
prev = null;
|
||||
CHANGED = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
statements[n++] = stat;
|
||||
prev = stat instanceof AST_SimpleStatement ? stat : null;
|
||||
}
|
||||
@@ -1726,30 +1814,43 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function join_consecutive_vars(statements, compressor) {
|
||||
var defs;
|
||||
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
|
||||
var stat = statements[i];
|
||||
var prev = statements[j];
|
||||
if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
|
||||
prev.definitions = prev.definitions.concat(stat.definitions);
|
||||
CHANGED = true;
|
||||
}
|
||||
else if (stat instanceof AST_For
|
||||
&& prev instanceof AST_Var
|
||||
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
||||
CHANGED = true;
|
||||
if (stat.init) {
|
||||
stat.init.definitions = prev.definitions.concat(stat.init.definitions);
|
||||
if (stat instanceof AST_Definitions) {
|
||||
if (prev && prev.TYPE == stat.TYPE) {
|
||||
prev.definitions = prev.definitions.concat(stat.definitions);
|
||||
CHANGED = true;
|
||||
} else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
|
||||
defs.definitions = defs.definitions.concat(stat.definitions);
|
||||
CHANGED = true;
|
||||
} else {
|
||||
stat.init = prev;
|
||||
statements[++j] = stat;
|
||||
defs = stat;
|
||||
}
|
||||
statements[j] = stat;
|
||||
}
|
||||
else {
|
||||
} else if (stat instanceof AST_For) {
|
||||
if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
||||
if (stat.init) {
|
||||
prev.definitions = prev.definitions.concat(stat.init.definitions);
|
||||
}
|
||||
stat.init = prev;
|
||||
statements[j] = stat;
|
||||
CHANGED = true;
|
||||
} else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
|
||||
defs.definitions = defs.definitions.concat(stat.init.definitions);
|
||||
stat.init = null;
|
||||
statements[++j] = stat;
|
||||
CHANGED = true;
|
||||
} else {
|
||||
statements[++j] = stat;
|
||||
}
|
||||
} else {
|
||||
statements[++j] = stat;
|
||||
}
|
||||
}
|
||||
statements.length = j + 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||
@@ -2792,6 +2893,7 @@ merge(Compressor.prototype, {
|
||||
};
|
||||
var in_use = [];
|
||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||
var fixed_ids = Object.create(null);
|
||||
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
||||
self.variables.each(function(def) {
|
||||
if (compressor.top_retain(def) && !(def.id in in_use_ids)) {
|
||||
@@ -2847,7 +2949,11 @@ merge(Compressor.prototype, {
|
||||
def.walk(tw);
|
||||
destructuring_value = destructuring_cache;
|
||||
} else {
|
||||
initializations.add(def.name.definition().id, def.value);
|
||||
var node_def = def.name.definition();;
|
||||
initializations.add(node_def.id, def.value);
|
||||
if (def.name.fixed_value() === def.value) {
|
||||
fixed_ids[node_def.id] = true;
|
||||
}
|
||||
}
|
||||
if (def.value.has_side_effects(compressor)) {
|
||||
def.value.walk(tw);
|
||||
@@ -2878,13 +2984,16 @@ merge(Compressor.prototype, {
|
||||
var parent = tt.parent();
|
||||
if (drop_vars) {
|
||||
var sym = assign_as_unused(node);
|
||||
if (sym instanceof AST_SymbolRef
|
||||
&& !((sym = sym.definition()).id in in_use_ids)
|
||||
&& (drop_vars || !sym.global)) {
|
||||
if (sym instanceof AST_SymbolRef) {
|
||||
var def = sym.definition();
|
||||
var in_use = def.id in in_use_ids;
|
||||
if (node instanceof AST_Assign) {
|
||||
return maintain_this_binding(parent, node, node.right.transform(tt));
|
||||
}
|
||||
return make_node(AST_Number, node, {
|
||||
if (!in_use
|
||||
|| def.id in fixed_ids
|
||||
&& node.left.fixed_value() !== node.right) {
|
||||
return maintain_this_binding(parent, node, node.right.transform(tt));
|
||||
}
|
||||
} else if (!in_use) return make_node(AST_Number, node, {
|
||||
value: 0
|
||||
});
|
||||
}
|
||||
@@ -2959,13 +3068,16 @@ merge(Compressor.prototype, {
|
||||
operator: "=",
|
||||
left: make_node(AST_SymbolRef, def.name, def.name),
|
||||
right: def.value
|
||||
}));
|
||||
}).transform(tt));
|
||||
}
|
||||
remove(var_defs, def);
|
||||
sym.eliminated++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (def.value && sym.id in fixed_ids && def.name.fixed_value() !== def.value) {
|
||||
def.value = def.value.drop_side_effect_free(compressor);
|
||||
}
|
||||
if (def.value) {
|
||||
if (side_effects.length > 0) {
|
||||
if (tail.length > 0) {
|
||||
@@ -3077,15 +3189,20 @@ merge(Compressor.prototype, {
|
||||
self.transform(tt);
|
||||
|
||||
function scan_ref_scoped(node, descend) {
|
||||
var sym;
|
||||
if ((sym = assign_as_unused(node)) instanceof AST_SymbolRef
|
||||
var node_def, sym = assign_as_unused(node);
|
||||
if (sym instanceof AST_SymbolRef
|
||||
&& !is_ref_of(node.left, AST_SymbolBlockDeclaration)
|
||||
&& self.variables.get(sym.name) === sym.definition()) {
|
||||
if (node instanceof AST_Assign) node.right.walk(tw);
|
||||
&& self.variables.get(sym.name) === (node_def = sym.definition())) {
|
||||
if (node instanceof AST_Assign) {
|
||||
node.right.walk(tw);
|
||||
if (node.left.fixed_value() === node.right) {
|
||||
fixed_ids[node_def.id] = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var node_def = node.definition();
|
||||
node_def = node.definition();
|
||||
if (!(node_def.id in in_use_ids)) {
|
||||
in_use_ids[node_def.id] = true;
|
||||
in_use.push(node_def);
|
||||
@@ -3382,7 +3499,12 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
def(AST_Assign, function(compressor){
|
||||
var left = this.left;
|
||||
if (left.has_side_effects(compressor)) return this;
|
||||
if (left.has_side_effects(compressor)
|
||||
|| compressor.has_directive("use strict")
|
||||
&& left instanceof AST_PropAccess
|
||||
&& left.expression.is_constant()) {
|
||||
return this;
|
||||
}
|
||||
this.write_only = true;
|
||||
while (left instanceof AST_PropAccess) {
|
||||
left = left.expression;
|
||||
@@ -4018,6 +4140,27 @@ merge(Compressor.prototype, {
|
||||
operator: "!"
|
||||
}).optimize(compressor);
|
||||
break;
|
||||
case "RegExp":
|
||||
var params = [];
|
||||
if (all(self.args, function(arg) {
|
||||
var value = arg.evaluate(compressor);
|
||||
params.unshift(value);
|
||||
return arg !== value;
|
||||
})) {
|
||||
try {
|
||||
return best_of(compressor, self, make_node(AST_RegExp, self, {
|
||||
value: RegExp.apply(RegExp, params),
|
||||
}));
|
||||
} catch (ex) {
|
||||
compressor.warn("Error converting {expr} [{file}:{line},{col}]", {
|
||||
expr: self.print_to_string(),
|
||||
file: self.start.file,
|
||||
line: self.start.line,
|
||||
col: self.start.col
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "Symbol":
|
||||
// Symbol's argument is only used for debugging.
|
||||
self.args = [];
|
||||
@@ -4219,24 +4362,22 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
if (is_func && !fn.is_generator && !fn.async) {
|
||||
var def, value, scope, level = -1;
|
||||
var def, value, scope, in_loop, level = -1;
|
||||
if (compressor.option("inline")
|
||||
&& simple_args
|
||||
&& !fn.uses_arguments
|
||||
&& !fn.uses_eval
|
||||
&& (fn.body instanceof AST_Node || fn.body.length == 1)
|
||||
&& (exp === fn ? !fn.name
|
||||
: compressor.option("unused")
|
||||
&& !(fn.name && fn instanceof AST_Function)
|
||||
&& (value = can_flatten_body(stat))
|
||||
&& (exp === fn
|
||||
|| compressor.option("unused")
|
||||
&& (def = exp.definition()).references.length == 1
|
||||
&& !recursive_ref(compressor, def)
|
||||
&& fn.is_constant_expression(exp.scope))
|
||||
&& !self.pure
|
||||
&& !fn.contains_this()
|
||||
&& can_flatten_args(fn)
|
||||
&& (value = flatten_body(stat))) {
|
||||
var expressions = flatten_args(fn);
|
||||
expressions.push(value.clone(true));
|
||||
return make_sequence(self, expressions).optimize(compressor);
|
||||
&& can_inject_symbols()) {
|
||||
return make_sequence(self, flatten_fn()).optimize(compressor);
|
||||
}
|
||||
if (compressor.option("side_effects") && !(fn.body instanceof AST_Node) && all(fn.body, is_empty)) {
|
||||
var args = self.args.concat(make_node(AST_Undefined, self));
|
||||
@@ -4266,19 +4407,45 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return self;
|
||||
|
||||
function can_flatten_args(fn) {
|
||||
var catches = Object.create(null), defs;
|
||||
do {
|
||||
scope = compressor.parent(++level);
|
||||
if (scope instanceof AST_Catch) {
|
||||
catches[scope.argname.name] = true;
|
||||
} else if (scope instanceof AST_IterationStatement) {
|
||||
defs = [];
|
||||
} else if (scope instanceof AST_SymbolRef) {
|
||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||
function return_value(stat) {
|
||||
if (!stat) return make_node(AST_Undefined, self);
|
||||
if (stat instanceof AST_Return) {
|
||||
if (!stat.value) return make_node(AST_Undefined, self);
|
||||
return stat.value.clone(true);
|
||||
}
|
||||
if (stat instanceof AST_SimpleStatement) {
|
||||
return make_node(AST_UnaryPrefix, stat, {
|
||||
operator: "void",
|
||||
expression: stat.body.clone(true)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function can_flatten_body(stat) {
|
||||
var body = fn.body instanceof AST_Node ? [ fn.body ] : fn.body;
|
||||
var len = body.length;
|
||||
if (compressor.option("inline") < 3) {
|
||||
return len == 1 && return_value(stat);
|
||||
}
|
||||
stat = null;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var line = body[i];
|
||||
if (line instanceof AST_Var) {
|
||||
if (stat && !all(line.definitions, function(var_def) {
|
||||
return !var_def.value;
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
} else if (stat) {
|
||||
return false;
|
||||
} else {
|
||||
stat = line;
|
||||
}
|
||||
} while (!(scope instanceof AST_Scope) || scope instanceof AST_Arrow);
|
||||
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
|
||||
}
|
||||
return return_value(stat);
|
||||
}
|
||||
|
||||
function can_inject_args(catches, safe_to_inject) {
|
||||
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
||||
var arg = fn.argnames[i];
|
||||
if (arg instanceof AST_DefaultAssign) {
|
||||
@@ -4297,44 +4464,119 @@ merge(Compressor.prototype, {
|
||||
|| scope.var_names()[arg.name]) {
|
||||
return false;
|
||||
}
|
||||
if (defs) defs.push(arg.definition());
|
||||
if (in_loop) in_loop.push(arg.definition());
|
||||
}
|
||||
return !defs || defs.length == 0 || !is_reachable(stat, defs);
|
||||
return true;
|
||||
}
|
||||
|
||||
function flatten_args(fn) {
|
||||
var decls = [];
|
||||
var expressions = [];
|
||||
for (var len = fn.argnames.length, i = len; --i >= 0;) {
|
||||
var name = fn.argnames[i];
|
||||
var value = self.args[i];
|
||||
if (name.__unused || !name.name) {
|
||||
if (value || expressions.length) {
|
||||
expressions.unshift(value || make_node(AST_Undefined, self));
|
||||
function can_inject_vars(catches, safe_to_inject) {
|
||||
var len = fn.body.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
if (!safe_to_inject) return false;
|
||||
for (var j = stat.definitions.length; --j >= 0;) {
|
||||
var name = stat.definitions[j].name;
|
||||
if (catches[name.name]
|
||||
|| identifier_atom(name.name)
|
||||
|| scope.var_names()[name.name]) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
var def = name.definition();
|
||||
scope.var_names()[name.name] = true;
|
||||
scope.variables.set(name.name, def);
|
||||
scope.enclosed.push(def);
|
||||
var symbol = make_node(AST_SymbolVar, name, name);
|
||||
def.orig.push(symbol);
|
||||
decls.unshift(make_node(AST_VarDef, name, {
|
||||
name: symbol,
|
||||
value: null
|
||||
}));
|
||||
var sym = make_node(AST_SymbolRef, name, name);
|
||||
def.references.push(sym);
|
||||
expressions.unshift(make_node(AST_Assign, self, {
|
||||
operator: "=",
|
||||
left: sym,
|
||||
right: value || make_node(AST_Undefined, self)
|
||||
}));
|
||||
if (in_loop) in_loop.push(name.definition());
|
||||
}
|
||||
}
|
||||
for (i = len, len = self.args.length; i < len; i++) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function can_inject_symbols() {
|
||||
var catches = Object.create(null);
|
||||
do {
|
||||
scope = compressor.parent(++level);
|
||||
if (scope instanceof AST_Catch) {
|
||||
catches[scope.argname.name] = true;
|
||||
} else if (scope instanceof AST_IterationStatement) {
|
||||
in_loop = [];
|
||||
} else if (scope instanceof AST_SymbolRef) {
|
||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||
}
|
||||
} while (!(scope instanceof AST_Scope) || scope instanceof AST_Arrow);
|
||||
var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||
var inline = compressor.option("inline");
|
||||
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
|
||||
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
|
||||
return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
|
||||
}
|
||||
|
||||
function append_var(decls, expressions, name, value) {
|
||||
var def = name.definition();
|
||||
scope.variables.set(name.name, def);
|
||||
scope.enclosed.push(def);
|
||||
if (!scope.var_names()[name.name]) {
|
||||
scope.var_names()[name.name] = true;
|
||||
decls.push(make_node(AST_VarDef, name, {
|
||||
name: name,
|
||||
value: null
|
||||
}));
|
||||
}
|
||||
var sym = make_node(AST_SymbolRef, name, name);
|
||||
def.references.push(sym);
|
||||
if (value) expressions.push(make_node(AST_Assign, self, {
|
||||
operator: "=",
|
||||
left: sym,
|
||||
right: value
|
||||
}));
|
||||
}
|
||||
|
||||
function flatten_args(decls, expressions) {
|
||||
var len = fn.argnames.length;
|
||||
for (var i = self.args.length; --i >= len;) {
|
||||
expressions.push(self.args[i]);
|
||||
}
|
||||
for (i = len; --i >= 0;) {
|
||||
var name = fn.argnames[i];
|
||||
var value = self.args[i];
|
||||
if (name.__unused || !name.name || scope.var_names()[name.name]) {
|
||||
if (value) expressions.push(value);
|
||||
} else {
|
||||
var symbol = make_node(AST_SymbolVar, name, name);
|
||||
name.definition().orig.push(symbol);
|
||||
if (!value && in_loop) value = make_node(AST_Undefined, self);
|
||||
append_var(decls, expressions, symbol, value);
|
||||
}
|
||||
}
|
||||
decls.reverse();
|
||||
expressions.reverse();
|
||||
}
|
||||
|
||||
function flatten_vars(decls, expressions) {
|
||||
var pos = expressions.length;
|
||||
for (var i = 0, lines = fn.body.length; i < lines; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
for (var j = 0, defs = stat.definitions.length; j < defs; j++) {
|
||||
var var_def = stat.definitions[j];
|
||||
var name = var_def.name;
|
||||
append_var(decls, expressions, name, var_def.value);
|
||||
if (in_loop) {
|
||||
var def = name.definition();
|
||||
var sym = make_node(AST_SymbolRef, name, name);
|
||||
def.references.push(sym);
|
||||
expressions.splice(pos++, 0, make_node(AST_Assign, var_def, {
|
||||
operator: "=",
|
||||
left: sym,
|
||||
right: make_node(AST_Undefined, name)
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function flatten_fn() {
|
||||
var decls = [];
|
||||
var expressions = [];
|
||||
flatten_args(decls, expressions);
|
||||
flatten_vars(decls, expressions);
|
||||
expressions.push(value);
|
||||
if (decls.length) {
|
||||
i = scope.body.indexOf(compressor.parent(level - 1)) + 1;
|
||||
scope.body.splice(i, 0, make_node(AST_Var, fn, {
|
||||
@@ -4343,17 +4585,6 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
function flatten_body(stat) {
|
||||
if (stat instanceof AST_Return) {
|
||||
return stat.value;
|
||||
} else if (stat instanceof AST_SimpleStatement) {
|
||||
return make_node(AST_UnaryPrefix, stat, {
|
||||
operator: "void",
|
||||
expression: stat.body
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
OPT(AST_New, function(self, compressor){
|
||||
@@ -5159,9 +5390,8 @@ merge(Compressor.prototype, {
|
||||
if (reachable) return true;
|
||||
if (node instanceof AST_Scope && node !== self) {
|
||||
var parent = scan_scope.parent();
|
||||
if (!(parent instanceof AST_Call && parent.expression === node)) {
|
||||
node.walk(find_ref);
|
||||
}
|
||||
if (parent instanceof AST_Call && parent.expression === node) return;
|
||||
node.walk(find_ref);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@@ -5595,6 +5825,14 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_Dot, function(self, compressor){
|
||||
if (self.property == "arguments" || self.property == "caller") {
|
||||
compressor.warn("Function.protoype.{prop} not supported [{file}:{line},{col}]", {
|
||||
prop: self.property,
|
||||
file: self.start.file,
|
||||
line: self.start.line,
|
||||
col: self.start.col
|
||||
});
|
||||
}
|
||||
var def = self.resolve_defines(compressor);
|
||||
if (def) {
|
||||
return def.optimize(compressor);
|
||||
@@ -5609,11 +5847,27 @@ merge(Compressor.prototype, {
|
||||
elements: []
|
||||
});
|
||||
break;
|
||||
case "Function":
|
||||
self.expression = make_node(AST_Function, self.expression, {
|
||||
argnames: [],
|
||||
body: []
|
||||
});
|
||||
break;
|
||||
case "Number":
|
||||
self.expression = make_node(AST_Number, self.expression, {
|
||||
value: 0
|
||||
});
|
||||
break;
|
||||
case "Object":
|
||||
self.expression = make_node(AST_Object, self.expression, {
|
||||
properties: []
|
||||
});
|
||||
break;
|
||||
case "RegExp":
|
||||
self.expression = make_node(AST_RegExp, self.expression, {
|
||||
value: /t/
|
||||
});
|
||||
break;
|
||||
case "String":
|
||||
self.expression = make_node(AST_String, self.expression, {
|
||||
value: ""
|
||||
|
||||
@@ -29,7 +29,6 @@ function set_shorthand(name, options, keys) {
|
||||
|
||||
function init_cache(cache) {
|
||||
if (!cache) return;
|
||||
if (!("cname" in cache)) cache.cname = -1;
|
||||
if (!("props" in cache)) {
|
||||
cache.props = new Dictionary();
|
||||
} else if (!(cache.props instanceof Dictionary)) {
|
||||
@@ -39,7 +38,6 @@ function init_cache(cache) {
|
||||
|
||||
function to_json(cache) {
|
||||
return {
|
||||
cname: cache.cname,
|
||||
props: cache.props.toObject()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -557,7 +557,11 @@ function OutputStream(options) {
|
||||
var token = node.end;
|
||||
if (!token) return;
|
||||
var comments = token[tail ? "comments_before" : "comments_after"];
|
||||
if (comments && comments._dumped !== self) {
|
||||
if (comments
|
||||
&& comments._dumped !== self
|
||||
&& (node instanceof AST_Statement || all(comments, function(c) {
|
||||
return !/comment[134]/.test(c.type);
|
||||
}))) {
|
||||
comments._dumped = self;
|
||||
var insert = OUTPUT.length;
|
||||
comments.filter(comment_filter, node).forEach(function(c, i) {
|
||||
@@ -627,7 +631,7 @@ function OutputStream(options) {
|
||||
add_mapping : add_mapping,
|
||||
option : function(opt) { return options[opt] },
|
||||
prepend_comments: readonly ? noop : prepend_comments,
|
||||
append_comments : readonly ? noop : append_comments,
|
||||
append_comments : readonly || comment_filter === return_false ? noop : append_comments,
|
||||
line : function() { return current_line },
|
||||
col : function() { return current_col },
|
||||
pos : function() { return current_pos },
|
||||
|
||||
@@ -1918,12 +1918,14 @@ function parse($TEXT, options) {
|
||||
} else {
|
||||
args = [];
|
||||
}
|
||||
return subscripts(new AST_New({
|
||||
var call = new AST_New({
|
||||
start : start,
|
||||
expression : newexp,
|
||||
args : args,
|
||||
end : prev()
|
||||
}), allow_calls);
|
||||
});
|
||||
mark_pure(call);
|
||||
return subscripts(call, allow_calls);
|
||||
};
|
||||
|
||||
function as_atom_node() {
|
||||
|
||||
@@ -130,12 +130,15 @@ function mangle_properties(ast, options) {
|
||||
if (!Array.isArray(reserved)) reserved = [];
|
||||
if (!options.builtins) find_builtins(reserved);
|
||||
|
||||
var cache = options.cache;
|
||||
if (cache == null) {
|
||||
cache = {
|
||||
cname: -1,
|
||||
props: new Dictionary()
|
||||
};
|
||||
var cname = -1;
|
||||
var cache;
|
||||
if (options.cache) {
|
||||
cache = options.cache.props;
|
||||
cache.each(function(mangled_name) {
|
||||
push_uniq(reserved, mangled_name);
|
||||
});
|
||||
} else {
|
||||
cache = new Dictionary();
|
||||
}
|
||||
|
||||
var regex = options.regex;
|
||||
@@ -192,7 +195,7 @@ function mangle_properties(ast, options) {
|
||||
if (unmangleable.indexOf(name) >= 0) return false;
|
||||
if (reserved.indexOf(name) >= 0) return false;
|
||||
if (options.only_cache) {
|
||||
return cache.props.has(name);
|
||||
return cache.has(name);
|
||||
}
|
||||
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
||||
return true;
|
||||
@@ -201,7 +204,7 @@ function mangle_properties(ast, options) {
|
||||
function should_mangle(name) {
|
||||
if (regex && !regex.test(name)) return false;
|
||||
if (reserved.indexOf(name) >= 0) return false;
|
||||
return cache.props.has(name)
|
||||
return cache.has(name)
|
||||
|| names_to_mangle.indexOf(name) >= 0;
|
||||
}
|
||||
|
||||
@@ -219,7 +222,7 @@ function mangle_properties(ast, options) {
|
||||
return name;
|
||||
}
|
||||
|
||||
var mangled = cache.props.get(name);
|
||||
var mangled = cache.get(name);
|
||||
if (!mangled) {
|
||||
if (debug) {
|
||||
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
||||
@@ -233,11 +236,11 @@ function mangle_properties(ast, options) {
|
||||
// either debug mode is off, or it is on and we could not use the mangled name
|
||||
if (!mangled) {
|
||||
do {
|
||||
mangled = base54(++cache.cname);
|
||||
mangled = base54(++cname);
|
||||
} while (!can_mangle(mangled));
|
||||
}
|
||||
|
||||
cache.props.set(name, mangled);
|
||||
cache.set(name, mangled);
|
||||
}
|
||||
return mangled;
|
||||
}
|
||||
|
||||
73
lib/scope.js
73
lib/scope.js
@@ -43,9 +43,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
function SymbolDef(scope, orig) {
|
||||
function SymbolDef(scope, orig, init) {
|
||||
this.name = orig.name;
|
||||
this.orig = [ orig ];
|
||||
this.init = init;
|
||||
this.eliminated = 0;
|
||||
this.scope = scope;
|
||||
this.references = [];
|
||||
@@ -175,7 +176,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
node.references = [];
|
||||
}
|
||||
if (node instanceof AST_SymbolLambda) {
|
||||
defun.def_function(node);
|
||||
defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||
}
|
||||
else if (node instanceof AST_SymbolDefun) {
|
||||
// Careful here, the scope where this should be defined is
|
||||
@@ -183,10 +184,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
// scope when we encounter the AST_Defun node (which is
|
||||
// instanceof AST_Scope) but we get to the symbol a bit
|
||||
// later.
|
||||
mark_export((node.scope = defun.parent_scope.get_defun_scope()).def_function(node), 1);
|
||||
mark_export((node.scope = defun.parent_scope.get_defun_scope()).def_function(node, defun), 1);
|
||||
}
|
||||
else if (node instanceof AST_SymbolClass) {
|
||||
mark_export(defun.def_variable(node), 1);
|
||||
mark_export(defun.def_variable(node, defun), 1);
|
||||
}
|
||||
else if (node instanceof AST_SymbolImport) {
|
||||
scope.def_variable(node);
|
||||
@@ -194,12 +195,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
else if (node instanceof AST_SymbolDefClass) {
|
||||
// This deals with the name of the class being available
|
||||
// inside the class.
|
||||
mark_export((node.scope = defun.parent_scope).def_function(node), 1);
|
||||
mark_export((node.scope = defun.parent_scope).def_function(node, defun), 1);
|
||||
}
|
||||
else if (node instanceof AST_SymbolVar
|
||||
|| node instanceof AST_SymbolLet
|
||||
|| node instanceof AST_SymbolConst) {
|
||||
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node);
|
||||
var def;
|
||||
if (node instanceof AST_SymbolBlockDeclaration) {
|
||||
def = scope.def_variable(node);
|
||||
} else {
|
||||
def = defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
|
||||
}
|
||||
if (!all(def.orig, function(sym) {
|
||||
if (sym === node) return true;
|
||||
if (node instanceof AST_SymbolBlockDeclaration) {
|
||||
@@ -334,10 +340,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (options.cache) {
|
||||
this.cname = options.cache.cname;
|
||||
}
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("def_global", function(node){
|
||||
@@ -407,29 +409,32 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|
||||
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
||||
var def = this.def_variable(symbol);
|
||||
AST_Scope.DEFMETHOD("def_function", function(symbol, init){
|
||||
var def = this.def_variable(symbol, init);
|
||||
if (!def.init) def.init = init;
|
||||
this.functions.set(symbol.name, def);
|
||||
return def;
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
||||
var def;
|
||||
if (!this.variables.has(symbol.name)) {
|
||||
def = new SymbolDef(this, symbol);
|
||||
AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
|
||||
var def = this.variables.get(symbol.name);
|
||||
if (def) {
|
||||
def.orig.push(symbol);
|
||||
if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) {
|
||||
def.init = init;
|
||||
}
|
||||
} else {
|
||||
def = new SymbolDef(this, symbol, init);
|
||||
this.variables.set(symbol.name, def);
|
||||
def.global = !this.parent_scope;
|
||||
} else {
|
||||
def = this.variables.get(symbol.name);
|
||||
def.orig.push(symbol);
|
||||
}
|
||||
return symbol.thedef = def;
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("next_mangled", function(options){
|
||||
var ext = this.enclosed;
|
||||
function next_mangled(scope, options) {
|
||||
var ext = scope.enclosed;
|
||||
out: while (true) {
|
||||
var m = base54(++this.cname);
|
||||
var m = base54(++scope.cname);
|
||||
if (!is_identifier(m)) continue; // skip over "do"
|
||||
|
||||
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
|
||||
@@ -446,6 +451,18 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
AST_Scope.DEFMETHOD("next_mangled", function(options){
|
||||
return next_mangled(this, options);
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("next_mangled", function(options){
|
||||
var name;
|
||||
do {
|
||||
name = next_mangled(this, options);
|
||||
} while (member(name, this.mangled_names));
|
||||
return name;
|
||||
});
|
||||
|
||||
AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
||||
@@ -459,7 +476,7 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
||||
var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
|
||||
|
||||
while (true) {
|
||||
var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
|
||||
var name = next_mangled(this, options);
|
||||
if (!tricky_name || tricky_name != name)
|
||||
return name;
|
||||
}
|
||||
@@ -511,8 +528,14 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||
var lname = -1;
|
||||
var to_mangle = [];
|
||||
|
||||
var mangled_names = this.mangled_names = [];
|
||||
if (options.cache) {
|
||||
this.globals.each(collect);
|
||||
if (options.cache.props) {
|
||||
options.cache.props.each(function(mangled_name) {
|
||||
push_uniq(mangled_names, mangled_name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var tw = new TreeWalker(function(node, descend){
|
||||
@@ -546,10 +569,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||
def.mangle(options);
|
||||
});
|
||||
|
||||
if (options.cache) {
|
||||
options.cache.cname = this.cname;
|
||||
}
|
||||
|
||||
function collect(symbol) {
|
||||
if (!member(symbol.name, options.reserved)) {
|
||||
to_mangle.push(symbol);
|
||||
|
||||
Reference in New Issue
Block a user