Compare commits

...

19 Commits

Author SHA1 Message Date
Alex Lam S.L
7ccdf3337b v3.5.7 2019-04-24 14:05:07 +08:00
Alex Lam S.L
dafed54764 fix corner case in reduce_vars (#3378)
fixes #3377
2019-04-24 14:01:01 +08:00
Alex Lam S.L
a84beafd1b fix corner case in assignments (#3376)
fixes #3375
2019-04-24 02:50:15 +08:00
Alex Lam S.L
f01cc1e413 unwind IIFE class patterns (#3373)
fixes #2332
2019-04-21 09:49:07 +08:00
Alex Lam S.L
338dd144b8 v3.5.6 2019-04-21 07:19:29 +08:00
Alex Lam S.L
c719552317 fix corner cases in functions (#3372)
fixes #3371
2019-04-21 02:16:05 +08:00
Alex Lam S.L
855964a87a enhance unsafe evaluate (#3370) 2019-04-20 19:42:41 +08:00
Alex Lam S.L
a438e2fca9 update domprops (#3369)
fixes #2343
fixes #3037
2019-04-20 07:16:14 +08:00
Alex Lam S.L
00833e893a enhance functions (#3368) 2019-04-19 19:01:47 +08:00
Alex Lam S.L
f1a77e4fc0 v3.5.5 2019-04-19 15:22:46 +08:00
Alex Lam S.L
b55a2fd531 fix corner case in functions (#3367)
fixes #3366
2019-04-19 02:55:43 +08:00
Alex Lam S.L
e8a2c0b5bf fix corner case in functions (#3365)
fixes #3364
2019-04-18 17:03:52 +08:00
Alex Lam S.L
21cd7e3f57 reduce test exports (#3361) 2019-04-17 16:19:08 +08:00
Alex Lam S.L
5172ba5f2a introduce functions (#3360)
`var f = function() {};` => `function f() {}`
2019-04-15 22:23:11 +08:00
Alex Lam S.L
a57b069409 v3.5.4 2019-04-10 02:40:42 +08:00
Alex Lam S.L
4454656c3b update dependencies (#3358)
- commander@2.20.0
- semver@6.0.0
2019-04-10 02:39:56 +08:00
Alex Lam S.L
fa43768ce0 v3.5.3 2019-04-01 18:12:03 +08:00
Alex Lam S.L
a74e600fa0 mangle shadowed lambda under ie8 correctly (#3356)
fixes #3355
2019-04-01 15:22:00 +08:00
Ruben Bridgewater
4b21526310 Fix test expectation (#3357)
The test expects a specific precision value that is not met on all V8 versions anymore due to a recent consolidation of different algorithms across the V8 code base.

This makes sure the preceision is tested against one digit less to keep the test working on all V8 versions.

Refs: 98453126c1
Refs: https://github.com/nodejs/node/issues/25060#issuecomment-477953457
2019-03-30 02:08:27 +08:00
20 changed files with 2574 additions and 180 deletions

View File

@@ -636,6 +636,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `expression` (default: `false`) -- Pass `true` to preserve completion values - `expression` (default: `false`) -- Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets. from terminal statements without `return`, e.g. in bookmarklets.
- `functions` (default: `true`) -- convert declarations from `var`to `function`
whenever possible.
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation) - `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
- `hoist_funs` (default: `false`) -- hoist function declarations - `hoist_funs` (default: `false`) -- hoist function declarations

View File

@@ -773,7 +773,7 @@ var AST_Label = DEFNODE("Label", "references", {
} }
}, AST_Symbol); }, AST_Symbol);
var AST_SymbolRef = DEFNODE("SymbolRef", null, { var AST_SymbolRef = DEFNODE("SymbolRef", "fixed", {
$documentation: "Reference to some symbol (not definition/declaration)", $documentation: "Reference to some symbol (not definition/declaration)",
}, AST_Symbol); }, AST_Symbol);

View File

@@ -60,6 +60,7 @@ function Compressor(options, false_by_default) {
drop_debugger : !false_by_default, drop_debugger : !false_by_default,
evaluate : !false_by_default, evaluate : !false_by_default,
expression : false, expression : false,
functions : !false_by_default,
global_defs : false, global_defs : false,
hoist_funs : false, hoist_funs : false,
hoist_props : !false_by_default, hoist_props : !false_by_default,
@@ -113,7 +114,7 @@ function Compressor(options, false_by_default) {
}; };
} else if (Array.isArray(pure_funcs)) { } else if (Array.isArray(pure_funcs)) {
this.pure_funcs = function(node) { this.pure_funcs = function(node) {
return pure_funcs.indexOf(node.expression.print_to_string()) < 0; return !member(node.expression.print_to_string(), pure_funcs);
}; };
} else { } else {
this.pure_funcs = return_true; this.pure_funcs = return_true;
@@ -130,7 +131,7 @@ function Compressor(options, false_by_default) {
top_retain = top_retain.split(/,/); top_retain = top_retain.split(/,/);
} }
this.top_retain = function(def) { this.top_retain = function(def) {
return top_retain.indexOf(def.name) >= 0; return member(def.name, top_retain);
}; };
} }
var toplevel = this.options["toplevel"]; var toplevel = this.options["toplevel"];
@@ -150,7 +151,7 @@ Compressor.prototype = new TreeTransformer;
merge(Compressor.prototype, { merge(Compressor.prototype, {
option: function(key) { return this.options[key] }, option: function(key) { return this.options[key] },
exposed: function(def) { exposed: function(def) {
if (def.global) for (var i = 0, len = def.orig.length; i < len; i++) if (def.global) for (var i = 0; i < def.orig.length; i++)
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"]) if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
return true; return true;
return false; return false;
@@ -311,8 +312,22 @@ merge(Compressor.prototype, {
return value instanceof AST_SymbolRef && value.fixed_value() || value; return value instanceof AST_SymbolRef && value.fixed_value() || value;
} }
function is_read_only_fn(value, name) {
if (value instanceof AST_Boolean) return native_fns.Boolean[name];
if (value instanceof AST_Number) return native_fns.Number[name];
if (value instanceof AST_String) return native_fns.String[name];
if (name == "valueOf") return false;
if (value instanceof AST_Array) return native_fns.Array[name];
if (value instanceof AST_Function) return native_fns.Function[name];
if (value instanceof AST_Object) return native_fns.Object[name];
if (value instanceof AST_RegExp) return native_fns.RegExp[name];
}
function is_modified(compressor, tw, node, value, level, immutable) { function is_modified(compressor, tw, node, value, level, immutable) {
var parent = tw.parent(level); var parent = tw.parent(level);
if (compressor.option("unsafe") && parent instanceof AST_Dot && is_read_only_fn(value, parent.property)) {
return;
}
var lhs = is_lhs(node, parent); var lhs = is_lhs(node, parent);
if (lhs) return lhs; if (lhs) return lhs;
if (!immutable if (!immutable
@@ -343,7 +358,7 @@ merge(Compressor.prototype, {
def.assignments = 0; def.assignments = 0;
def.chained = false; def.chained = false;
def.direct_access = false; def.direct_access = false;
def.escaped = false; def.escaped = [];
def.fixed = !def.scope.pinned() def.fixed = !def.scope.pinned()
&& !compressor.exposed(def) && !compressor.exposed(def)
&& !(def.init instanceof AST_Function && def.init !== def.scope) && !(def.init instanceof AST_Function && def.init !== def.scope)
@@ -482,8 +497,9 @@ merge(Compressor.prototype, {
|| parent instanceof AST_Call && (node !== parent.expression || parent instanceof AST_New) || 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_Exit && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value) { || parent instanceof AST_VarDef && node === parent.value) {
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 || d.escaped > depth) d.escaped = depth; if (!d.escaped.depth || d.escaped.depth > depth) d.escaped.depth = depth;
return; return;
} else if (parent instanceof AST_Array } else if (parent instanceof AST_Array
|| parent instanceof AST_Binary && lazy_op[parent.operator] || parent instanceof AST_Binary && lazy_op[parent.operator]
@@ -535,6 +551,7 @@ merge(Compressor.prototype, {
mark_assignment_to_arguments(sym); mark_assignment_to_arguments(sym);
return; return;
} }
if (sym.fixed) delete sym.fixed;
var d = sym.definition(); var d = sym.definition();
var safe = safe_to_assign(tw, d, sym.scope, node.right); var safe = safe_to_assign(tw, d, sym.scope, node.right);
d.assignments++; d.assignments++;
@@ -544,7 +561,7 @@ merge(Compressor.prototype, {
var value = eq ? node.right : node; var value = eq ? node.right : node;
if (is_modified(compressor, tw, node, value, 0)) return; if (is_modified(compressor, tw, node, value, 0)) return;
if (!eq) d.chained = true; if (!eq) d.chained = true;
d.fixed = eq ? function() { sym.fixed = d.fixed = eq ? function() {
return node.right; return node.right;
} : function() { } : function() {
return make_node(AST_Binary, node, { return make_node(AST_Binary, node, {
@@ -558,7 +575,7 @@ merge(Compressor.prototype, {
mark(tw, d, false); mark(tw, d, false);
node.right.walk(tw); node.right.walk(tw);
mark(tw, d, true); mark(tw, d, true);
mark_escaped(tw, d, sym.scope, node, value, 0, 1); if (eq) mark_escaped(tw, d, sym.scope, node, value, 0, 1);
return true; return true;
}); });
def(AST_Binary, function(tw) { def(AST_Binary, function(tw) {
@@ -714,6 +731,7 @@ merge(Compressor.prototype, {
this.definition().fixed = false; this.definition().fixed = false;
}); });
def(AST_SymbolRef, function(tw, descend, compressor) { def(AST_SymbolRef, function(tw, descend, compressor) {
if (this.fixed) delete this.fixed;
var d = this.definition(); var d = this.definition();
d.references.push(this); d.references.push(this);
if (d.references.length == 1 if (d.references.length == 1
@@ -726,7 +744,7 @@ merge(Compressor.prototype, {
d.fixed = false; d.fixed = false;
} else if (d.fixed) { } else if (d.fixed) {
value = this.fixed_value(); value = this.fixed_value();
if (value instanceof AST_Lambda && recursive_ref(tw, d)) { if (recursive_ref(tw, d)) {
d.recursive_refs++; d.recursive_refs++;
} else if (value && ref_once(tw, compressor, d)) { } else if (value && ref_once(tw, compressor, d)) {
d.single_use = value instanceof AST_Lambda && !value.pinned() d.single_use = value instanceof AST_Lambda && !value.pinned()
@@ -741,8 +759,8 @@ merge(Compressor.prototype, {
d.fixed = false; d.fixed = false;
} }
} }
mark_escaped(tw, d, this.scope, this, value, 0, 1);
} }
mark_escaped(tw, d, this.scope, this, value, 0, 1);
var parent; var parent;
if (d.fixed instanceof AST_Defun if (d.fixed instanceof AST_Defun
&& !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) { && !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
@@ -781,13 +799,14 @@ merge(Compressor.prototype, {
mark_assignment_to_arguments(exp); mark_assignment_to_arguments(exp);
return; return;
} }
if (exp.fixed) delete exp.fixed;
var d = exp.definition(); var d = exp.definition();
var safe = safe_to_assign(tw, d, exp.scope, true); var safe = safe_to_assign(tw, d, exp.scope, true);
d.assignments++; d.assignments++;
var fixed = d.fixed; var fixed = d.fixed;
if (!fixed) return; if (!fixed) return;
d.chained = true; d.chained = true;
d.fixed = function() { exp.fixed = d.fixed = function() {
return make_node(AST_Binary, node, { return make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1), operator: node.operator.slice(0, -1),
left: make_node(AST_UnaryPrefix, node, { left: make_node(AST_UnaryPrefix, node, {
@@ -858,10 +877,11 @@ merge(Compressor.prototype, {
this.walk(tw); this.walk(tw);
}); });
AST_Symbol.DEFMETHOD("fixed_value", function() { AST_Symbol.DEFMETHOD("fixed_value", function(final) {
var fixed = this.definition().fixed; var fixed = this.definition().fixed;
if (!fixed || fixed instanceof AST_Node) return fixed; if (!fixed) return fixed;
return fixed(); if (!final && this.fixed) fixed = this.fixed;
return fixed instanceof AST_Node ? fixed : fixed();
}); });
AST_SymbolRef.DEFMETHOD("is_immutable", function() { AST_SymbolRef.DEFMETHOD("is_immutable", function() {
@@ -1241,7 +1261,7 @@ merge(Compressor.prototype, {
// Scan case expressions first in a switch statement // Scan case expressions first in a switch statement
if (node instanceof AST_Switch) { if (node instanceof AST_Switch) {
node.expression = node.expression.transform(scanner); node.expression = node.expression.transform(scanner);
for (var i = 0, len = node.body.length; !abort && i < len; i++) { for (var i = 0; !abort && i < node.body.length; i++) {
var branch = node.body[i]; var branch = node.body[i];
if (branch instanceof AST_Case) { if (branch instanceof AST_Case) {
if (!hit) { if (!hit) {
@@ -1271,7 +1291,9 @@ merge(Compressor.prototype, {
if (node instanceof AST_Try) return true; if (node instanceof AST_Try) return true;
if (node instanceof AST_With) return true; if (node instanceof AST_With) return true;
if (replace_all) return false; if (replace_all) return false;
return node instanceof AST_SymbolRef && !node.is_declared(compressor); return node instanceof AST_SymbolRef
&& !node.is_declared(compressor)
&& !(parent instanceof AST_Assign && parent.left === node);
} }
function in_conditional(node, parent) { function in_conditional(node, parent) {
@@ -1578,9 +1600,14 @@ merge(Compressor.prototype, {
lvalues[candidate.name.name] = lhs; lvalues[candidate.name.name] = lhs;
} }
var tw = new TreeWalker(function(node) { var tw = new TreeWalker(function(node) {
var sym = root_expr(node); var value;
if (sym instanceof AST_SymbolRef || sym instanceof AST_This) { if (node instanceof AST_SymbolRef) {
lvalues[sym.name] = lvalues[sym.name] || is_modified(compressor, tw, node, node, 0); value = node.fixed_value() || node;
} else if (node instanceof AST_This) {
value = node;
}
if (value && !lvalues[node.name]) {
lvalues[node.name] = is_modified(compressor, tw, node, value, 0);
} }
}); });
expr.walk(tw); expr.walk(tw);
@@ -1690,7 +1717,7 @@ merge(Compressor.prototype, {
CHANGED = true; CHANGED = true;
statements.splice(i, 1); statements.splice(i, 1);
} else if (stat instanceof AST_Directive) { } else if (stat instanceof AST_Directive) {
if (seen_dirs.indexOf(stat.value) < 0) { if (!member(stat.value, seen_dirs)) {
i++; i++;
seen_dirs.push(stat.value); seen_dirs.push(stat.value);
} else { } else {
@@ -1887,7 +1914,7 @@ merge(Compressor.prototype, {
} }
function next_index(i) { function next_index(i) {
for (var j = i + 1, len = statements.length; j < len; j++) { for (var j = i + 1; j < statements.length; j++) {
var stat = statements[j]; var stat = statements[j];
if (!(stat instanceof AST_Var && declarations_only(stat))) { if (!(stat instanceof AST_Var && declarations_only(stat))) {
break; break;
@@ -1978,7 +2005,7 @@ merge(Compressor.prototype, {
function to_simple_statement(block, decls) { function to_simple_statement(block, decls) {
if (!(block instanceof AST_BlockStatement)) return block; if (!(block instanceof AST_BlockStatement)) return block;
var stat = null; var stat = null;
for (var i = 0, len = block.body.length; i < len; i++) { for (var i = 0; i < block.body.length; i++) {
var line = block.body[i]; var line = block.body[i];
if (line instanceof AST_Var && declarations_only(line)) { if (line instanceof AST_Var && declarations_only(line)) {
decls.push(line); decls.push(line);
@@ -2118,7 +2145,7 @@ merge(Compressor.prototype, {
function join_consecutive_vars(statements) { function join_consecutive_vars(statements) {
var defs; var defs;
for (var i = 0, j = -1, len = statements.length; i < len; i++) { for (var i = 0, j = -1; i < statements.length; i++) {
var stat = statements[i]; var stat = statements[i];
var prev = statements[j]; var prev = statements[j];
if (stat instanceof AST_Definitions) { if (stat instanceof AST_Definitions) {
@@ -2576,9 +2603,9 @@ merge(Compressor.prototype, {
} }
function convert_to_predicate(obj) { function convert_to_predicate(obj) {
for (var key in obj) { Object.keys(obj).forEach(function(key) {
obj[key] = makePredicate(obj[key]); obj[key] = makePredicate(obj[key]);
} });
} }
var object_fns = [ var object_fns = [
@@ -2719,7 +2746,7 @@ merge(Compressor.prototype, {
def(AST_Array, function(compressor, cached, depth) { def(AST_Array, function(compressor, cached, depth) {
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
var elements = []; var elements = [];
for (var i = 0, len = this.elements.length; i < len; i++) { for (var i = 0; i < this.elements.length; i++) {
var element = this.elements[i]; var element = this.elements[i];
var value = element._eval(compressor, cached, depth); var value = element._eval(compressor, cached, depth);
if (element === value) return this; if (element === value) return this;
@@ -2732,7 +2759,7 @@ merge(Compressor.prototype, {
def(AST_Object, function(compressor, cached, depth) { def(AST_Object, function(compressor, cached, depth) {
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
var val = {}; var val = {};
for (var i = 0, len = this.properties.length; i < len; i++) { for (var i = 0; i < this.properties.length; i++) {
var prop = this.properties[i]; var prop = this.properties[i];
var key = prop.key; var key = prop.key;
if (key instanceof AST_Symbol) { if (key instanceof AST_Symbol) {
@@ -2832,7 +2859,7 @@ merge(Compressor.prototype, {
var fixed = this.fixed_value(); var fixed = this.fixed_value();
if (!fixed) return this; if (!fixed) return this;
var value; var value;
if (cached.indexOf(fixed) >= 0) { if (member(fixed, cached)) {
value = fixed._eval(); value = fixed._eval();
} else { } else {
this._eval = return_this; this._eval = return_this;
@@ -2846,9 +2873,25 @@ merge(Compressor.prototype, {
} }
if (value && typeof value == "object") { if (value && typeof value == "object") {
var escaped = this.definition().escaped; var escaped = this.definition().escaped;
if (escaped && depth > escaped) return this; switch (escaped.length) {
case 0:
break;
case 1:
if (contains_ref(escaped[0], this)) break;
default:
if (depth > escaped.depth) return this;
}
} }
return value; return value;
function contains_ref(expr, ref) {
var found = false;
expr.walk(new TreeWalker(function(node) {
if (found) return true;
if (node === ref) return found = true;
}));
return found;
}
}); });
var global_objs = { var global_objs = {
Array: Array, Array: Array,
@@ -2927,7 +2970,7 @@ merge(Compressor.prototype, {
if (!native_fn || !native_fn[key]) return this; if (!native_fn || !native_fn[key]) return this;
} }
var args = []; var args = [];
for (var i = 0, len = this.args.length; i < len; i++) { for (var i = 0; i < this.args.length; i++) {
var arg = this.args[i]; var arg = this.args[i];
var value = arg._eval(compressor, cached, depth); var value = arg._eval(compressor, cached, depth);
if (arg === value) return this; if (arg === value) return this;
@@ -3463,9 +3506,7 @@ merge(Compressor.prototype, {
if (node instanceof AST_Definitions && scope === self) { if (node instanceof AST_Definitions && scope === self) {
node.definitions.forEach(function(def) { node.definitions.forEach(function(def) {
var node_def = def.name.definition(); var node_def = def.name.definition();
if (def.name instanceof AST_SymbolVar) { var_defs_by_id.add(node_def.id, def);
var_defs_by_id.add(node_def.id, def);
}
if (!drop_vars) { if (!drop_vars) {
if (!(node_def.id in in_use_ids)) { if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true; in_use_ids[node_def.id] = true;
@@ -3477,7 +3518,7 @@ merge(Compressor.prototype, {
if (def.value.has_side_effects(compressor)) { if (def.value.has_side_effects(compressor)) {
def.value.walk(tw); def.value.walk(tw);
} }
if (!node_def.chained && def.name.fixed_value() === def.value) { if (!node_def.chained && def.name.fixed_value(true) === def.value) {
fixed_ids[node_def.id] = def; fixed_ids[node_def.id] = def;
} }
} }
@@ -3572,29 +3613,49 @@ merge(Compressor.prototype, {
if (def.value && sym.id in fixed_ids && fixed_ids[sym.id] !== def) { if (def.value && sym.id in fixed_ids && fixed_ids[sym.id] !== def) {
def.value = def.value.drop_side_effect_free(compressor); def.value = def.value.drop_side_effect_free(compressor);
} }
if (def.name instanceof AST_SymbolVar) { var var_defs = var_defs_by_id.get(sym.id);
var var_defs = var_defs_by_id.get(sym.id); if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) { compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name)); if (def.value) {
if (def.value) { var ref = make_node(AST_SymbolRef, def.name, def.name);
var ref = make_node(AST_SymbolRef, def.name, def.name); sym.references.push(ref);
sym.references.push(ref); var assign = make_node(AST_Assign, def, {
var assign = make_node(AST_Assign, def, { operator: "=",
operator: "=", left: ref,
left: ref, right: def.value
right: def.value });
}); if (fixed_ids[sym.id] === def) {
if (fixed_ids[sym.id] === def) { fixed_ids[sym.id] = assign;
fixed_ids[sym.id] = assign;
}
side_effects.push(assign.transform(tt));
} }
remove(var_defs, def); side_effects.push(assign.transform(tt));
sym.eliminated++;
return;
} }
remove(var_defs, def);
sym.eliminated++;
return;
} }
if (def.value) { if (!def.value) {
head.push(def);
} else if (compressor.option("functions")
&& def.value === def.name.fixed_value()
&& def.value instanceof AST_Function
&& can_rename(def.value, def.name.name)
&& (!compressor.has_directive("use strict") || parent instanceof AST_Scope)) {
compressor.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
var defun = make_node(AST_Defun, def, def.value);
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
var name_def = def.name.scope.resolve().def_function(defun.name);
if (def.value.name) {
var old_def = def.value.name.definition();
def.value.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolRef && node.definition() === old_def) {
node.name = name_def.name;
node.thedef = name_def;
node.reference({});
}
}));
}
body.push(defun);
} else {
if (side_effects.length > 0) { if (side_effects.length > 0) {
if (tail.length > 0) { if (tail.length > 0) {
side_effects.push(def.value); side_effects.push(def.value);
@@ -3607,8 +3668,6 @@ merge(Compressor.prototype, {
side_effects = []; side_effects = [];
} }
tail.push(def); tail.push(def);
} else {
head.push(def);
} }
} else if (sym.orig[0] instanceof AST_SymbolCatch) { } else if (sym.orig[0] instanceof AST_SymbolCatch) {
var value = def.value && def.value.drop_side_effect_free(compressor); var value = def.value && def.value.drop_side_effect_free(compressor);
@@ -3625,6 +3684,11 @@ merge(Compressor.prototype, {
} }
sym.eliminated++; sym.eliminated++;
} }
function can_rename(fn, name) {
var def = fn.variables.get(name);
return !def || fn.name && def === fn.name.definition();
}
}); });
if (head.length > 0 || tail.length > 0) { if (head.length > 0 || tail.length > 0) {
node.definitions = head.concat(tail); node.definitions = head.concat(tail);
@@ -3650,6 +3714,7 @@ merge(Compressor.prototype, {
// https://github.com/mishoo/UglifyJS2/issues/44 // https://github.com/mishoo/UglifyJS2/issues/44
// https://github.com/mishoo/UglifyJS2/issues/1830 // https://github.com/mishoo/UglifyJS2/issues/1830
// https://github.com/mishoo/UglifyJS2/issues/1838 // https://github.com/mishoo/UglifyJS2/issues/1838
// https://github.com/mishoo/UglifyJS2/issues/3371
// that's an invalid AST. // that's an invalid AST.
// We fix it at this stage by moving the `var` outside the `for`. // We fix it at this stage by moving the `var` outside the `for`.
if (node instanceof AST_For) { if (node instanceof AST_For) {
@@ -3660,7 +3725,15 @@ merge(Compressor.prototype, {
node.init = block.body.pop(); node.init = block.body.pop();
block.body.push(node); block.body.push(node);
} }
if (node.init instanceof AST_SimpleStatement) { if (node.init instanceof AST_Defun) {
if (!block) {
block = make_node(AST_BlockStatement, node, {
body: [ node ]
});
}
block.body.splice(-1, 0, node.init);
node.init = null;
} else if (node.init instanceof AST_SimpleStatement) {
node.init = node.init.body; node.init = node.init.body;
} else if (is_empty(node.init)) { } else if (is_empty(node.init)) {
node.init = null; node.init = null;
@@ -3716,7 +3789,7 @@ merge(Compressor.prototype, {
if (node instanceof AST_Assign) { if (node instanceof AST_Assign) {
node.right.walk(tw); node.right.walk(tw);
if (node.left === sym) { if (node.left === sym) {
if (!node_def.chained && sym.fixed_value() === node.right) { if (!node_def.chained && sym.fixed_value(true) === node.right) {
fixed_ids[node_def.id] = node; fixed_ids[node_def.id] = node;
} }
if (!node.write_only) { if (!node.write_only) {
@@ -3966,7 +4039,7 @@ merge(Compressor.prototype, {
var def = sym.definition(); var def = sym.definition();
if (def.assignments != count) return; if (def.assignments != count) return;
if (def.direct_access) return; if (def.direct_access) return;
if (def.escaped == 1) return; if (def.escaped.depth == 1) return;
if (def.references.length == count) return; if (def.references.length == count) return;
if (def.single_use) return; if (def.single_use) return;
if (top_retain(def)) return; if (top_retain(def)) return;
@@ -4669,7 +4742,7 @@ merge(Compressor.prototype, {
&& !fn.uses_arguments && !fn.uses_arguments
&& !fn.pinned()) { && !fn.pinned()) {
var pos = 0, last = 0; var pos = 0, last = 0;
for (var i = 0, len = self.args.length; i < len; i++) { for (var i = 0; i < self.args.length; i++) {
var trim = i >= fn.argnames.length; var trim = i >= fn.argnames.length;
if (trim || fn.argnames[i].__unused) { if (trim || fn.argnames[i].__unused) {
var node = self.args[i].drop_side_effect_free(compressor); var node = self.args[i].drop_side_effect_free(compressor);
@@ -5035,7 +5108,7 @@ merge(Compressor.prototype, {
})) { })) {
return false; return false;
} }
} else if (line instanceof AST_EmptyStatement) { } else if (line instanceof AST_Defun || line instanceof AST_EmptyStatement) {
continue; continue;
} else if (stat) { } else if (stat) {
return false; return false;
@@ -5046,33 +5119,32 @@ merge(Compressor.prototype, {
return return_value(stat); return return_value(stat);
} }
function var_exists(catches, name) {
return catches[name] || identifier_atom[name] || scope.var_names()[name];
}
function can_inject_args(catches, safe_to_inject) { function can_inject_args(catches, safe_to_inject) {
for (var i = 0, len = fn.argnames.length; i < len; i++) { for (var i = 0; i < fn.argnames.length; i++) {
var arg = fn.argnames[i]; var arg = fn.argnames[i];
if (arg.__unused) continue; if (arg.__unused) continue;
if (!safe_to_inject if (!safe_to_inject || var_exists(catches, arg.name)) return false;
|| catches[arg.name]
|| identifier_atom[arg.name]
|| scope.var_names()[arg.name]) {
return false;
}
if (in_loop) in_loop.push(arg.definition()); if (in_loop) in_loop.push(arg.definition());
} }
return true; return true;
} }
function can_inject_vars(catches, safe_to_inject) { function can_inject_vars(catches, safe_to_inject) {
for (var i = 0, len = fn.body.length; i < len; i++) { for (var i = 0; i < fn.body.length; i++) {
var stat = fn.body[i]; var stat = fn.body[i];
if (stat instanceof AST_Defun) {
if (!safe_to_inject || var_exists(catches, stat.name.name)) return false;
continue;
}
if (!(stat instanceof AST_Var)) continue; if (!(stat instanceof AST_Var)) continue;
if (!safe_to_inject) return false; if (!safe_to_inject) return false;
for (var j = stat.definitions.length; --j >= 0;) { for (var j = stat.definitions.length; --j >= 0;) {
var name = stat.definitions[j].name; var name = stat.definitions[j].name;
if (catches[name.name] if (var_exists(catches, name.name)) return false;
|| identifier_atom[name.name]
|| scope.var_names()[name.name]) {
return false;
}
if (in_loop) in_loop.push(name.definition()); if (in_loop) in_loop.push(name.definition());
} }
} }
@@ -5142,10 +5214,10 @@ merge(Compressor.prototype, {
function flatten_vars(decls, expressions) { function flatten_vars(decls, expressions) {
var pos = expressions.length; var pos = expressions.length;
for (var i = 0, lines = fn.body.length; i < lines; i++) { for (var i = 0; i < fn.body.length; i++) {
var stat = fn.body[i]; var stat = fn.body[i];
if (!(stat instanceof AST_Var)) continue; if (!(stat instanceof AST_Var)) continue;
for (var j = 0, defs = stat.definitions.length; j < defs; j++) { for (var j = 0; j < stat.definitions.length; j++) {
var var_def = stat.definitions[j]; var var_def = stat.definitions[j];
var name = var_def.name; var name = var_def.name;
var redef = name.definition().redefined(); var redef = name.definition().redefined();
@@ -5176,12 +5248,21 @@ merge(Compressor.prototype, {
flatten_args(decls, expressions); flatten_args(decls, expressions);
flatten_vars(decls, expressions); flatten_vars(decls, expressions);
expressions.push(value); expressions.push(value);
if (decls.length) { var args = fn.body.filter(function(stat) {
i = scope.body.indexOf(compressor.parent(level - 1)) + 1; if (stat instanceof AST_Defun) {
scope.body.splice(i, 0, make_node(AST_Var, fn, { var def = stat.name.definition();
definitions: decls scope.functions.set(def.name, def);
})); scope.variables.set(def.name, def);
} scope.enclosed.push(def);
scope.var_names()[def.name] = true;
return true;
}
});
args.unshift(scope.body.indexOf(compressor.parent(level - 1)) + 1, 0);
if (decls.length) args.push(make_node(AST_Var, fn, {
definitions: decls
}));
[].splice.apply(scope.body, args);
return expressions; return expressions;
} }
}); });
@@ -5846,7 +5927,7 @@ merge(Compressor.prototype, {
var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor)); var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
if (single_use && fixed instanceof AST_Lambda) { if (single_use && fixed instanceof AST_Lambda) {
if (def.scope !== self.scope if (def.scope !== self.scope
&& (!compressor.option("reduce_funcs") || def.escaped == 1 || fixed.inlined)) { && (!compressor.option("reduce_funcs") || def.escaped.depth == 1 || fixed.inlined)) {
single_use = false; single_use = false;
} else if (recursive_ref(compressor, def)) { } else if (recursive_ref(compressor, def)) {
single_use = false; single_use = false;

View File

@@ -123,7 +123,7 @@ function OutputStream(options) {
}); });
} : function(str) { } : function(str) {
var s = ""; var s = "";
for (var i = 0, len = str.length; i < len; i++) { for (var i = 0; i < str.length; i++) {
if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1]) if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1])
|| is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) { || is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) {
s += "\\u" + str.charCodeAt(i).toString(16); s += "\\u" + str.charCodeAt(i).toString(16);

View File

@@ -164,10 +164,6 @@ function is_unicode_connector_punctuation(ch) {
return UNICODE.connector_punctuation.test(ch); return UNICODE.connector_punctuation.test(ch);
} }
function is_identifier(name) {
return !RESERVED_WORDS[name] && /^[a-z_$][a-z0-9_$]*$/i.test(name);
}
function is_identifier_start(code) { function is_identifier_start(code) {
return code == 36 || code == 95 || is_letter(code); return code == 36 || code == 95 || is_letter(code);
} }
@@ -272,10 +268,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function find_eol() { function find_eol() {
var text = S.text; var text = S.text;
for (var i = S.pos, n = S.text.length; i < n; ++i) { for (var i = S.pos; i < S.text.length; ++i) {
var ch = text[i]; if (NEWLINE_CHARS[text[i]]) return i;
if (NEWLINE_CHARS[ch])
return i;
} }
return -1; return -1;
} }

View File

@@ -61,8 +61,6 @@ SymbolDef.next_id = 1;
SymbolDef.prototype = { SymbolDef.prototype = {
unmangleable: function(options) { unmangleable: function(options) {
if (!options) options = {};
return this.global && !options.toplevel return this.global && !options.toplevel
|| this.undeclared || this.undeclared
|| !options.eval && this.scope.pinned() || !options.eval && this.scope.pinned()
@@ -198,24 +196,20 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
} }
if (node instanceof AST_SymbolLambda) { if (node instanceof AST_SymbolLambda) {
var def = node.thedef; var def = node.thedef;
if (def.orig.length == 1) { redefine(node, node.scope.parent_scope);
redefine(node, node.scope.parent_scope); node.thedef.init = def.init;
node.thedef.init = def.init;
}
return true; return true;
} }
})); }));
function redefine(node, scope) { function redefine(node, scope) {
var name = node.name; var name = node.name;
var refs = node.thedef.references; var old_def = node.thedef;
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node); var new_def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
refs.forEach(function(ref) { old_def.orig.concat(old_def.references).forEach(function(node) {
ref.thedef = def; node.thedef = new_def;
ref.reference(options); node.reference(options);
}); });
node.thedef = def;
node.reference(options);
} }
}); });
@@ -300,7 +294,7 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
AST_Lambda.DEFMETHOD("resolve", return_this); AST_Lambda.DEFMETHOD("resolve", return_this);
AST_Scope.DEFMETHOD("resolve", function() { AST_Scope.DEFMETHOD("resolve", function() {
return this.parent_scope; return this.parent_scope.resolve();
}); });
AST_Toplevel.DEFMETHOD("resolve", return_this); AST_Toplevel.DEFMETHOD("resolve", return_this);
@@ -337,7 +331,7 @@ function next_mangled_name(scope, options, def) {
} while (scope = scope.parent_scope); } while (scope = scope.parent_scope);
}); });
var name; var name;
for (var i = 0, len = holes.length; i < len; i++) { for (var i = 0; i < holes.length; i++) {
name = base54(holes[i]); name = base54(holes[i]);
if (names[name]) continue; if (names[name]) continue;
holes.splice(i, 1); holes.splice(i, 1);
@@ -346,7 +340,7 @@ function next_mangled_name(scope, options, def) {
} }
while (true) { while (true) {
name = base54(++scope.cname); name = base54(++scope.cname);
if (in_use[name] || !is_identifier(name) || options.reserved.has[name]) continue; if (in_use[name] || RESERVED_WORDS[name] || options.reserved.has[name]) continue;
if (!names[name]) break; if (!names[name]) break;
holes.push(scope.cname); holes.push(scope.cname);
} }
@@ -426,7 +420,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
var name; var name;
do { do {
name = base54(++lname); name = base54(++lname);
} while (!is_identifier(name)); } while (RESERVED_WORDS[name]);
node.mangled_name = name; node.mangled_name = name;
return true; return true;
} }
@@ -497,7 +491,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
var name; var name;
do { do {
name = base54(cname++); name = base54(cname++);
} while (avoid[name] || !is_identifier(name)); } while (avoid[name] || RESERVED_WORDS[name]);
return name; return name;
} }
@@ -559,7 +553,7 @@ var base54 = (function() {
var freq = Object.create(null); var freq = Object.create(null);
function init(chars) { function init(chars) {
var array = []; var array = [];
for (var i = 0, len = chars.length; i < len; i++) { for (var i = 0; i < chars.length; i++) {
var ch = chars[i]; var ch = chars[i];
array.push(ch); array.push(ch);
freq[ch] = -1e-2 * i; freq[ch] = -1e-2 * i;

View File

@@ -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.5.2", "version": "3.5.7",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -23,12 +23,12 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.19.0", "commander": "~2.20.0",
"source-map": "~0.6.1" "source-map": "~0.6.1"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~6.1.1", "acorn": "~6.1.1",
"semver": "~5.6.0" "semver": "~6.0.0"
}, },
"scripts": { "scripts": {
"test": "node test/run-tests.js" "test": "node test/run-tests.js"

View File

@@ -289,3 +289,25 @@ increment_decrement_2: {
} }
expect_stdout: "42" expect_stdout: "42"
} }
issue_3375: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
console.log(typeof function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect: {
console.log(typeof function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect_stdout: "string"
}

View File

@@ -6157,3 +6157,24 @@ sub_property: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
assign_undeclared: {
options = {
collapse_vars: true,
toplevel: true,
unused: true,
}
input: {
var A = (console.log(42), function() {});
B = new A();
console.log(typeof B);
}
expect: {
B = new (console.log(42), function() {})();
console.log(typeof B);
}
expect_stdout: [
"42",
"object",
]
}

View File

@@ -2005,3 +2005,24 @@ issue_3233: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3375: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var b = 1;
var a = c = [], c = --b + ("function" == typeof f && f());
var a = c && c[a];
console.log(a, b);
}
expect: {
var b = 1;
var a = [], c = --b + ("function" == typeof f && f());
a = c && c[a];
console.log(a, b);
}
expect_stdout: "0 0"
}

View File

@@ -1124,14 +1124,14 @@ issue_2207_1: {
console.log(Math.max(3, 6, 2, 7, 3, 4)); console.log(Math.max(3, 6, 2, 7, 3, 4));
console.log(Math.cos(1.2345)); console.log(Math.cos(1.2345));
console.log(Math.cos(1.2345) - Math.sin(4.321)); console.log(Math.cos(1.2345) - Math.sin(4.321));
console.log(Math.pow(Math.PI, Math.E - Math.LN10)); console.log(Math.pow(Math.PI, Math.E - Math.LN10).toFixed(15));
} }
expect: { expect: {
console.log("A"); console.log("A");
console.log(7); console.log(7);
console.log(Math.cos(1.2345)); console.log(Math.cos(1.2345));
console.log(1.2543732512566947); console.log(1.2543732512566947);
console.log(1.6093984514472044); console.log("1.609398451447204");
} }
expect_stdout: true expect_stdout: true
} }
@@ -1687,3 +1687,28 @@ try_increment: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
unsafe_escaped: {
options = {
evaluate: true,
inline: true,
passes: 3,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
(function(a) {
console.log(function(index) {
return a[index];
}(function(term) {
return a.indexOf(term);
}("PASS")));
})([ "PASS" ]);
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -2703,3 +2703,365 @@ loop_inline: {
} }
expect_stdout: "undefined" expect_stdout: "undefined"
} }
functions: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
var a = function a() {
return a && "a";
};
var b = function x() {
return !!x;
};
var c = function(c) {
return c;
};
if (c(b(a()))) {
var d = function() {};
var e = function y() {
return typeof y;
};
var f = function(f) {
return f;
};
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
}
}();
}
expect: {
!function() {
function a() {
return a && "a";
}
function b() {
return !!b;
}
var c = function(c) {
return c;
};
if (c(b(a()))) {
function d() {}
function e() {
return typeof e;
}
var f = function(f) {
return f;
};
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
}
}();
}
expect_stdout: "a true 42 function function function"
}
functions_use_strict: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
"use strict";
!function() {
var a = function a() {
return a && "a";
};
var b = function x() {
return !!x;
};
var c = function(c) {
return c;
};
if (c(b(a()))) {
var d = function() {};
var e = function y() {
return typeof y;
};
var f = function(f) {
return f;
};
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
}
}();
}
expect: {
"use strict";
!function() {
function a() {
return a && "a";
}
function b() {
return !!b;
}
var c = function(c) {
return c;
};
if (c(b(a()))) {
var d = function() {};
var e = function y() {
return typeof y;
};
var f = function(f) {
return f;
};
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
}
}();
}
expect_stdout: "a true 42 function function function"
}
issue_2437: {
options = {
collapse_vars: true,
conditionals: true,
functions: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function foo() {
return bar();
}
function bar() {
if (xhrDesc) {
var req = new XMLHttpRequest();
var result = !!req.onreadystatechange;
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
return result;
} else {
var req = new XMLHttpRequest();
var detectFunc = function(){};
req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null;
return result;
}
}
console.log(foo());
}
expect: {
console.log(function() {
if (xhrDesc) {
var result = !!(req = new XMLHttpRequest()).onreadystatechange;
return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
result;
}
function detectFunc() {}
var req;
(req = new XMLHttpRequest()).onreadystatechange = detectFunc;
result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
return req.onreadystatechange = null, result;
}());
}
}
issue_2485: {
options = {
functions: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
var foo = function(bar) {
var n = function(a, b) {
return a + b;
};
var sumAll = function(arg) {
return arg.reduce(n, 0);
};
var runSumAll = function(arg) {
return sumAll(arg);
};
bar.baz = function(arg) {
var n = runSumAll(arg);
return (n.get = 1), n;
};
return bar;
};
var bar = foo({});
console.log(bar.baz([1, 2, 3]));
}
expect: {
var foo = function(bar) {
function n(a, b) {
return a + b;
}
function runSumAll(arg) {
return function(arg) {
return arg.reduce(n, 0);
}(arg);
}
bar.baz = function(arg) {
var n = runSumAll(arg);
return (n.get = 1), n;
};
return bar;
};
var bar = foo({});
console.log(bar.baz([1, 2, 3]));
}
expect_stdout: "6"
}
issue_3364: {
options = {
functions: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {}
input: {
var s = 2, a = 100, b = 10, c = 0;
function f(p, e, r) {
try {
for (var i = 1; i-- > 0;)
var a = function(x) {
function g(y) {
y && y[a++];
}
var x = g(--s >= 0 && f(c++));
for (var j = 1; --j > 0;);
}();
} catch (e) {
try {
return;
} catch (z) {
for (var k = 1; --k > 0;) {
for (var l = 1; l > 0; --l) {
var n = function() {};
for (var k in n)
var o = (n, k);
}
}
}
}
}
var r = f();
console.log(c);
}
expect: {
var s = 2, c = 0;
(function n(r, o, a) {
try {
for (var f = 1; f-- >0;)
var t = function(r) {
(function(r) {
r && r[t++];
})(--s >= 0 && n(c++));
for (var o = 1; --o > 0;);
}();
} catch (o) {
try {
return;
} catch (r) {
for (var v = 1; --v > 0;)
for (var i = 1; i > 0;--i) {
function u() {}
for (var v in u);
}
}
}
})();
console.log(c);
}
expect_stdout: "2"
}
issue_3366: {
options = {
functions: true,
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
return function() {};
}
var a = g();
(function() {
this && a && console.log("PASS");
})();
}
f();
}
expect: {
void function() {
this && a && console.log("PASS");
}();
function a() {}
}
expect_stdout: "PASS"
}
issue_3371: {
options = {
functions: true,
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
(function() {
var a = function f() {
(function() {
console.log(typeof f);
})();
};
while (a());
})();
}
expect: {
(function() {
function a() {
console.log(typeof a);
}
while (a());
})();
}
expect_stdout: "function"
}
class_iife: {
options = {
inline: true,
sequences: true,
toplevel: true,
}
input: {
var A = function() {
function B() {}
B.prototype.m = function() {
console.log("PASS");
};
return B;
}();
new A().m();
}
expect: {
var A = (B.prototype.m = function() {
console.log("PASS");
}, B);
function B() {}
new A().m();
}
expect_stdout: "PASS"
}

View File

@@ -861,3 +861,111 @@ issue_3215_4: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3355_1: {
mangle = {
ie8: false,
}
input: {
(function f() {
var f;
})();
(function g() {
})();
console.log(typeof f === typeof g);
}
expect: {
(function o() {
var o;
})();
(function o() {
})();
console.log(typeof f === typeof g);
}
expect_stdout: "true"
}
issue_3355_2: {
mangle = {
ie8: true,
}
input: {
(function f() {
var f;
})();
(function g() {
})();
console.log(typeof f === typeof g);
}
expect: {
(function f() {
var f;
})();
(function g() {
})();
console.log(typeof f === typeof g);
}
expect_stdout: "true"
}
issue_3355_3: {
mangle = {
ie8: false,
}
input: {
!function(a) {
"aaaaaaaaaa";
a();
var b = function c() {
var c = 42;
console.log("FAIL");
};
}(function() {
console.log("PASS");
});
}
expect: {
!function(a) {
"aaaaaaaaaa";
a();
var o = function a() {
var a = 42;
console.log("FAIL");
};
}(function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}
issue_3355_4: {
mangle = {
ie8: true,
}
input: {
!function(a) {
"aaaaaaaaaa";
a();
var b = function c() {
var c = 42;
console.log("FAIL");
};
}(function() {
console.log("PASS");
});
}
expect: {
!function(a) {
"aaaaaaaaaa";
a();
var o = function n() {
var n = 42;
console.log("FAIL");
};
}(function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}

View File

@@ -646,3 +646,30 @@ issue_2904: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
issue_3371: {
options = {
functions: true,
join_vars: true,
loops: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = function() {
console.log("PASS");
};
while (a());
})();
}
expect: {
(function() {
function a() {
console.log("PASS");
}
for (; a(); );
})();
}
expect_stdout: "PASS"
}

View File

@@ -281,8 +281,8 @@ unsafe_evaluate_escaped: {
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }()); console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
} }
expect: { expect: {
console.log(function(){ var o={p:1}; console.log(o, o.p); return o.p; }()); console.log(function(){ var o={p:1}; console.log(o, 1); return o.p; }());
console.log(function(){ var o={p:2}; console.log(o.p, o); return o.p; }()); console.log(function(){ var o={p:2}; console.log(2, o); return o.p; }());
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }()); console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
} }
expect_stdout: true expect_stdout: true
@@ -6737,3 +6737,21 @@ drop_side_effect_free: {
} }
expect_stdout: "123" expect_stdout: "123"
} }
issue_3377: {
options = {
reduce_vars: true,
unused: true,
}
input: {
console.log(function f() {
return f[0], (f = 42);
}());
}
expect: {
console.log(function f() {
return f[0], (f = 42);
}());
}
expect_stdout: "42"
}

View File

@@ -1,7 +1,5 @@
exports["base54"] = base54;
exports["Compressor"] = Compressor; exports["Compressor"] = Compressor;
exports["defaults"] = defaults; exports["defaults"] = defaults;
exports["is_identifier"] = is_identifier;
exports["JS_Parse_Error"] = JS_Parse_Error; exports["JS_Parse_Error"] = JS_Parse_Error;
exports["mangle_properties"] = mangle_properties; exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify; exports["minify"] = minify;
@@ -9,7 +7,6 @@ exports["OutputStream"] = OutputStream;
exports["parse"] = parse; exports["parse"] = parse;
exports["push_uniq"] = push_uniq; exports["push_uniq"] = push_uniq;
exports["reserve_quoted_keys"] = reserve_quoted_keys; exports["reserve_quoted_keys"] = reserve_quoted_keys;
exports["SourceMap"] = SourceMap;
exports["string_template"] = string_template; exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer; exports["tokenizer"] = tokenizer;
exports["TreeTransformer"] = TreeTransformer; exports["TreeTransformer"] = TreeTransformer;

View File

@@ -3,7 +3,7 @@
"use strict"; "use strict";
var site = "https://browserbench.org/JetStream"; var site = "https://browserbench.org/JetStream1.1";
if (typeof phantom == "undefined") { if (typeof phantom == "undefined") {
require("../tools/exit"); require("../tools/exit");
var args = process.argv.slice(2); var args = process.argv.slice(2);

View File

@@ -73,8 +73,10 @@ exports.run_code = function(code, reuse) {
process.stdout.write = original_write; process.stdout.write = original_write;
if (!reuse || code.indexOf(".prototype") >= 0) { if (!reuse || code.indexOf(".prototype") >= 0) {
context = null; context = null;
} else for (var key in context) { } else {
delete context[key]; vm.runInContext(Object.keys(context).map(function(name) {
return "delete " + name;
}).join("\n"), context);
} }
} }
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +1,540 @@
<!doctype html>
<html> <html>
<head> <body>
</head> <script>
<body> !function() {
<script>(function(){ var names = [];
var props = {}; var scanned = [];
var to_scan = [];
function addObject(obj) { function scan(obj) {
if (obj == null) return; if (obj && typeof obj == "object" && !~scanned.indexOf(obj)) {
try { scanned.push(obj);
Object.getOwnPropertyNames(obj).forEach(add); to_scan.push(obj);
} catch(ex) {} }
if (obj.prototype) { }
Object.getOwnPropertyNames(obj.prototype).forEach(add);
}
if (typeof obj == "function") {
try {
Object.getOwnPropertyNames(new obj).forEach(add);
} catch(ex) {}
}
}
function add(name) { scan(self);
props[name] = true; [
} "a",
"abbr",
"acronym",
"address",
"applet",
"area",
"article",
"aside",
"audio",
"b",
"base",
"basefont",
"bdi",
"bdo",
"bgsound",
"big",
"blink",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"center",
"checked",
"cite",
"code",
"col",
"colgroup",
"command",
"comment",
"compact",
"content",
"data",
"datalist",
"dd",
"declare",
"defer",
"del",
"details",
"dfn",
"dialog",
"dir",
"disabled",
"div",
"dl",
"dt",
"element",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"font",
"footer",
"form",
"frame",
"frameset",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"iframe",
"image",
"img",
"input",
"ins",
"isindex",
"ismap",
"kbd",
"keygen",
"label",
"legend",
"li",
"link",
"listing",
"main",
"map",
"mark",
"marquee",
"math",
"menu",
"menuitem",
"meta",
"meter",
"multicol",
"multiple",
"nav",
"nobr",
"noembed",
"noframes",
"nohref",
"noresize",
"noscript",
"noshade",
"nowrap",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"picture",
"plaintext",
"pre",
"progress",
"q",
"rb",
"readonly",
"rp",
"rt",
"rtc",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"selected",
"shadow",
"small",
"source",
"spacer",
"span",
"strike",
"strong",
"style",
"sub",
"summary",
"sup",
"svg",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"tt",
"u",
"ul",
"var",
"video",
"wbr",
"xmp",
"XXX",
].forEach(function(tag) {
scan(document.createElement(tag));
});
[
"abort",
"absolutedeviceorientation",
"activate",
"active",
"addsourcebuffer",
"addstream",
"addtrack",
"afterprint",
"afterscriptexecute",
"afterupdate",
"animationcancel",
"animationend",
"animationiteration",
"animationstart",
"appinstalled",
"audioend",
"audioprocess",
"audiostart",
"autocomplete",
"autocompleteerror",
"auxclick",
"beforeactivate",
"beforecopy",
"beforecut",
"beforedeactivate",
"beforeeditfocus",
"beforeinstallprompt",
"beforepaste",
"beforeprint",
"beforescriptexecute",
"beforeunload",
"beforeupdate",
"blocked",
"blur",
"bounce",
"boundary",
"cached",
"cancel",
"candidatewindowhide",
"candidatewindowshow",
"candidatewindowupdate",
"canplay",
"canplaythrough",
"cellchange",
"change",
"chargingchange",
"chargingtimechange",
"checking",
"click",
"close",
"compassneedscalibration",
"complete",
"connect",
"connecting",
"connectionstatechange",
"contextmenu",
"controllerchange",
"controlselect",
"copy",
"cuechange",
"cut",
"dataavailable",
"datachannel",
"datasetchanged",
"datasetcomplete",
"dblclick",
"deactivate",
"devicechange",
"devicelight",
"devicemotion",
"deviceorientation",
"deviceorientationabsolute",
"deviceproximity",
"dischargingtimechange",
"disconnect",
"display",
"downloading",
"drag",
"dragend",
"dragenter",
"dragexit",
"dragleave",
"dragover",
"dragstart",
"drop",
"durationchange",
"emptied",
"encrypted",
"end",
"ended",
"enter",
"enterpictureinpicture",
"error",
"errorupdate",
"exit",
"filterchange",
"finish",
"focus",
"focusin",
"focusout",
"freeze",
"fullscreenchange",
"fullscreenerror",
"gesturechange",
"gestureend",
"gesturestart",
"gotpointercapture",
"hashchange",
"help",
"icecandidate",
"iceconnectionstatechange",
"icegatheringstatechange",
"inactive",
"input",
"invalid",
"keydown",
"keypress",
"keyup",
"languagechange",
"layoutcomplete",
"leavepictureinpicture",
"levelchange",
"load",
"loadeddata",
"loadedmetadata",
"loadend",
"loading",
"loadingdone",
"loadingerror",
"loadstart",
"losecapture",
"lostpointercapture",
"mark",
"message",
"messageerror",
"mousedown",
"mouseenter",
"mouseleave",
"mousemove",
"mouseout",
"mouseover",
"mouseup",
"mousewheel",
"move",
"moveend",
"movestart",
"mozfullscreenchange",
"mozfullscreenerror",
"mozorientationchange",
"mozpointerlockchange",
"mozpointerlockerror",
"mscontentzoom",
"msfullscreenchange",
"msfullscreenerror",
"msgesturechange",
"msgesturedoubletap",
"msgestureend",
"msgesturehold",
"msgesturestart",
"msgesturetap",
"msgotpointercapture",
"msinertiastart",
"mslostpointercapture",
"msmanipulationstatechanged",
"msneedkey",
"msorientationchange",
"mspointercancel",
"mspointerdown",
"mspointerenter",
"mspointerhover",
"mspointerleave",
"mspointermove",
"mspointerout",
"mspointerover",
"mspointerup",
"mssitemodejumplistitemremoved",
"msthumbnailclick",
"negotiationneeded",
"nomatch",
"noupdate",
"obsolete",
"offline",
"online",
"open",
"orientationchange",
"pagechange",
"pagehide",
"pageshow",
"paste",
"pause",
"play",
"playing",
"pluginstreamstart",
"pointercancel",
"pointerdown",
"pointerenter",
"pointerleave",
"pointerlockchange",
"pointerlockerror",
"pointermove",
"pointerout",
"pointerover",
"pointerup",
"popstate",
"progress",
"propertychange",
"ratechange",
"reading",
"readystatechange",
"rejectionhandled",
"removesourcebuffer",
"removestream",
"removetrack",
"reset",
"resize",
"resizeend",
"resizestart",
"resourcetimingbufferfull",
"result",
"resume",
"rowenter",
"rowexit",
"rowsdelete",
"rowsinserted",
"scroll",
"search",
"seeked",
"seeking",
"select",
"selectionchange",
"selectstart",
"show",
"signalingstatechange",
"soundend",
"soundstart",
"sourceclose",
"sourceclosed",
"sourceended",
"sourceopen",
"speechend",
"speechstart",
"stalled",
"start",
"statechange",
"stop",
"storage",
"storagecommit",
"submit",
"success",
"suspend",
"textinput",
"timeout",
"timeupdate",
"toggle",
"touchcancel",
"touchend",
"touchmove",
"touchstart",
"track",
"transitioncancel",
"transitionend",
"transitionrun",
"transitionstart",
"unhandledrejection",
"unload",
"updateready",
"upgradeneeded",
"userproximity",
"versionchange",
"visibilitychange",
"voiceschanged",
"volumechange",
"vrdisplayactivate",
"vrdisplayconnect",
"vrdisplaydeactivate",
"vrdisplaydisconnect",
"vrdisplaypresentchange",
"waiting",
"waitingforkey",
"warning",
"webkitanimationend",
"webkitanimationiteration",
"webkitanimationstart",
"webkitcurrentplaybacktargetiswirelesschanged",
"webkitfullscreenchange",
"webkitfullscreenerror",
"webkitkeyadded",
"webkitkeyerror",
"webkitkeymessage",
"webkitneedkey",
"webkitorientationchange",
"webkitplaybacktargetavailabilitychanged",
"webkitpointerlockchange",
"webkitpointerlockerror",
"webkitresourcetimingbufferfull",
"webkittransitionend",
"wheel",
"zoom",
].forEach(function(type) {
[
"beforeunloadevent",
"compositionevent",
"customevent",
"devicemotionevent",
"deviceorientationevent",
"dragevent",
"event",
"events",
"focusevent",
"hashchangeevent",
"htmlevents",
"keyboardevent",
"messageevent",
"mouseevent",
"mouseevents",
"storageevent",
"svgevents",
"textevent",
"touchevent",
"uievent",
"uievents",
].forEach(function(interface) {
try {
var event = document.createEvent(interface);
event.initEvent(type, true, true);
scan(event);
} catch (e) {}
});
});
Object.getOwnPropertyNames(window).forEach(function(thing){ var obj;
addObject(window[thing]); while (obj = to_scan.shift()) {
}); var proto = obj;
do {
try { Object.getOwnPropertyNames(proto).forEach(function(name) {
addObject(new Event("click")); var visited = ~names.indexOf(name);
addObject(new Event("contextmenu")); if (!visited) names.push(name);
addObject(new Event("mouseup")); try {
addObject(new Event("mousedown")); scan(obj[name]);
addObject(new Event("keydown")); if (visited) return;
addObject(new Event("keypress")); if (/^create/.test(name)) {
addObject(new Event("keyup")); scan(obj[name]());
} catch(ex) {} }
if (/^[A-Z]/.test(name)) {
var ta = document.createElement("textarea"); scan(new obj[name]());
ta.style.width = "100%"; }
ta.style.height = "20em"; } catch (e) {}
ta.style.boxSizing = "border-box"; });
<!-- ta.value = Object.keys(props).sort(cmp).map(function(name){ --> } while (proto = Object.getPrototypeOf(proto));
<!-- return JSON.stringify(name); --> }
<!-- }).join(",\n"); --> names.sort();
ta.value = JSON.stringify({ document.write('<pre>[\n "');
vars: [], document.write(names.join('",\n "'));
props: Object.keys(props).sort(cmp) document.write('"\n]</pre>');
}, null, 2); }();
document.body.appendChild(ta); </script>
</body>
function cmp(a, b) {
a = a.toLowerCase();
b = b.toLowerCase();
return a < b ? -1 : a > b ? 1 : 0;
}
})();</script>
</body>
</html> </html>