10
README.md
10
README.md
@@ -779,11 +779,11 @@ to be `false` and all symbol names will be omitted.
|
|||||||
overhead (compression will be slower). Make sure symbols under `pure_funcs`
|
overhead (compression will be slower). Make sure symbols under `pure_funcs`
|
||||||
are also under `mangle.reserved` to avoid mangling.
|
are also under `mangle.reserved` to avoid mangling.
|
||||||
|
|
||||||
- `pure_getters` (default: `"strict"`) — If you pass `true` for
|
- `pure_getters` (default: `"strict"`) — Pass `true` for UglifyJS to assume that
|
||||||
this, UglifyJS will assume that object property access
|
object property access (e.g. `foo.bar` or `a[42]`) does not throw exception or
|
||||||
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
|
alter program states via getter function. Pass `"strict"` to allow dropping or
|
||||||
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
|
reordering `foo.bar` only if `foo` is not `null` or `undefined` and is safe to
|
||||||
`foo` is certain to not throw, i.e. not `null` or `undefined`.
|
access as a variable. Pass `false` to retain all property accesses.
|
||||||
|
|
||||||
- `reduce_funcs` (default: `true`) — Allows single-use functions to be
|
- `reduce_funcs` (default: `true`) — Allows single-use functions to be
|
||||||
inlined as function expressions when permissible allowing further
|
inlined as function expressions when permissible allowing further
|
||||||
|
|||||||
@@ -169,8 +169,6 @@ DEF_BITPROPS(AST_Node, [
|
|||||||
"private",
|
"private",
|
||||||
// AST_Call
|
// AST_Call
|
||||||
"pure",
|
"pure",
|
||||||
// AST_Assign
|
|
||||||
"redundant",
|
|
||||||
// AST_Node
|
// AST_Node
|
||||||
"single_use",
|
"single_use",
|
||||||
// AST_ClassProperty
|
// AST_ClassProperty
|
||||||
|
|||||||
@@ -638,15 +638,30 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function push(tw, sequential) {
|
function push(tw, sequential) {
|
||||||
|
var defined_ids = Object.create(tw.defined_ids);
|
||||||
var safe_ids = Object.create(tw.safe_ids);
|
var safe_ids = Object.create(tw.safe_ids);
|
||||||
if (!sequential) safe_ids.seq = {};
|
if (!sequential) {
|
||||||
|
defined_ids.seq = {};
|
||||||
|
safe_ids.seq = {};
|
||||||
|
}
|
||||||
|
tw.defined_ids = defined_ids;
|
||||||
tw.safe_ids = safe_ids;
|
tw.safe_ids = safe_ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pop(tw) {
|
function pop(tw) {
|
||||||
|
tw.defined_ids = Object.getPrototypeOf(tw.defined_ids);
|
||||||
tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
|
tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function access(tw, def) {
|
||||||
|
tw.defined_ids[def.id] = [ tw.defined_ids.seq ];
|
||||||
|
}
|
||||||
|
|
||||||
|
function assign(tw, def) {
|
||||||
|
var defined = tw.defined_ids[def.id];
|
||||||
|
if (defined) defined[0] = false;
|
||||||
|
}
|
||||||
|
|
||||||
function mark(tw, def) {
|
function mark(tw, def) {
|
||||||
tw.safe_ids[def.id] = {};
|
tw.safe_ids[def.id] = {};
|
||||||
}
|
}
|
||||||
@@ -939,9 +954,13 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return fixed_node;
|
return fixed_node;
|
||||||
}, visit);
|
}, visit);
|
||||||
walk_lambda(fn, tw);
|
walk_lambda(fn, tw);
|
||||||
|
var defined_ids = tw.defined_ids;
|
||||||
var safe_ids = tw.safe_ids;
|
var safe_ids = tw.safe_ids;
|
||||||
pop_scope(tw, fn);
|
pop_scope(tw, fn);
|
||||||
if (!aborts) tw.safe_ids = safe_ids;
|
if (!aborts) {
|
||||||
|
tw.defined_ids = defined_ids;
|
||||||
|
tw.safe_ids = safe_ids;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
function visit(node, fixed) {
|
function visit(node, fixed) {
|
||||||
@@ -966,10 +985,10 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var scan = ld || left instanceof AST_Destructured;
|
var scan = ld || left instanceof AST_Destructured;
|
||||||
switch (node.operator) {
|
switch (node.operator) {
|
||||||
case "=":
|
case "=":
|
||||||
|
if (ld) assign(tw, ld);
|
||||||
if (left.equals(right) && !left.has_side_effects(compressor)) {
|
if (left.equals(right) && !left.has_side_effects(compressor)) {
|
||||||
right.walk(tw);
|
right.walk(tw);
|
||||||
walk_prop(left);
|
walk_prop(left);
|
||||||
node.redundant = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (ld && right instanceof AST_LambdaExpression) {
|
if (ld && right instanceof AST_LambdaExpression) {
|
||||||
@@ -990,6 +1009,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
case "||=":
|
case "||=":
|
||||||
case "??=":
|
case "??=":
|
||||||
var lazy = true;
|
var lazy = true;
|
||||||
|
if (ld) assign(tw, ld);
|
||||||
default:
|
default:
|
||||||
if (!scan) {
|
if (!scan) {
|
||||||
mark_assignment_to_arguments(left);
|
mark_assignment_to_arguments(left);
|
||||||
@@ -1103,7 +1123,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
def(AST_BlockScope, function(tw, descend, compressor) {
|
def(AST_BlockScope, function(tw, descend, compressor) {
|
||||||
reset_block_variables(tw, compressor, this);
|
reset_block_variables(tw, compressor, this);
|
||||||
});
|
});
|
||||||
def(AST_Call, function(tw, descend) {
|
def(AST_Call, function(tw) {
|
||||||
var node = this;
|
var node = this;
|
||||||
var exp = node.expression;
|
var exp = node.expression;
|
||||||
if (exp instanceof AST_LambdaExpression) {
|
if (exp instanceof AST_LambdaExpression) {
|
||||||
@@ -1134,6 +1154,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (fixed instanceof AST_Lambda) {
|
if (fixed instanceof AST_Lambda) {
|
||||||
mark_fn_def(tw, exp.definition(), fixed);
|
mark_fn_def(tw, exp.definition(), fixed);
|
||||||
} else {
|
} else {
|
||||||
|
tw.defined_ids.seq = {};
|
||||||
tw.find_parent(AST_Scope).may_call_this();
|
tw.find_parent(AST_Scope).may_call_this();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -1238,6 +1259,12 @@ Compressor.prototype.compress = function(node) {
|
|||||||
tw.in_loop = save_loop;
|
tw.in_loop = save_loop;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
def(AST_Dot, function(tw, descend) {
|
||||||
|
descend();
|
||||||
|
var expr = this.expression;
|
||||||
|
if (expr instanceof AST_SymbolRef) access(tw, expr.definition());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
def(AST_For, function(tw, descend, compressor) {
|
def(AST_For, function(tw, descend, compressor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
reset_block_variables(tw, compressor, node);
|
reset_block_variables(tw, compressor, node);
|
||||||
@@ -1336,10 +1363,13 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Sub, function(tw) {
|
def(AST_Sub, function(tw) {
|
||||||
if (!this.optional) return;
|
var node = this;
|
||||||
this.expression.walk(tw);
|
if (!node.optional) return;
|
||||||
|
var expr = node.expression;
|
||||||
|
expr.walk(tw);
|
||||||
|
if (expr instanceof AST_SymbolRef) access(tw, expr.definition());
|
||||||
push(tw, true);
|
push(tw, true);
|
||||||
this.property.walk(tw);
|
node.property.walk(tw);
|
||||||
pop(tw);
|
pop(tw);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -1390,6 +1420,8 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var d = ref.definition();
|
var d = ref.definition();
|
||||||
var fixed = d.fixed || d.last_ref && d.last_ref.fixed;
|
var fixed = d.fixed || d.last_ref && d.last_ref.fixed;
|
||||||
push_ref(d, ref);
|
push_ref(d, ref);
|
||||||
|
var defined = tw.defined_ids[d.id];
|
||||||
|
if (defined && defined[0] === tw.defined_ids.seq) ref.defined = true;
|
||||||
if (d.references.length == 1 && !d.fixed && d.orig[0] instanceof AST_SymbolDefun) {
|
if (d.references.length == 1 && !d.fixed && d.orig[0] instanceof AST_SymbolDefun) {
|
||||||
tw.loop_ids[d.id] = tw.in_loop;
|
tw.loop_ids[d.id] = tw.in_loop;
|
||||||
}
|
}
|
||||||
@@ -1618,6 +1650,9 @@ Compressor.prototype.compress = function(node) {
|
|||||||
reset_flags(node);
|
reset_flags(node);
|
||||||
return node.reduce_vars(tw, descend, compressor);
|
return node.reduce_vars(tw, descend, compressor);
|
||||||
} : reset_flags);
|
} : reset_flags);
|
||||||
|
// Side-effect tracking on sequential property access
|
||||||
|
tw.defined_ids = Object.create(null);
|
||||||
|
tw.defined_ids.seq = {};
|
||||||
// Flow control for visiting lambda definitions
|
// Flow control for visiting lambda definitions
|
||||||
tw.fn_scanning = null;
|
tw.fn_scanning = null;
|
||||||
tw.fn_visited = [];
|
tw.fn_visited = [];
|
||||||
@@ -4712,6 +4747,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return this.tail_node()._dot_throw(compressor);
|
return this.tail_node()._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor, force) {
|
def(AST_SymbolRef, function(compressor, force) {
|
||||||
|
if (this.defined) return false;
|
||||||
if (this.is_undefined) return true;
|
if (this.is_undefined) return true;
|
||||||
if (!is_strict(compressor, force)) return false;
|
if (!is_strict(compressor, force)) return false;
|
||||||
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
||||||
@@ -12955,16 +12991,14 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
if (self.left instanceof AST_PropAccess) {
|
if (self.left instanceof AST_PropAccess) {
|
||||||
if (self.operator == "=") {
|
if (self.operator == "=") {
|
||||||
if (self.redundant) {
|
|
||||||
var exprs = [ self.left.expression ];
|
|
||||||
if (self.left instanceof AST_Sub) exprs.push(self.left.property);
|
|
||||||
exprs.push(self.right);
|
|
||||||
return make_sequence(self, exprs).optimize(compressor);
|
|
||||||
}
|
|
||||||
if (self.left.equals(self.right) && !self.left.has_side_effects(compressor)) {
|
|
||||||
return self.right;
|
|
||||||
}
|
|
||||||
var exp = self.left.expression;
|
var exp = self.left.expression;
|
||||||
|
if (self.left.equals(self.right)) {
|
||||||
|
var defined = exp.defined;
|
||||||
|
exp.defined = false;
|
||||||
|
var drop_lhs = !self.left.has_side_effects(compressor);
|
||||||
|
exp.defined = defined;
|
||||||
|
if (drop_lhs) return self.right;
|
||||||
|
}
|
||||||
if (exp instanceof AST_Lambda
|
if (exp instanceof AST_Lambda
|
||||||
|| !compressor.has_directive("use strict")
|
|| !compressor.has_directive("use strict")
|
||||||
&& exp instanceof AST_Constant
|
&& exp instanceof AST_Constant
|
||||||
|
|||||||
@@ -1312,7 +1312,7 @@ issue_5653: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((a => {
|
console.log((a => {
|
||||||
return console, +{};
|
return +{};
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
expect_stdout: "NaN"
|
||||||
|
|||||||
@@ -724,3 +724,106 @@ retain_instanceof: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drop_access: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {};
|
||||||
|
o.p;
|
||||||
|
try {
|
||||||
|
(function() {
|
||||||
|
o.q;
|
||||||
|
})();
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {};
|
||||||
|
o.p;
|
||||||
|
try {
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_access: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {};
|
||||||
|
o.p;
|
||||||
|
o = null;
|
||||||
|
try {
|
||||||
|
(function() {
|
||||||
|
o.q;
|
||||||
|
})();
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {};
|
||||||
|
o.p;
|
||||||
|
o = null;
|
||||||
|
try {
|
||||||
|
(function() {
|
||||||
|
o.q;
|
||||||
|
})();
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_access_after_call: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {};
|
||||||
|
o.p;
|
||||||
|
o.q;
|
||||||
|
f();
|
||||||
|
try {
|
||||||
|
o.r;
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
function f() {
|
||||||
|
o = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {};
|
||||||
|
o.p;
|
||||||
|
f();
|
||||||
|
try {
|
||||||
|
o.r;
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
function f() {
|
||||||
|
o = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user