Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30761eede5 | ||
|
|
fb30aeccaf | ||
|
|
226aa1f76b | ||
|
|
6e235602fb | ||
|
|
980fcbb56b | ||
|
|
375ebe316d | ||
|
|
2500930234 | ||
|
|
2f0da2ff05 | ||
|
|
83a3cbf151 | ||
|
|
da8d154571 |
184
lib/compress.js
184
lib/compress.js
@@ -325,22 +325,22 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var lhs = is_lhs(node, parent);
|
var lhs = is_lhs(node, parent);
|
||||||
if (lhs) return lhs;
|
if (lhs) return lhs;
|
||||||
if (!immutable
|
if (parent instanceof AST_Array) return is_modified(compressor, tw, parent, parent, level + 1);
|
||||||
&& parent instanceof AST_Call
|
if (parent instanceof AST_Call) {
|
||||||
&& parent.expression === node
|
return !immutable
|
||||||
&& !parent.is_expr_pure(compressor)
|
&& parent.expression === node
|
||||||
&& (!(value instanceof AST_Function)
|
&& !parent.is_expr_pure(compressor)
|
||||||
|| !(parent instanceof AST_New) && value.contains_this())) {
|
&& (!(value instanceof AST_Function)
|
||||||
return true;
|
|| !(parent instanceof AST_New) && value.contains_this());
|
||||||
}
|
}
|
||||||
if (parent instanceof AST_Array) {
|
if (parent instanceof AST_ForIn) return parent.init === node;
|
||||||
return is_modified(compressor, tw, parent, parent, level + 1);
|
if (parent instanceof AST_ObjectKeyVal) {
|
||||||
}
|
if (parent.value !== node) return;
|
||||||
if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
|
|
||||||
var obj = tw.parent(level + 1);
|
var obj = tw.parent(level + 1);
|
||||||
return is_modified(compressor, tw, obj, obj, level + 2);
|
return is_modified(compressor, tw, obj, obj, level + 2);
|
||||||
}
|
}
|
||||||
if (parent instanceof AST_PropAccess && parent.expression === node) {
|
if (parent instanceof AST_PropAccess) {
|
||||||
|
if (parent.expression !== node) return;
|
||||||
var prop = read_property(value, parent);
|
var prop = read_property(value, parent);
|
||||||
return (!immutable || recursive) && is_modified(compressor, tw, parent, prop, level + 1);
|
return (!immutable || recursive) && is_modified(compressor, tw, parent, prop, level + 1);
|
||||||
}
|
}
|
||||||
@@ -514,33 +514,41 @@ merge(Compressor.prototype, {
|
|||||||
|| value instanceof AST_This;
|
|| value instanceof AST_This;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function has_escaped(d, node, parent) {
|
||||||
|
if (parent instanceof AST_Assign) return parent.operator == "=" && parent.right === node;
|
||||||
|
if (parent instanceof AST_Call) return parent.expression !== node || parent instanceof AST_New;
|
||||||
|
if (parent instanceof AST_Exit) return parent.value === node && node.scope !== d.scope;
|
||||||
|
if (parent instanceof AST_VarDef) return parent.value === node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function value_in_use(node, parent) {
|
||||||
|
if (parent instanceof AST_Array) return true;
|
||||||
|
if (parent instanceof AST_Binary) return lazy_op[parent.operator];
|
||||||
|
if (parent instanceof AST_Conditional) return parent.condition !== node;
|
||||||
|
if (parent instanceof AST_Sequence) return parent.tail_node() === node;
|
||||||
|
}
|
||||||
|
|
||||||
function mark_escaped(tw, d, scope, node, value, level, depth) {
|
function mark_escaped(tw, d, scope, node, value, level, depth) {
|
||||||
var parent = tw.parent(level);
|
var parent = tw.parent(level);
|
||||||
if (value && value.is_constant()) return;
|
if (value && value.is_constant()) return;
|
||||||
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|
if (has_escaped(d, node, parent)) {
|
||||||
|| parent instanceof AST_Call && (node !== parent.expression || parent instanceof AST_New)
|
|
||||||
|| parent instanceof AST_Exit && node === parent.value && node.scope !== d.scope
|
|
||||||
|| parent instanceof AST_VarDef && node === parent.value) {
|
|
||||||
d.escaped.push(parent);
|
d.escaped.push(parent);
|
||||||
if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
|
if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
|
||||||
if (!d.escaped.depth || d.escaped.depth > depth) d.escaped.depth = depth;
|
if (!d.escaped.depth || d.escaped.depth > depth) d.escaped.depth = depth;
|
||||||
return;
|
return;
|
||||||
} else if (parent instanceof AST_Array
|
} else if (value_in_use(node, parent)) {
|
||||||
|| parent instanceof AST_Binary && lazy_op[parent.operator]
|
|
||||||
|| parent instanceof AST_Conditional && node !== parent.condition
|
|
||||||
|| parent instanceof AST_Sequence && node === parent.tail_node()) {
|
|
||||||
mark_escaped(tw, d, scope, parent, parent, level + 1, depth);
|
mark_escaped(tw, d, scope, parent, parent, level + 1, depth);
|
||||||
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
|
} else if (parent instanceof AST_ObjectKeyVal && parent.value === node) {
|
||||||
var obj = tw.parent(level + 1);
|
var obj = tw.parent(level + 1);
|
||||||
mark_escaped(tw, d, scope, obj, obj, level + 2, depth);
|
mark_escaped(tw, d, scope, obj, obj, level + 2, depth);
|
||||||
} else if (parent instanceof AST_PropAccess && node === parent.expression) {
|
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||||
value = read_property(value, parent);
|
value = read_property(value, parent);
|
||||||
mark_escaped(tw, d, scope, parent, value, level + 1, depth + 1);
|
mark_escaped(tw, d, scope, parent, value, level + 1, depth + 1);
|
||||||
if (value) return;
|
if (value) return;
|
||||||
}
|
}
|
||||||
if (level > 0) return;
|
if (level > 0) return;
|
||||||
if (parent instanceof AST_Call && node === parent.expression) return;
|
if (parent instanceof AST_Call && parent.expression === node) return;
|
||||||
if (parent instanceof AST_Sequence && node !== parent.tail_node()) return;
|
if (parent instanceof AST_Sequence && parent.tail_node() !== node) return;
|
||||||
if (parent instanceof AST_SimpleStatement) return;
|
if (parent instanceof AST_SimpleStatement) return;
|
||||||
if (parent instanceof AST_Unary && !unary_side_effects[parent.operator]) return;
|
if (parent instanceof AST_Unary && !unary_side_effects[parent.operator]) return;
|
||||||
d.direct_access = true;
|
d.direct_access = true;
|
||||||
@@ -739,13 +747,11 @@ merge(Compressor.prototype, {
|
|||||||
push(tw);
|
push(tw);
|
||||||
var init = this.init;
|
var init = this.init;
|
||||||
init.walk(tw);
|
init.walk(tw);
|
||||||
if (init instanceof AST_Var) {
|
if (init instanceof AST_SymbolRef) {
|
||||||
init = init.definitions[0].name;
|
init.definition().fixed = false;
|
||||||
} else while (init instanceof AST_PropAccess) {
|
} else if (init instanceof AST_Var) {
|
||||||
init = init.expression.tail_node();
|
init.definitions[0].name.definition().fixed = false;
|
||||||
}
|
}
|
||||||
var def = init.definition();
|
|
||||||
if (def) def.fixed = false;
|
|
||||||
this.body.walk(tw);
|
this.body.walk(tw);
|
||||||
pop(tw);
|
pop(tw);
|
||||||
tw.in_loop = saved_loop;
|
tw.in_loop = saved_loop;
|
||||||
@@ -2638,6 +2644,14 @@ merge(Compressor.prototype, {
|
|||||||
defs = stat.init;
|
defs = stat.init;
|
||||||
}
|
}
|
||||||
} else if (stat instanceof AST_ForIn) {
|
} else if (stat instanceof AST_ForIn) {
|
||||||
|
if (defs && defs.TYPE == stat.init.TYPE) {
|
||||||
|
defs.definitions = defs.definitions.concat(stat.init.definitions);
|
||||||
|
var name = stat.init.definitions[0].name;
|
||||||
|
var ref = make_node(AST_SymbolRef, name, name);
|
||||||
|
name.definition().references.push(ref);
|
||||||
|
stat.init = ref;
|
||||||
|
CHANGED = true;
|
||||||
|
}
|
||||||
stat.object = join_assigns_expr(stat.object);
|
stat.object = join_assigns_expr(stat.object);
|
||||||
} else if (stat instanceof AST_If) {
|
} else if (stat instanceof AST_If) {
|
||||||
stat.condition = join_assigns_expr(stat.condition);
|
stat.condition = join_assigns_expr(stat.condition);
|
||||||
@@ -4298,6 +4312,7 @@ merge(Compressor.prototype, {
|
|||||||
return sym;
|
return sym;
|
||||||
};
|
};
|
||||||
var assign_in_use = Object.create(null);
|
var assign_in_use = Object.create(null);
|
||||||
|
var for_ins = Object.create(null);
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||||
var value_read = Object.create(null);
|
var value_read = Object.create(null);
|
||||||
@@ -4588,23 +4603,37 @@ merge(Compressor.prototype, {
|
|||||||
return !def || fn.name && def === fn.name.definition();
|
return !def || fn.name && def === fn.name.definition();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (head.length == 0 && tail.length == duplicated) {
|
switch (head.length) {
|
||||||
[].unshift.apply(side_effects, tail.map(function(def) {
|
case 0:
|
||||||
AST_Node.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
if (tail.length == 0) break;
|
||||||
var sym = def.name.definition();
|
if (tail.length == duplicated) {
|
||||||
var ref = make_node(AST_SymbolRef, def.name, def.name);
|
[].unshift.apply(side_effects, tail.map(function(def) {
|
||||||
sym.references.push(ref);
|
AST_Node.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
var assign = make_node(AST_Assign, def, {
|
var sym = def.name.definition();
|
||||||
operator: "=",
|
var ref = make_node(AST_SymbolRef, def.name, def.name);
|
||||||
left: ref,
|
sym.references.push(ref);
|
||||||
right: def.value
|
var assign = make_node(AST_Assign, def, {
|
||||||
});
|
operator: "=",
|
||||||
var index = indexOf_assign(sym, def);
|
left: ref,
|
||||||
if (index >= 0) assign_in_use[sym.id][index] = assign;
|
right: def.value
|
||||||
sym.eliminated++;
|
});
|
||||||
return assign;
|
var index = indexOf_assign(sym, def);
|
||||||
}));
|
if (index >= 0) assign_in_use[sym.id][index] = assign;
|
||||||
} else if (head.length > 0 || tail.length > 0) {
|
sym.eliminated++;
|
||||||
|
return assign;
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if (tail.length == 0) {
|
||||||
|
var id = head[0].name.definition().id;
|
||||||
|
if (id in for_ins) {
|
||||||
|
node.definitions = head;
|
||||||
|
for_ins[id].init = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
node.definitions = head.concat(tail);
|
node.definitions = head.concat(tail);
|
||||||
body.push(node);
|
body.push(node);
|
||||||
}
|
}
|
||||||
@@ -4613,16 +4642,7 @@ merge(Compressor.prototype, {
|
|||||||
body: make_sequence(node, side_effects)
|
body: make_sequence(node, side_effects)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
switch (body.length) {
|
return insert_statements(body, node, in_list);
|
||||||
case 0:
|
|
||||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
|
||||||
case 1:
|
|
||||||
return body[0];
|
|
||||||
default:
|
|
||||||
return in_list ? List.splice(body) : make_node(AST_BlockStatement, node, {
|
|
||||||
body: body
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
|
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
|
||||||
// Certain combination of unused name + side effect leads to invalid AST:
|
// Certain combination of unused name + side effect leads to invalid AST:
|
||||||
@@ -4682,15 +4702,22 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var def = sym.definition();
|
var def = sym.definition();
|
||||||
if (!def) return;
|
if (!def) return;
|
||||||
if (def.scope !== self) return;
|
|
||||||
if (def.id in in_use_ids) return;
|
if (def.id in in_use_ids) return;
|
||||||
|
if (def.scope !== self && member(def, self.enclosed)) return;
|
||||||
log(sym, "Dropping unused loop variable {name}");
|
log(sym, "Dropping unused loop variable {name}");
|
||||||
|
if (for_ins[def.id] === node) delete for_ins[def.id];
|
||||||
|
var body = [];
|
||||||
var value = node.object.drop_side_effect_free(compressor);
|
var value = node.object.drop_side_effect_free(compressor);
|
||||||
if (!value) return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
if (value) {
|
||||||
AST_Node.warn("Side effects in object of for-in loop [{file}:{line},{col}]", value.start);
|
AST_Node.warn("Side effects in object of for-in loop [{file}:{line},{col}]", value.start);
|
||||||
return make_node(AST_SimpleStatement, node, {
|
body.push(make_node(AST_SimpleStatement, node, {
|
||||||
body: value
|
body: value
|
||||||
});
|
}));
|
||||||
|
}
|
||||||
|
if (node.init instanceof AST_Definitions && def.orig[0] instanceof AST_SymbolCatch) {
|
||||||
|
body.push(node.init);
|
||||||
|
}
|
||||||
|
return insert_statements(body, node, in_list);
|
||||||
} else if (node instanceof AST_Sequence) {
|
} else if (node instanceof AST_Sequence) {
|
||||||
if (node.expressions.length == 1) return node.expressions[0];
|
if (node.expressions.length == 1) return node.expressions[0];
|
||||||
}
|
}
|
||||||
@@ -4723,6 +4750,19 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function insert_statements(body, orig, in_list) {
|
||||||
|
switch (body.length) {
|
||||||
|
case 0:
|
||||||
|
return in_list ? List.skip : make_node(AST_EmptyStatement, orig);
|
||||||
|
case 1:
|
||||||
|
return body[0];
|
||||||
|
default:
|
||||||
|
return in_list ? List.splice(body) : make_node(AST_BlockStatement, orig, {
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function track_assigns(def, node) {
|
function track_assigns(def, node) {
|
||||||
if (def.scope !== self) return false;
|
if (def.scope !== self) return false;
|
||||||
if (!def.fixed || !node.fixed) assign_in_use[def.id] = false;
|
if (!def.fixed || !node.fixed) assign_in_use[def.id] = false;
|
||||||
@@ -4800,6 +4840,10 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_ForIn) {
|
if (node instanceof AST_ForIn) {
|
||||||
|
if (node.init instanceof AST_SymbolRef && scope === self) {
|
||||||
|
var id = node.init.definition().id;
|
||||||
|
if (!(id in for_ins)) for_ins[id] = node;
|
||||||
|
}
|
||||||
if (!drop_vars || !compressor.option("loops")) return;
|
if (!drop_vars || !compressor.option("loops")) return;
|
||||||
if (!is_empty(node.body)) return;
|
if (!is_empty(node.body)) return;
|
||||||
if (node.init.has_side_effects(compressor)) return;
|
if (node.init.has_side_effects(compressor)) return;
|
||||||
@@ -7512,13 +7556,15 @@ merge(Compressor.prototype, {
|
|||||||
&& self.left.is_number(compressor)) {
|
&& self.left.is_number(compressor)) {
|
||||||
if (self.left.left instanceof AST_Constant) {
|
if (self.left.left instanceof AST_Constant) {
|
||||||
var lhs = make_binary(self.left, self.operator, self.left.left, self.right, self.left.left.start, self.right.end);
|
var lhs = make_binary(self.left, self.operator, self.left.left, self.right, self.left.left.start, self.right.end);
|
||||||
self = make_binary(self, self.left.operator, lhs, self.left.right);
|
self = make_binary(self, self.left.operator, try_evaluate(compressor, lhs), self.left.right);
|
||||||
} else if (self.left.right instanceof AST_Constant) {
|
} else if (self.left.right instanceof AST_Constant) {
|
||||||
var rhs = make_binary(self.left, align(self.left.operator, self.operator), self.left.right, self.right, self.left.right.start, self.right.end);
|
var op = align(self.left.operator, self.operator);
|
||||||
if (self.left.operator != "-"
|
var rhs = try_evaluate(compressor, make_binary(self.left, op, self.left.right, self.right));
|
||||||
|| !self.right.value
|
if (rhs.is_constant()
|
||||||
|| rhs.evaluate(compressor)
|
&& !(self.left.operator == "-"
|
||||||
|| !self.left.left.is_negative_zero()) {
|
&& self.right.value != 0
|
||||||
|
&& +rhs.value == 0
|
||||||
|
&& self.left.left.is_negative_zero())) {
|
||||||
self = make_binary(self, self.left.operator, self.left.left, rhs);
|
self = make_binary(self, self.left.operator, self.left.left, rhs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.10.3",
|
"version": "3.10.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2848,3 +2848,60 @@ issue_4025: {
|
|||||||
"1 1 1",
|
"1 1 1",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forin_var_1: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var k;
|
||||||
|
for (k in [ 1, 2 ])
|
||||||
|
console.log(k);
|
||||||
|
for (k in { PASS: 3 })
|
||||||
|
console.log(k);
|
||||||
|
console.log(k);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var k in [ 1, 2 ])
|
||||||
|
console.log(k);
|
||||||
|
for (k in { PASS: 3 })
|
||||||
|
console.log(k);
|
||||||
|
console.log(k);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"0",
|
||||||
|
"1",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
forin_var_2: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
switch (0) {
|
||||||
|
case function() {
|
||||||
|
for (a in 0);
|
||||||
|
}:
|
||||||
|
var b = 0;
|
||||||
|
}
|
||||||
|
for (var c = 0; a;);
|
||||||
|
var a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
switch (0) {
|
||||||
|
case function() {
|
||||||
|
for (a in 0);
|
||||||
|
}:
|
||||||
|
}
|
||||||
|
for (; a;);
|
||||||
|
var a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1483,8 +1483,7 @@ issue_2663_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function() {
|
(function() {
|
||||||
var i;
|
for (var i in { a: 1, b: 2, c: 3 })
|
||||||
for (i in { a: 1, b: 2, c: 3 })
|
|
||||||
j = i, console.log(j);
|
j = i, console.log(j);
|
||||||
var j;
|
var j;
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -277,8 +277,8 @@ join_object_assignments_forin: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function() {
|
console.log(function() {
|
||||||
var o = { a: "PASS" };
|
var o = { a: "PASS" }, a;
|
||||||
for (var a in o)
|
for (a in o)
|
||||||
return o[a];
|
return o[a];
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1009,3 +1009,82 @@ issue_4082: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4084: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: "strict",
|
||||||
|
loops: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
function f(a) {
|
||||||
|
var b = a++;
|
||||||
|
for (a in "foo");
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
(function() {
|
||||||
|
0;
|
||||||
|
})();
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4091_1: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
for (var e in 42);
|
||||||
|
}
|
||||||
|
console.log(e && e);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
var e;
|
||||||
|
}
|
||||||
|
console.log(e && e);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4091_2: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
for (e in 42);
|
||||||
|
var e;
|
||||||
|
}
|
||||||
|
console.log(e && e);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
var e;
|
||||||
|
}
|
||||||
|
console.log(e && e);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -637,6 +637,22 @@ evaluate_7_unsafe_math: {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evaluate_8_unsafe_math: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe_math: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ "42" ];
|
||||||
|
console.log(a * (1 / 7));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = [ "42" ];
|
||||||
|
console.log(+a / 7);
|
||||||
|
}
|
||||||
|
expect_stdout: "6"
|
||||||
|
}
|
||||||
|
|
||||||
NaN_redefined: {
|
NaN_redefined: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
var o = this;
|
UNUSED: {
|
||||||
|
console.log(0 - .1 - .1 - .1);
|
||||||
for (var k in o) L17060: {
|
|
||||||
a++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var a;
|
|
||||||
|
|
||||||
console.log(k);
|
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
// (beautified)
|
// (beautified)
|
||||||
var o = this;
|
console.log(0 - 1 - .1 - .1);
|
||||||
|
// output: -1.2000000000000002
|
||||||
for (var k in o) {}
|
|
||||||
|
|
||||||
var a;
|
|
||||||
|
|
||||||
console.log(k);
|
|
||||||
// output: a
|
|
||||||
//
|
//
|
||||||
// minify: k
|
// minify: -1.2
|
||||||
//
|
//
|
||||||
// options: {
|
// options: {
|
||||||
|
// "compress": {
|
||||||
|
// "unsafe_math": true
|
||||||
|
// },
|
||||||
// "mangle": false
|
// "mangle": false
|
||||||
// }
|
// }
|
||||||
@@ -24,6 +24,9 @@ describe("test/reduce.js", function() {
|
|||||||
});
|
});
|
||||||
it("Should eliminate unreferenced labels", function() {
|
it("Should eliminate unreferenced labels", function() {
|
||||||
var result = reduce_test(read("test/input/reduce/label.js"), {
|
var result = reduce_test(read("test/input/reduce/label.js"), {
|
||||||
|
compress: {
|
||||||
|
unsafe_math: true,
|
||||||
|
},
|
||||||
mangle: false,
|
mangle: false,
|
||||||
}, {
|
}, {
|
||||||
verbose: false,
|
verbose: false,
|
||||||
|
|||||||
@@ -112,19 +112,18 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
// no structural AST changes before this point.
|
// no structural AST changes before this point.
|
||||||
if (node.start._permute >= REPLACEMENTS.length) return;
|
if (node.start._permute >= REPLACEMENTS.length) return;
|
||||||
|
|
||||||
if (parent instanceof U.AST_Assign
|
// ignore lvalues
|
||||||
&& parent.left === node
|
if (parent instanceof U.AST_Assign && parent.left === node) return;
|
||||||
|| parent instanceof U.AST_Unary
|
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
|
||||||
&& parent.expression === node
|
case "++":
|
||||||
&& ["++", "--", "delete"].indexOf(parent.operator) >= 0) {
|
case "--":
|
||||||
// ignore lvalues
|
case "delete":
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((parent instanceof U.AST_For || parent instanceof U.AST_ForIn)
|
// preserve for (var xxx; ...)
|
||||||
&& parent.init === node && node instanceof U.AST_Var) {
|
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Var) return node;
|
||||||
// preserve for (var ...)
|
// preserve for (xxx in ...)
|
||||||
return node;
|
if (parent instanceof U.AST_ForIn && parent.init === node) return node;
|
||||||
}
|
|
||||||
|
|
||||||
// node specific permutations with no parent logic
|
// node specific permutations with no parent logic
|
||||||
|
|
||||||
@@ -452,6 +451,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
node.start = JSON.parse(JSON.stringify(node.start));
|
node.start = JSON.parse(JSON.stringify(node.start));
|
||||||
node.start._permute = 0;
|
node.start._permute = 0;
|
||||||
}));
|
}));
|
||||||
|
var before_iterations = testcase;
|
||||||
for (var c = 0; c < max_iterations; ++c) {
|
for (var c = 0; c < max_iterations; ++c) {
|
||||||
if (verbose && pass == 1 && c % 25 == 0) {
|
if (verbose && pass == 1 && c % 25 == 0) {
|
||||||
log("// reduce test pass " + pass + ", iteration " + c + ": " + testcase.length + " bytes");
|
log("// reduce test pass " + pass + ", iteration " + c + ": " + testcase.length + " bytes");
|
||||||
@@ -494,7 +494,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c == 0) break;
|
if (before_iterations === testcase) break;
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
log("// reduce test pass " + pass + ": " + testcase.length + " bytes");
|
log("// reduce test pass " + pass + ": " + testcase.length + " bytes");
|
||||||
}
|
}
|
||||||
@@ -557,7 +557,7 @@ function try_beautify(testcase, minify_options, expected, result_cache, timeout)
|
|||||||
code: testcase,
|
code: testcase,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
var actual = run_code(result.code, toplevel, result_cache, timeout);
|
var actual = run_code(result.code, toplevel, result_cache, timeout).result;
|
||||||
if (!sandbox.same_stdout(expected, actual)) return {
|
if (!sandbox.same_stdout(expected, actual)) return {
|
||||||
code: testcase,
|
code: testcase,
|
||||||
};
|
};
|
||||||
@@ -650,7 +650,15 @@ function wrap_with_console_log(node) {
|
|||||||
|
|
||||||
function run_code(code, toplevel, result_cache, timeout) {
|
function run_code(code, toplevel, result_cache, timeout) {
|
||||||
var key = crypto.createHash("sha1").update(code).digest("base64");
|
var key = crypto.createHash("sha1").update(code).digest("base64");
|
||||||
return result_cache[key] || (result_cache[key] = sandbox.run_code(code, toplevel, timeout));
|
var value = result_cache[key];
|
||||||
|
if (!value) {
|
||||||
|
var start = Date.now();
|
||||||
|
result_cache[key] = value = {
|
||||||
|
result: sandbox.run_code(code, toplevel, timeout),
|
||||||
|
elapsed: Date.now() - start,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function compare_run_code(code, minify_options, result_cache, max_timeout) {
|
function compare_run_code(code, minify_options, result_cache, max_timeout) {
|
||||||
@@ -658,21 +666,19 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) {
|
|||||||
if (minified.error) return minified;
|
if (minified.error) return minified;
|
||||||
|
|
||||||
var toplevel = sandbox.has_toplevel(minify_options);
|
var toplevel = sandbox.has_toplevel(minify_options);
|
||||||
var elapsed = Date.now();
|
var unminified = run_code(code, toplevel, result_cache, max_timeout);
|
||||||
var unminified_result = run_code(code, toplevel, result_cache, max_timeout);
|
var timeout = Math.min(100 * unminified.elapsed, max_timeout);
|
||||||
elapsed = Date.now() - elapsed;
|
var minified_result = run_code(minified.code, toplevel, result_cache, timeout).result;
|
||||||
var timeout = Math.min(100 * elapsed, max_timeout);
|
|
||||||
var minified_result = run_code(minified.code, toplevel, result_cache, timeout);
|
|
||||||
|
|
||||||
if (sandbox.same_stdout(unminified_result, minified_result)) {
|
if (sandbox.same_stdout(unminified.result, minified_result)) {
|
||||||
return is_timed_out(unminified_result) && is_timed_out(minified_result) && {
|
return is_timed_out(unminified.result) && is_timed_out(minified_result) && {
|
||||||
timed_out: true,
|
timed_out: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
unminified_result: unminified_result,
|
unminified_result: unminified.result,
|
||||||
minified_result: minified_result,
|
minified_result: minified_result,
|
||||||
elapsed: elapsed,
|
elapsed: unminified.elapsed,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ process.on("beforeExit", function() {
|
|||||||
if (queued > 3) {
|
if (queued > 3) {
|
||||||
process.stdout.write("0");
|
process.stdout.write("0");
|
||||||
} else if (now - earliest > 0 && total > 1) {
|
} else if (now - earliest > 0 && total > 1) {
|
||||||
process.stdout.write(Math.min(20 * (now - earliest) / (total - 1), 6300000).toFixed(0));
|
process.stdout.write(Math.min(20 * (now - earliest) / (total - 1), 18000000).toFixed(0));
|
||||||
} else {
|
} else {
|
||||||
process.stdout.write("3600000");
|
process.stdout.write("3600000");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user