perform reduce_vars on safe literals (#2351)
- constant expression - single reference - same scope - not across loop body
This commit is contained in:
@@ -297,6 +297,8 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||
d.fixed = false;
|
||||
});
|
||||
var in_loop = null;
|
||||
var loop_ids = Object.create(null);
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
@@ -307,7 +309,7 @@ merge(Compressor.prototype, {
|
||||
var d = node.definition();
|
||||
d.references.push(node);
|
||||
if (d.fixed === undefined || !safe_to_read(d)
|
||||
|| is_modified(node, 0, is_immutable(node.fixed_value()))) {
|
||||
|| is_modified(node, 0, is_immutable(node))) {
|
||||
d.fixed = false;
|
||||
} else {
|
||||
var parent = tw.parent();
|
||||
@@ -329,6 +331,7 @@ merge(Compressor.prototype, {
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
};
|
||||
loop_ids[d.id] = in_loop;
|
||||
mark(d, false);
|
||||
descend();
|
||||
} else {
|
||||
@@ -384,6 +387,7 @@ merge(Compressor.prototype, {
|
||||
d.fixed = function() {
|
||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||
};
|
||||
loop_ids[d.id] = in_loop;
|
||||
mark(d, true);
|
||||
} else {
|
||||
d.fixed = false;
|
||||
@@ -431,10 +435,13 @@ merge(Compressor.prototype, {
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_DWLoop) {
|
||||
var saved_loop = in_loop;
|
||||
in_loop = node;
|
||||
push();
|
||||
node.condition.walk(tw);
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
in_loop = saved_loop;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_LabeledStatement) {
|
||||
@@ -445,6 +452,8 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (node instanceof AST_For) {
|
||||
if (node.init) node.init.walk(tw);
|
||||
var saved_loop = in_loop;
|
||||
in_loop = node;
|
||||
if (node.condition) {
|
||||
push();
|
||||
node.condition.walk(tw);
|
||||
@@ -458,14 +467,18 @@ merge(Compressor.prototype, {
|
||||
node.step.walk(tw);
|
||||
pop();
|
||||
}
|
||||
in_loop = saved_loop;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_ForIn) {
|
||||
node.init.walk(suppressor);
|
||||
node.object.walk(tw);
|
||||
var saved_loop = in_loop;
|
||||
in_loop = node;
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
in_loop = saved_loop;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Try) {
|
||||
@@ -535,10 +548,23 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
def.references = [];
|
||||
def.should_replace = undefined;
|
||||
def.single_use = undefined;
|
||||
}
|
||||
|
||||
function is_immutable(value) {
|
||||
return value && value.is_constant() || value instanceof AST_Lambda;
|
||||
function is_immutable(node) {
|
||||
var value = node.fixed_value();
|
||||
if (!value) return false;
|
||||
if (value.is_constant()) return true;
|
||||
if (compressor.option("unused")) {
|
||||
var d = node.definition();
|
||||
if (d.single_use === undefined) {
|
||||
d.single_use = loop_ids[d.id] === in_loop
|
||||
&& d.scope === node.scope
|
||||
&& value.is_constant_expression();
|
||||
}
|
||||
if (d.references.length == 1 && d.single_use) return true;
|
||||
}
|
||||
return value instanceof AST_Lambda;
|
||||
}
|
||||
|
||||
function is_modified(node, level, immutable) {
|
||||
@@ -2115,6 +2141,22 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
def(AST_Node, return_false);
|
||||
def(AST_Constant, return_true);
|
||||
def(AST_Function, function(){
|
||||
var self = this;
|
||||
var result = true;
|
||||
self.walk(new TreeWalker(function(node) {
|
||||
if (!result) return true;
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var def = node.definition();
|
||||
if (self.enclosed.indexOf(def) >= 0
|
||||
&& self.variables.get(def.name) !== def) {
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}));
|
||||
return result;
|
||||
});
|
||||
def(AST_Unary, function(){
|
||||
return this.expression.is_constant_expression();
|
||||
});
|
||||
@@ -4078,12 +4120,13 @@ merge(Compressor.prototype, {
|
||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||
}
|
||||
if (compressor.option("unused")
|
||||
&& fixed instanceof AST_Function
|
||||
&& d.references.length == 1
|
||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
||||
&& !d.scope.uses_eval
|
||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope) {
|
||||
return fixed.clone(true);
|
||||
&& (d.single_use || fixed instanceof AST_Function
|
||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
||||
&& !d.scope.uses_eval
|
||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope)) {
|
||||
var value = fixed.optimize(compressor);
|
||||
return value === fixed ? fixed.clone(true) : value;
|
||||
}
|
||||
if (compressor.option("evaluate") && fixed) {
|
||||
if (d.should_replace === undefined) {
|
||||
|
||||
Reference in New Issue
Block a user