151
lib/compress.js
151
lib/compress.js
@@ -868,6 +868,21 @@ merge(Compressor.prototype, {
|
||||
var stat_index = statements.length;
|
||||
var scanner = new TreeTransformer(function(node, descend) {
|
||||
if (abort) return node;
|
||||
// Scan case expressions first in a switch statement
|
||||
if (node instanceof AST_Switch) {
|
||||
node.expression = node.expression.transform(scanner);
|
||||
for (var i = 0, len = node.body.length; !abort && i < len; i++) {
|
||||
var branch = node.body[i];
|
||||
if (branch instanceof AST_Case)
|
||||
branch.expression = branch.expression.transform(scanner);
|
||||
}
|
||||
for (i = 0; !abort && i < len; i++) {
|
||||
var branch = node.body[i];
|
||||
for (var j = 0, len2 = branch.body.length; j < len2; j++)
|
||||
branch.body[j] = branch.body[j].transform(scanner);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
// Skip nodes before `candidate` as quickly as possible
|
||||
if (!hit) {
|
||||
if (node === candidate) {
|
||||
@@ -944,17 +959,17 @@ merge(Compressor.prototype, {
|
||||
|| side_effects && !references_in_scope(node.definition()))
|
||||
|| (sym = lhs_or_def(node))
|
||||
&& (sym instanceof AST_PropAccess || sym.name in lvalues)
|
||||
|| may_throw && node.has_side_effects(compressor)
|
||||
|| (side_effects || !replace_all)
|
||||
&& (parent instanceof AST_Binary && lazy_op(parent.operator)
|
||||
|| parent instanceof AST_Case
|
||||
|| parent instanceof AST_Conditional
|
||||
|| parent instanceof AST_If)) {
|
||||
if (!(node instanceof AST_Scope)) descend(node, scanner);
|
||||
abort = true;
|
||||
return node;
|
||||
}
|
||||
// Skip (non-executed) functions and (leading) default case in switch statements
|
||||
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
||||
// Skip (non-executed) functions
|
||||
if (node instanceof AST_Scope) return node;
|
||||
});
|
||||
var multi_replacer = new TreeTransformer(function(node) {
|
||||
if (abort) return node;
|
||||
@@ -1000,6 +1015,7 @@ merge(Compressor.prototype, {
|
||||
replace_all = def.references.length - def.replaced == 1;
|
||||
}
|
||||
var side_effects = value_has_side_effects(candidate);
|
||||
var may_throw = candidate.may_throw(compressor);
|
||||
var funarg = candidate.name instanceof AST_SymbolFunarg;
|
||||
var hit = funarg;
|
||||
var abort = false, replaced = 0, can_replace = !args || !hit;
|
||||
@@ -2200,15 +2216,6 @@ merge(Compressor.prototype, {
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_This, return_false);
|
||||
|
||||
def(AST_Call, function(compressor){
|
||||
if (!this.is_expr_pure(compressor)) return true;
|
||||
for (var i = this.args.length; --i >= 0;) {
|
||||
if (this.args[i].has_side_effects(compressor))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
function any(list, compressor) {
|
||||
for (var i = list.length; --i >= 0;)
|
||||
if (list[i].has_side_effects(compressor))
|
||||
@@ -2219,6 +2226,10 @@ merge(Compressor.prototype, {
|
||||
def(AST_Block, function(compressor){
|
||||
return any(this.body, compressor);
|
||||
});
|
||||
def(AST_Call, function(compressor){
|
||||
return !this.is_expr_pure(compressor)
|
||||
|| any(this.args, compressor);
|
||||
});
|
||||
def(AST_Switch, function(compressor){
|
||||
return this.expression.has_side_effects(compressor)
|
||||
|| any(this.body, compressor);
|
||||
@@ -2243,8 +2254,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_SimpleStatement, function(compressor){
|
||||
return this.body.has_side_effects(compressor);
|
||||
});
|
||||
def(AST_Defun, return_true);
|
||||
def(AST_Function, return_false);
|
||||
def(AST_Lambda, return_false);
|
||||
def(AST_Binary, function(compressor){
|
||||
return this.left.has_side_effects(compressor)
|
||||
|| this.right.has_side_effects(compressor);
|
||||
@@ -2282,14 +2292,121 @@ merge(Compressor.prototype, {
|
||||
|| this.property.has_side_effects(compressor);
|
||||
});
|
||||
def(AST_Sequence, function(compressor){
|
||||
return this.expressions.some(function(expression, index) {
|
||||
return expression.has_side_effects(compressor);
|
||||
});
|
||||
return any(this.expressions, compressor);
|
||||
});
|
||||
def(AST_Definitions, function(compressor){
|
||||
return any(this.definitions, compressor);
|
||||
});
|
||||
def(AST_VarDef, function(compressor){
|
||||
return this.value;
|
||||
});
|
||||
})(function(node, func){
|
||||
node.DEFMETHOD("has_side_effects", func);
|
||||
});
|
||||
|
||||
// determine if expression may throw
|
||||
(function(def){
|
||||
def(AST_Node, return_true);
|
||||
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_EmptyStatement, return_false);
|
||||
def(AST_Lambda, return_false);
|
||||
def(AST_SymbolDeclaration, return_false);
|
||||
def(AST_This, return_false);
|
||||
|
||||
function any(list, compressor) {
|
||||
for (var i = list.length; --i >= 0;)
|
||||
if (list[i].may_throw(compressor))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
def(AST_Array, function(compressor){
|
||||
return any(this.elements, compressor);
|
||||
});
|
||||
def(AST_Assign, function(compressor){
|
||||
return this.operator != "=" && this.left.may_throw(compressor)
|
||||
|| this.right.may_throw(compressor);
|
||||
});
|
||||
def(AST_Binary, function(compressor){
|
||||
return this.left.may_throw(compressor)
|
||||
|| this.right.may_throw(compressor);
|
||||
});
|
||||
def(AST_Block, function(compressor){
|
||||
return any(this.body, compressor);
|
||||
});
|
||||
def(AST_Call, function(compressor){
|
||||
if (any(this.args, compressor)) return true;
|
||||
if (this.is_expr_pure(compressor)) return false;
|
||||
if (this.expression.may_throw(compressor)) return true;
|
||||
return !(this.expression instanceof AST_Lambda)
|
||||
|| any(this.expression.body, compressor);
|
||||
});
|
||||
def(AST_Case, function(compressor){
|
||||
return this.expression.may_throw(compressor)
|
||||
|| any(this.body, compressor);
|
||||
});
|
||||
def(AST_Conditional, function(compressor){
|
||||
return this.condition.may_throw(compressor)
|
||||
|| this.consequent.may_throw(compressor)
|
||||
|| this.alternative.may_throw(compressor);
|
||||
});
|
||||
def(AST_Definitions, function(compressor){
|
||||
return any(this.definitions, compressor);
|
||||
});
|
||||
def(AST_Dot, function(compressor){
|
||||
return this.expression.may_throw_on_access(compressor)
|
||||
|| this.expression.may_throw(compressor);
|
||||
});
|
||||
def(AST_If, function(compressor){
|
||||
return this.condition.may_throw(compressor)
|
||||
|| this.body && this.body.may_throw(compressor)
|
||||
|| this.alternative && this.alternative.may_throw(compressor);
|
||||
});
|
||||
def(AST_LabeledStatement, function(compressor){
|
||||
return this.body.may_throw(compressor);
|
||||
});
|
||||
def(AST_Object, function(compressor){
|
||||
return any(this.properties, compressor);
|
||||
});
|
||||
def(AST_ObjectProperty, function(compressor){
|
||||
return this.value.may_throw(compressor);
|
||||
});
|
||||
def(AST_Sequence, function(compressor){
|
||||
return any(this.expressions, compressor);
|
||||
});
|
||||
def(AST_SimpleStatement, function(compressor){
|
||||
return this.body.may_throw(compressor);
|
||||
});
|
||||
def(AST_Sub, function(compressor){
|
||||
return this.expression.may_throw_on_access(compressor)
|
||||
|| this.expression.may_throw(compressor)
|
||||
|| this.property.may_throw(compressor);
|
||||
});
|
||||
def(AST_Switch, function(compressor){
|
||||
return this.expression.may_throw(compressor)
|
||||
|| any(this.body, compressor);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor){
|
||||
return !this.is_declared(compressor);
|
||||
});
|
||||
def(AST_Try, function(compressor){
|
||||
return any(this.body, compressor)
|
||||
|| this.bcatch && this.bcatch.may_throw(compressor)
|
||||
|| this.bfinally && this.bfinally.may_throw(compressor);
|
||||
});
|
||||
def(AST_Unary, function(compressor){
|
||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
|
||||
return false;
|
||||
return this.expression.may_throw(compressor);
|
||||
});
|
||||
def(AST_VarDef, function(compressor){
|
||||
return this.value.may_throw(compressor);
|
||||
});
|
||||
})(function(node, func){
|
||||
node.DEFMETHOD("may_throw", func);
|
||||
});
|
||||
|
||||
// determine if expression is constant
|
||||
(function(def){
|
||||
function all(list) {
|
||||
|
||||
Reference in New Issue
Block a user