[WIP] improve compression of undefined, NaN & Infinitiy

Maintains identical behaviour, but move all the transformation logic from `OutputStream` to `Compressor`.
This commit is contained in:
alexlamsl 2017-03-31 19:26:59 +08:00
parent 1ddc05725d
commit da0273e805
2 changed files with 57 additions and 43 deletions

View File

@ -215,7 +215,12 @@ merge(Compressor.prototype, {
}) : make_node(AST_EmptyStatement, node); }) : make_node(AST_EmptyStatement, node);
} }
return make_node(AST_SimpleStatement, node, { return make_node(AST_SimpleStatement, node, {
body: node.value || make_node(AST_Undefined, node) body: node.value || make_node(AST_UnaryPrefix, node, {
operator: "void",
expression: make_node(AST_Number, node, {
value: 0
})
})
}); });
} }
if (node instanceof AST_Lambda && node !== self) { if (node instanceof AST_Lambda && node !== self) {
@ -1123,8 +1128,12 @@ merge(Compressor.prototype, {
})); }));
}; };
function is_undefined(node) { function is_undefined(node, compressor) {
return node instanceof AST_Undefined || node.is_undefined; return node.is_undefined
|| node instanceof AST_Undefined
|| node instanceof AST_UnaryPrefix
&& node.operator == "void"
&& !node.expression.has_side_effects(compressor);
} }
/* -----[ boolean/negation helpers ]----- */ /* -----[ boolean/negation helpers ]----- */
@ -1313,7 +1322,7 @@ merge(Compressor.prototype, {
return this; return this;
} }
}); });
var unaryPrefix = makePredicate("! ~ - +"); var unaryPrefix = makePredicate("! ~ - + void");
AST_Node.DEFMETHOD("is_constant", function(){ AST_Node.DEFMETHOD("is_constant", function(){
// Accomodate when compress option evaluate=false // Accomodate when compress option evaluate=false
// as well as the common constant expressions !0 and -1 // as well as the common constant expressions !0 and -1
@ -2971,7 +2980,7 @@ merge(Compressor.prototype, {
} }
} }
} }
if (is_undefined(self.cdr)) { if (is_undefined(self.cdr, compressor)) {
return make_node(AST_UnaryPrefix, self, { return make_node(AST_UnaryPrefix, self, {
operator : "void", operator : "void",
expression : self.car expression : self.car
@ -3010,7 +3019,7 @@ merge(Compressor.prototype, {
self.expression = e; self.expression = e;
return self; return self;
} else { } else {
return make_node(AST_Undefined, self).transform(compressor); return make_node(AST_Undefined, self).optimize(compressor);
} }
} }
if (compressor.option("booleans") && compressor.in_boolean_context()) { if (compressor.option("booleans") && compressor.in_boolean_context()) {
@ -3034,6 +3043,9 @@ merge(Compressor.prototype, {
})).optimize(compressor); })).optimize(compressor);
} }
} }
if (self.operator == "-" && e instanceof AST_Infinity) {
e = e.transform(compressor);
}
if (e instanceof AST_Binary if (e instanceof AST_Binary
&& (self.operator == "+" || self.operator == "-") && (self.operator == "+" || self.operator == "-")
&& (e.operator == "*" || e.operator == "/" || e.operator == "%")) { && (e.operator == "*" || e.operator == "/" || e.operator == "%")) {
@ -3043,8 +3055,7 @@ merge(Compressor.prototype, {
} }
// avoids infinite recursion of numerals // avoids infinite recursion of numerals
if (self.operator != "-" if (self.operator != "-"
|| !(self.expression instanceof AST_Number || !(e instanceof AST_Number || e instanceof AST_Infinity)) {
|| self.expression instanceof AST_Infinity)) {
var ev = self.evaluate(compressor); var ev = self.evaluate(compressor);
if (ev !== self) { if (ev !== self) {
ev = make_node_from_constant(ev, self).optimize(compressor); ev = make_node_from_constant(ev, self).optimize(compressor);
@ -3087,8 +3098,8 @@ merge(Compressor.prototype, {
OPT(AST_Binary, function(self, compressor){ OPT(AST_Binary, function(self, compressor){
function reversible() { function reversible() {
return self.left instanceof AST_Constant return self.left.is_constant()
|| self.right instanceof AST_Constant || self.right.is_constant()
|| !self.left.has_side_effects(compressor) || !self.left.has_side_effects(compressor)
&& !self.right.has_side_effects(compressor); && !self.right.has_side_effects(compressor);
} }
@ -3101,8 +3112,8 @@ merge(Compressor.prototype, {
} }
} }
if (commutativeOperators(self.operator)) { if (commutativeOperators(self.operator)) {
if (self.right instanceof AST_Constant if (self.right.is_constant()
&& !(self.left instanceof AST_Constant)) { && !self.left.is_constant()) {
// if right is a constant, whatever side effects the // if right is a constant, whatever side effects the
// left side might have could not influence the // left side might have could not influence the
// result. hence, force switch. // result. hence, force switch.
@ -3464,9 +3475,9 @@ merge(Compressor.prototype, {
case "undefined": case "undefined":
return make_node(AST_Undefined, self).optimize(compressor); return make_node(AST_Undefined, self).optimize(compressor);
case "NaN": case "NaN":
return make_node(AST_NaN, self); return make_node(AST_NaN, self).optimize(compressor);
case "Infinity": case "Infinity":
return make_node(AST_Infinity, self); return make_node(AST_Infinity, self).optimize(compressor);
} }
} }
if (compressor.option("evaluate") && compressor.option("reduce_vars")) { if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
@ -3508,7 +3519,36 @@ merge(Compressor.prototype, {
return ref; return ref;
} }
} }
return self; return make_node(AST_UnaryPrefix, self, {
operator: "void",
expression: make_node(AST_Number, self, {
value: 0
})
});
});
OPT(AST_Infinity, function(self, compressor){
return make_node(AST_Binary, self, {
operator: "/",
left: make_node(AST_Number, self, {
value: 1
}),
right: make_node(AST_Number, self, {
value: 0
})
});
});
OPT(AST_NaN, function(self, compressor){
return make_node(AST_Binary, self, {
operator: "/",
left: make_node(AST_Number, self, {
value: 0
}),
right: make_node(AST_Number, self, {
value: 0
})
});
}); });
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ]; var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
@ -3809,7 +3849,7 @@ merge(Compressor.prototype, {
OPT(AST_RegExp, literals_in_boolean_context); OPT(AST_RegExp, literals_in_boolean_context);
OPT(AST_Return, function(self, compressor){ OPT(AST_Return, function(self, compressor){
if (self.value && is_undefined(self.value)) { if (self.value && is_undefined(self.value, compressor)) {
self.value = null; self.value = null;
} }
return self; return self;

View File

@ -586,21 +586,12 @@ function OutputStream(options) {
return first_in_statement(output); return first_in_statement(output);
}); });
PARENS([ AST_Unary, AST_Undefined ], function(output){ PARENS(AST_Unary, function(output){
var p = output.parent(); var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this; || p instanceof AST_Call && p.expression === this;
}); });
PARENS([ AST_Infinity, AST_NaN ], function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this
|| p instanceof AST_Unary && p.operator != "+" && p.operator != "-"
|| p instanceof AST_Binary && p.right === this
&& (p.operator == "/" || p.operator == "%");
});
PARENS(AST_Seq, function(output){ PARENS(AST_Seq, function(output){
var p = output.parent(); var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
@ -1258,24 +1249,7 @@ function OutputStream(options) {
var def = self.definition(); var def = self.definition();
output.print_name(def ? def.mangled_name || def.name : self.name); output.print_name(def ? def.mangled_name || def.name : self.name);
}); });
DEFPRINT(AST_Undefined, function(self, output){
output.print("void 0");
});
DEFPRINT(AST_Hole, noop); DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_Infinity, function(self, output){
output.print("1");
output.space();
output.print("/");
output.space();
output.print("0");
});
DEFPRINT(AST_NaN, function(self, output){
output.print("0");
output.space();
output.print("/");
output.space();
output.print("0");
});
DEFPRINT(AST_This, function(self, output){ DEFPRINT(AST_This, function(self, output){
output.print("this"); output.print("this");
}); });