Merge remote-tracking branch 'refs/remotes/mishoo/master'
This commit is contained in:
commit
77042d50ba
46
lib/ast.js
46
lib/ast.js
|
|
@ -145,12 +145,13 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
function walk_body(node, visitor) {
|
function walk_body(node, visitor) {
|
||||||
if (node.body instanceof AST_Statement) {
|
var body = node.body;
|
||||||
node.body._walk(visitor);
|
if (body instanceof AST_Statement) {
|
||||||
|
body._walk(visitor);
|
||||||
|
}
|
||||||
|
else for (var i = 0, len = body.length; i < len; i++) {
|
||||||
|
body[i]._walk(visitor);
|
||||||
}
|
}
|
||||||
else node.body.forEach(function(stat){
|
|
||||||
stat._walk(visitor);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var AST_Block = DEFNODE("Block", "body", {
|
var AST_Block = DEFNODE("Block", "body", {
|
||||||
|
|
@ -371,9 +372,10 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
if (this.name) this.name._walk(visitor);
|
if (this.name) this.name._walk(visitor);
|
||||||
this.argnames.forEach(function(arg){
|
var argnames = this.argnames;
|
||||||
arg._walk(visitor);
|
for (var i = 0, len = argnames.length; i < len; i++) {
|
||||||
});
|
argnames[i]._walk(visitor);
|
||||||
|
}
|
||||||
walk_body(this, visitor);
|
walk_body(this, visitor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -533,9 +535,10 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
this.definitions.forEach(function(def){
|
var definitions = this.definitions;
|
||||||
def._walk(visitor);
|
for (var i = 0, len = definitions.length; i < len; i++) {
|
||||||
});
|
definitions[i]._walk(visitor);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
@ -573,9 +576,10 @@ var AST_Call = DEFNODE("Call", "expression args", {
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
this.expression._walk(visitor);
|
this.expression._walk(visitor);
|
||||||
this.args.forEach(function(arg){
|
var args = this.args;
|
||||||
arg._walk(visitor);
|
for (var i = 0, len = args.length; i < len; i++) {
|
||||||
});
|
args[i]._walk(visitor);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -742,9 +746,10 @@ var AST_Array = DEFNODE("Array", "elements", {
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
this.elements.forEach(function(el){
|
var elements = this.elements;
|
||||||
el._walk(visitor);
|
for (var i = 0, len = elements.length; i < len; i++) {
|
||||||
});
|
elements[i]._walk(visitor);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -756,9 +761,10 @@ var AST_Object = DEFNODE("Object", "properties", {
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
this.properties.forEach(function(prop){
|
var properties = this.properties;
|
||||||
prop._walk(visitor);
|
for (var i = 0, len = properties.length; i < len; i++) {
|
||||||
});
|
properties[i]._walk(visitor);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ merge(Compressor.prototype, {
|
||||||
var passes = +this.options.passes || 1;
|
var passes = +this.options.passes || 1;
|
||||||
for (var pass = 0; pass < passes && pass < 3; ++pass) {
|
for (var pass = 0; pass < passes && pass < 3; ++pass) {
|
||||||
if (pass > 0 || this.option("reduce_vars"))
|
if (pass > 0 || this.option("reduce_vars"))
|
||||||
node.reset_opt_flags(this);
|
node.reset_opt_flags(this, true);
|
||||||
node = node.transform(this);
|
node = node.transform(this);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
|
|
@ -178,28 +178,26 @@ merge(Compressor.prototype, {
|
||||||
return this.print_to_string() == node.print_to_string();
|
return this.print_to_string() == node.print_to_string();
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor){
|
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan){
|
||||||
var reduce_vars = compressor.option("reduce_vars");
|
var reduce_vars = rescan && compressor.option("reduce_vars");
|
||||||
|
var unsafe = compressor.option("unsafe");
|
||||||
var tw = new TreeWalker(function(node){
|
var tw = new TreeWalker(function(node){
|
||||||
if (reduce_vars && node instanceof AST_Scope) {
|
if (reduce_vars) {
|
||||||
node.variables.each(function(def) {
|
if (node instanceof AST_Toplevel) node.globals.each(reset_def);
|
||||||
delete def.modified;
|
if (node instanceof AST_Scope) node.variables.each(reset_def);
|
||||||
});
|
if (node instanceof AST_SymbolRef) {
|
||||||
}
|
var d = node.definition();
|
||||||
if (node instanceof AST_SymbolRef) {
|
d.references.push(node);
|
||||||
var d = node.definition();
|
if (!d.modified && (d.orig.length > 1 || isModified(node, 0))) {
|
||||||
if (d.init) {
|
d.modified = true;
|
||||||
delete d.init._evaluated;
|
}
|
||||||
}
|
}
|
||||||
if (reduce_vars && (d.orig.length > 1 || isModified(node, 0))) {
|
if (node instanceof AST_Call && node.expression instanceof AST_Function) {
|
||||||
d.modified = true;
|
node.expression.argnames.forEach(function(arg, i) {
|
||||||
|
arg.definition().init = node.args[i] || make_node(AST_Undefined, node);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (reduce_vars && node instanceof AST_Call && node.expression instanceof AST_Function) {
|
|
||||||
node.expression.argnames.forEach(function(arg, i) {
|
|
||||||
arg.definition().init = node.args[i] || make_node(AST_Undefined, node);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
|
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
|
||||||
node._squeezed = false;
|
node._squeezed = false;
|
||||||
node._optimized = false;
|
node._optimized = false;
|
||||||
|
|
@ -207,10 +205,18 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
this.walk(tw);
|
this.walk(tw);
|
||||||
|
|
||||||
|
function reset_def(def) {
|
||||||
|
def.modified = false;
|
||||||
|
def.references = [];
|
||||||
|
def.should_replace = undefined;
|
||||||
|
if (unsafe && def.init) {
|
||||||
|
def.init._evaluated = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isModified(node, level) {
|
function isModified(node, level) {
|
||||||
var parent = tw.parent(level);
|
var parent = tw.parent(level);
|
||||||
if (parent instanceof AST_Unary && (parent.operator === "++" || parent.operator === "--")
|
if (isLHS(node, parent)
|
||||||
|| parent instanceof AST_Assign && parent.left === node
|
|
||||||
|| parent instanceof AST_Call && parent.expression === node) {
|
|| parent instanceof AST_Call && parent.expression === node) {
|
||||||
return true;
|
return true;
|
||||||
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||||
|
|
@ -1255,7 +1261,7 @@ merge(Compressor.prototype, {
|
||||||
var d = this.definition();
|
var d = this.definition();
|
||||||
if (compressor.option("reduce_vars") && !d.modified && d.init) {
|
if (compressor.option("reduce_vars") && !d.modified && d.init) {
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
if (!HOP(d.init, '_evaluated')) {
|
if (d.init._evaluated === undefined) {
|
||||||
d.init._evaluated = ev(d.init, compressor);
|
d.init._evaluated = ev(d.init, compressor);
|
||||||
}
|
}
|
||||||
return d.init._evaluated;
|
return d.init._evaluated;
|
||||||
|
|
@ -1906,7 +1912,7 @@ merge(Compressor.prototype, {
|
||||||
// returned if nothing changed.
|
// returned if nothing changed.
|
||||||
function trim(nodes, compressor, first_in_statement) {
|
function trim(nodes, compressor, first_in_statement) {
|
||||||
var ret = [], changed = false;
|
var ret = [], changed = false;
|
||||||
for (var i = 0, ii = nodes.length; i < ii; i++) {
|
for (var i = 0, len = nodes.length; i < len; i++) {
|
||||||
var node = nodes[i].drop_side_effect_free(compressor, first_in_statement);
|
var node = nodes[i].drop_side_effect_free(compressor, first_in_statement);
|
||||||
changed |= node !== nodes[i];
|
changed |= node !== nodes[i];
|
||||||
if (node) {
|
if (node) {
|
||||||
|
|
@ -2404,9 +2410,6 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Call, function(self, compressor){
|
OPT(AST_Call, function(self, compressor){
|
||||||
self.args = self.args.map(function(arg) {
|
|
||||||
return arg.evaluate(compressor)[0];
|
|
||||||
});
|
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
||||||
|
|
@ -3065,18 +3068,24 @@ merge(Compressor.prototype, {
|
||||||
return make_node(AST_Infinity, self).transform(compressor);
|
return make_node(AST_Infinity, self).transform(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate")
|
if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
|
||||||
&& compressor.option("reduce_vars")
|
|
||||||
&& !isLHS(self, compressor.parent())) {
|
|
||||||
var d = self.definition();
|
var d = self.definition();
|
||||||
if (d.constant && !d.modified && d.init && d.init.is_constant(compressor)) {
|
if (!d.modified && d.init) {
|
||||||
var original_as_string = self.print_to_string();
|
if (d.should_replace === undefined) {
|
||||||
var const_node = make_node_from_constant(compressor, d.init.constant_value(compressor), self);
|
var init = d.init.evaluate(compressor);
|
||||||
var const_node_as_string = const_node.print_to_string();
|
if (init.length > 1) {
|
||||||
var per_const_overhead = d.global || !d.references.length ? 0
|
var value = init[0].print_to_string().length;
|
||||||
: (d.name.length + 2 + const_node_as_string.length) / d.references.length;
|
var name = d.name.length;
|
||||||
if (const_node_as_string.length <= original_as_string.length + per_const_overhead)
|
var freq = d.references.length;
|
||||||
return const_node;
|
var overhead = d.global || !freq ? 0 : (name + 2 + value) / freq;
|
||||||
|
d.should_replace = value <= name + overhead ? init[0] : false;
|
||||||
|
} else {
|
||||||
|
d.should_replace = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d.should_replace) {
|
||||||
|
return d.should_replace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ function SymbolDef(scope, index, orig) {
|
||||||
this.global = false;
|
this.global = false;
|
||||||
this.mangled_name = null;
|
this.mangled_name = null;
|
||||||
this.undeclared = false;
|
this.undeclared = false;
|
||||||
this.constant = false;
|
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.id = SymbolDef.next_id++;
|
this.id = SymbolDef.next_id++;
|
||||||
};
|
};
|
||||||
|
|
@ -156,7 +155,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||||
else if (node instanceof AST_SymbolVar
|
else if (node instanceof AST_SymbolVar
|
||||||
|| node instanceof AST_SymbolConst) {
|
|| node instanceof AST_SymbolConst) {
|
||||||
var def = defun.def_variable(node);
|
var def = defun.def_variable(node);
|
||||||
def.constant = node instanceof AST_SymbolConst;
|
|
||||||
def.init = tw.parent().value;
|
def.init = tw.parent().value;
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolCatch) {
|
else if (node instanceof AST_SymbolCatch) {
|
||||||
|
|
|
||||||
|
|
@ -615,7 +615,7 @@ call_args: {
|
||||||
const a = 1;
|
const a = 1;
|
||||||
console.log(1);
|
console.log(1);
|
||||||
+function(a) {
|
+function(a) {
|
||||||
return a;
|
return 1;
|
||||||
}(1);
|
}(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,8 +134,8 @@ modified: {
|
||||||
}
|
}
|
||||||
|
|
||||||
function f2() {
|
function f2() {
|
||||||
var b = 2, c = 3;
|
var b = 2;
|
||||||
b = c;
|
b = 3;
|
||||||
console.log(1 + b);
|
console.log(1 + b);
|
||||||
console.log(b + 3);
|
console.log(b + 3);
|
||||||
console.log(4);
|
console.log(4);
|
||||||
|
|
@ -143,8 +143,8 @@ modified: {
|
||||||
}
|
}
|
||||||
|
|
||||||
function f3() {
|
function f3() {
|
||||||
var b = 2, c = 3;
|
var b = 2;
|
||||||
b *= c;
|
b *= 3;
|
||||||
console.log(1 + b);
|
console.log(1 + b);
|
||||||
console.log(b + 3);
|
console.log(b + 3);
|
||||||
console.log(4);
|
console.log(4);
|
||||||
|
|
@ -236,7 +236,7 @@ unsafe_evaluate_object: {
|
||||||
function f0(){
|
function f0(){
|
||||||
var a = 1;
|
var a = 1;
|
||||||
var b = {};
|
var b = {};
|
||||||
b[a] = 2;
|
b[1] = 2;
|
||||||
console.log(4);
|
console.log(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,7 +280,7 @@ unsafe_evaluate_array: {
|
||||||
function f0(){
|
function f0(){
|
||||||
var a = 1;
|
var a = 1;
|
||||||
var b = [];
|
var b = [];
|
||||||
b[a] = 2;
|
b[1] = 2;
|
||||||
console.log(4);
|
console.log(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,8 +373,8 @@ passes: {
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
var b = 2, c = 3;
|
var b = 2;
|
||||||
b = c;
|
b = 3;
|
||||||
console.log(1 + b);
|
console.log(1 + b);
|
||||||
console.log(b + 3);
|
console.log(b + 3);
|
||||||
console.log(4);
|
console.log(4);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ describe("comment before constant", function() {
|
||||||
it("Should test comment before constant is retained and output after mangle.", function() {
|
it("Should test comment before constant is retained and output after mangle.", function() {
|
||||||
var result = Uglify.minify(js, {
|
var result = Uglify.minify(js, {
|
||||||
fromString: true,
|
fromString: true,
|
||||||
compress: { collapse_vars: false },
|
compress: { collapse_vars: false, reduce_vars: false },
|
||||||
mangle: {},
|
mangle: {},
|
||||||
output: { comments: true },
|
output: { comments: true },
|
||||||
});
|
});
|
||||||
|
|
@ -17,9 +17,9 @@ describe("comment before constant", function() {
|
||||||
it("Should test code works when comments disabled.", function() {
|
it("Should test code works when comments disabled.", function() {
|
||||||
var result = Uglify.minify(js, {
|
var result = Uglify.minify(js, {
|
||||||
fromString: true,
|
fromString: true,
|
||||||
compress: { collapse_vars: false },
|
compress: { collapse_vars: false, reduce_vars: false },
|
||||||
mangle: {},
|
mangle: {},
|
||||||
output: {},
|
output: { comments: false },
|
||||||
});
|
});
|
||||||
assert.strictEqual(result.code, 'function f(){var n=!1;return n}');
|
assert.strictEqual(result.code, 'function f(){var n=!1;return n}');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user