enhance evaluate, functions & inline (#3931)
This commit is contained in:
@@ -450,6 +450,11 @@ merge(Compressor.prototype, {
|
|||||||
tw.safe_ids[def.id] = safe;
|
tw.safe_ids[def.id] = safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function push_ref(def, ref) {
|
||||||
|
def.references.push(ref);
|
||||||
|
def.last_ref = ref;
|
||||||
|
}
|
||||||
|
|
||||||
function add_assign(tw, def, node) {
|
function add_assign(tw, def, node) {
|
||||||
if (def.fixed === false) return;
|
if (def.fixed === false) return;
|
||||||
tw.assigns.add(def.id, node);
|
tw.assigns.add(def.id, node);
|
||||||
@@ -550,7 +555,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!(node instanceof AST_Symbol)) return;
|
if (!(node instanceof AST_Symbol)) return;
|
||||||
var d = node.definition();
|
var d = node.definition();
|
||||||
if (!d) return;
|
if (!d) return;
|
||||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
if (node instanceof AST_SymbolRef) push_ref(d, node);
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
});
|
});
|
||||||
def(AST_Accessor, function(tw, descend, compressor) {
|
def(AST_Accessor, function(tw, descend, compressor) {
|
||||||
@@ -588,7 +593,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
if (!safe) return;
|
if (!safe) return;
|
||||||
d.references.push(sym);
|
push_ref(d, sym);
|
||||||
mark(tw, d, false);
|
mark(tw, d, false);
|
||||||
node.right.walk(tw);
|
node.right.walk(tw);
|
||||||
mark(tw, d, true);
|
mark(tw, d, true);
|
||||||
@@ -784,7 +789,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_SymbolRef, function(tw, descend, compressor) {
|
def(AST_SymbolRef, function(tw, descend, compressor) {
|
||||||
if (this.fixed) delete this.fixed;
|
if (this.fixed) delete this.fixed;
|
||||||
var d = this.definition();
|
var d = this.definition();
|
||||||
d.references.push(this);
|
push_ref(d, this);
|
||||||
if (d.references.length == 1
|
if (d.references.length == 1
|
||||||
&& !d.fixed
|
&& !d.fixed
|
||||||
&& d.orig[0] instanceof AST_SymbolDefun) {
|
&& d.orig[0] instanceof AST_SymbolDefun) {
|
||||||
@@ -886,7 +891,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
if (!safe) return;
|
if (!safe) return;
|
||||||
d.references.push(exp);
|
push_ref(d, exp);
|
||||||
mark(tw, d, true);
|
mark(tw, d, true);
|
||||||
add_assign(tw, d, node);
|
add_assign(tw, d, node);
|
||||||
return true;
|
return true;
|
||||||
@@ -3280,12 +3285,30 @@ merge(Compressor.prototype, {
|
|||||||
return this.value;
|
return this.value;
|
||||||
});
|
});
|
||||||
def(AST_Assign, function(compressor, ignore_side_effects, cached, depth) {
|
def(AST_Assign, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
if (!ignore_side_effects) return this;
|
var lhs = this.left;
|
||||||
if (this.operator != "=") return this;
|
if (!ignore_side_effects) {
|
||||||
var node = this.right;
|
if (!(lhs instanceof AST_SymbolRef)) return this;
|
||||||
|
if (!HOP(lhs, "_eval") && !lhs.fixed) return this;
|
||||||
|
var def = lhs.definition();
|
||||||
|
if (def.undeclared) return this;
|
||||||
|
if (def.last_ref !== lhs) return this;
|
||||||
|
if (def.single_use == "m") return this;
|
||||||
|
}
|
||||||
|
var op = this.operator;
|
||||||
|
var node;
|
||||||
|
if (HOP(lhs, "_eval") || !lhs.fixed) {
|
||||||
|
node = op == "=" ? this.right : make_node(AST_Binary, this, {
|
||||||
|
operator: op.slice(0, -1),
|
||||||
|
left: lhs,
|
||||||
|
right: this.right,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
node = lhs;
|
||||||
|
}
|
||||||
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
modified(this.left);
|
if (value === node) return this;
|
||||||
return value === node ? this : value;
|
modified(lhs);
|
||||||
|
return value;
|
||||||
});
|
});
|
||||||
def(AST_Sequence, function(compressor, ignore_side_effects, cached, depth) {
|
def(AST_Sequence, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
if (!ignore_side_effects) return this;
|
if (!ignore_side_effects) return this;
|
||||||
@@ -3377,8 +3400,7 @@ merge(Compressor.prototype, {
|
|||||||
case "++":
|
case "++":
|
||||||
case "--":
|
case "--":
|
||||||
if (!(e instanceof AST_SymbolRef)) return this;
|
if (!(e instanceof AST_SymbolRef)) return this;
|
||||||
var refs = e.definition().references;
|
if (!ignore_side_effects && e.definition().last_ref !== e) return this;
|
||||||
if (!ignore_side_effects && refs[refs.length - 1] !== e) return this;
|
|
||||||
if (HOP(e, "_eval")) v = +(op[0] + 1) + +v;
|
if (HOP(e, "_eval")) v = +(op[0] + 1) + +v;
|
||||||
modified(e);
|
modified(e);
|
||||||
return v;
|
return v;
|
||||||
@@ -3388,11 +3410,11 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_UnaryPostfix, function(compressor, ignore_side_effects, cached, depth) {
|
def(AST_UnaryPostfix, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
var e = this.expression;
|
var e = this.expression;
|
||||||
if (!e.fixed) return this;
|
if (!e.fixed) return this;
|
||||||
var refs = e.definition().references;
|
if (!ignore_side_effects && e.definition().last_ref !== e) return this;
|
||||||
if (!ignore_side_effects && refs[refs.length - 1] !== e) return this;
|
|
||||||
var v = e._eval(compressor, ignore_side_effects, cached, depth + 1);
|
var v = e._eval(compressor, ignore_side_effects, cached, depth + 1);
|
||||||
|
if (v === e) return this;
|
||||||
modified(e);
|
modified(e);
|
||||||
return v === e ? this : +v;
|
return v;
|
||||||
});
|
});
|
||||||
var non_converting_binary = makePredicate("&& || === !==");
|
var non_converting_binary = makePredicate("&& || === !==");
|
||||||
def(AST_Binary, function(compressor, ignore_side_effects, cached, depth) {
|
def(AST_Binary, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
@@ -4385,13 +4407,11 @@ merge(Compressor.prototype, {
|
|||||||
var defun = make_node(AST_Defun, def, def.value);
|
var defun = make_node(AST_Defun, def, def.value);
|
||||||
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
||||||
var name_def = def.name.scope.resolve().def_function(defun.name);
|
var name_def = def.name.scope.resolve().def_function(defun.name);
|
||||||
if (old_def) def.value.walk(new TreeWalker(function(node) {
|
if (old_def) old_def.references.forEach(function(node) {
|
||||||
if (node instanceof AST_SymbolRef && node.definition() === old_def) {
|
node.name = name_def.name;
|
||||||
node.name = name_def.name;
|
node.thedef = name_def;
|
||||||
node.thedef = name_def;
|
node.reference({});
|
||||||
node.reference({});
|
});
|
||||||
}
|
|
||||||
}));
|
|
||||||
body.push(defun);
|
body.push(defun);
|
||||||
} else {
|
} else {
|
||||||
if (var_defs.length > 1 && sym.orig.indexOf(def.name) > sym.eliminated) {
|
if (var_defs.length > 1 && sym.orig.indexOf(def.name) > sym.eliminated) {
|
||||||
@@ -6242,17 +6262,19 @@ merge(Compressor.prototype, {
|
|||||||
&& !fn.uses_arguments
|
&& !fn.uses_arguments
|
||||||
&& !fn.pinned()
|
&& !fn.pinned()
|
||||||
&& !(fn.name && fn instanceof AST_Function)
|
&& !(fn.name && fn instanceof AST_Function)
|
||||||
&& (exp === fn
|
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
||||||
|| !recursive_ref(compressor, def = exp.definition()) && fn.is_constant_expression(exp.scope))
|
&& fn.is_constant_expression(compressor.find_parent(AST_Scope)))
|
||||||
&& (value = can_flatten_body(stat))
|
&& (value = can_flatten_body(stat))
|
||||||
&& !fn.contains_this()) {
|
&& !fn.contains_this()) {
|
||||||
|
var replacing = exp === fn || compressor.option("unused") && def.references.length - def.replaced == 1;
|
||||||
if (can_substitute_directly()) {
|
if (can_substitute_directly()) {
|
||||||
var args = self.args.slice();
|
var args = self.args.slice();
|
||||||
|
var refs = [];
|
||||||
args.push(value.clone(true).transform(new TreeTransformer(function(node) {
|
args.push(value.clone(true).transform(new TreeTransformer(function(node) {
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
if (fn.variables.get(node.name) !== def) {
|
if (fn.variables.get(node.name) !== def) {
|
||||||
if (exp !== fn) def.references.push(node);
|
refs.push(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
var index = resolve_index(def);
|
var index = resolve_index(def);
|
||||||
@@ -6267,11 +6289,17 @@ merge(Compressor.prototype, {
|
|||||||
return arg;
|
return arg;
|
||||||
})).optimize(compressor);
|
})).optimize(compressor);
|
||||||
node = maintain_this_binding(compressor, compressor.parent(), compressor.self(), node);
|
node = maintain_this_binding(compressor, compressor.parent(), compressor.self(), node);
|
||||||
if (best_of(compressor, self, node) === node) return node;
|
if (replacing || best_of(compressor, self, node) === node) {
|
||||||
|
refs.forEach(function(ref) {
|
||||||
|
var def = ref.definition();
|
||||||
|
def.references.push(ref);
|
||||||
|
if (replacing) def.replaced++;
|
||||||
|
});
|
||||||
|
return node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var scope, in_loop, level = -1;
|
var scope, in_loop, level = -1;
|
||||||
if ((exp === fn || compressor.option("unused") && def.references.length - def.replaced == 1)
|
if (replacing && can_inject_symbols()) {
|
||||||
&& can_inject_symbols()) {
|
|
||||||
fn._squeezed = true;
|
fn._squeezed = true;
|
||||||
if (exp !== fn) fn.parent_scope = exp.scope;
|
if (exp !== fn) fn.parent_scope = exp.scope;
|
||||||
var node = make_sequence(self, flatten_fn()).optimize(compressor);
|
var node = make_sequence(self, flatten_fn()).optimize(compressor);
|
||||||
@@ -6360,7 +6388,7 @@ merge(Compressor.prototype, {
|
|||||||
var begin;
|
var begin;
|
||||||
var in_order = [];
|
var in_order = [];
|
||||||
var side_effects = false;
|
var side_effects = false;
|
||||||
value.walk(new TreeWalker(function(node) {
|
value.walk(new TreeWalker(function(node, descend) {
|
||||||
if (abort) return true;
|
if (abort) return true;
|
||||||
if (node instanceof AST_Binary && lazy_op[node.operator]
|
if (node instanceof AST_Binary && lazy_op[node.operator]
|
||||||
|| node instanceof AST_Conditional) {
|
|| node instanceof AST_Conditional) {
|
||||||
@@ -6386,7 +6414,11 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node.has_side_effects(compressor)) side_effects = true;
|
if (node.has_side_effects(compressor)) {
|
||||||
|
descend();
|
||||||
|
side_effects = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
if (abort) return;
|
if (abort) return;
|
||||||
var end = self.args.length;
|
var end = self.args.length;
|
||||||
@@ -6395,8 +6427,8 @@ merge(Compressor.prototype, {
|
|||||||
while (end-- > begin && fn.argnames[end] === in_order.pop());
|
while (end-- > begin && fn.argnames[end] === in_order.pop());
|
||||||
end++;
|
end++;
|
||||||
}
|
}
|
||||||
var scope = side_effects && compressor.find_parent(AST_Scope);
|
var scope = side_effects && !in_order && compressor.find_parent(AST_Scope);
|
||||||
return end <= begin || all(self.args.slice(begin, end), side_effects ? function(funarg) {
|
return end <= begin || all(self.args.slice(begin, end), scope ? function(funarg) {
|
||||||
return funarg.is_constant_expression(scope);
|
return funarg.is_constant_expression(scope);
|
||||||
} : function(funarg) {
|
} : function(funarg) {
|
||||||
return !funarg.has_side_effects(compressor);
|
return !funarg.has_side_effects(compressor);
|
||||||
@@ -6685,7 +6717,7 @@ merge(Compressor.prototype, {
|
|||||||
var seq = lift_sequence_in_expression(self, compressor);
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
return self;
|
return try_evaluate(compressor, self);
|
||||||
});
|
});
|
||||||
|
|
||||||
var SIGN_OPS = makePredicate("+ -");
|
var SIGN_OPS = makePredicate("+ -");
|
||||||
@@ -7832,7 +7864,7 @@ merge(Compressor.prototype, {
|
|||||||
expression: self.left
|
expression: self.left
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return self;
|
return try_evaluate(compressor, self);
|
||||||
|
|
||||||
function in_try(level, node) {
|
function in_try(level, node) {
|
||||||
var right = self.right;
|
var right = self.right;
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ collapse_vars_side_effects_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f1() {
|
function f1() {
|
||||||
var s = "abcdef", i = 2;
|
var s = "abcdef", i = 2;
|
||||||
console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(i++), 7);
|
console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(4), 7);
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
var s = "abcdef", i = 2;
|
var s = "abcdef", i = 2;
|
||||||
@@ -74,13 +74,14 @@ collapse_vars_side_effects_1: {
|
|||||||
log = console.log.bind(console),
|
log = console.log.bind(console),
|
||||||
x = s.charAt(i++),
|
x = s.charAt(i++),
|
||||||
y = s.charAt(i++);
|
y = s.charAt(i++);
|
||||||
log(x, s.charAt(i++), y, 7);
|
log(x, s.charAt(4), y, 7);
|
||||||
}
|
}
|
||||||
function f4() {
|
function f4() {
|
||||||
var i = 10,
|
var i = 10;
|
||||||
x = i += 2,
|
i += 2,
|
||||||
y = i += 3;
|
i += 3,
|
||||||
console.log.bind(console)(x, i += 4, y, 19);
|
i += 4;
|
||||||
|
console.log.bind(console)(12, 19, 15, 19);
|
||||||
}
|
}
|
||||||
f1(), f2(), f3(), f4();
|
f1(), f2(), f3(), f4();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2485,3 +2485,62 @@ issue_3920: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "false"
|
expect_stdout: "false"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inlined_increment_prefix: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
(function() {
|
||||||
|
++a;
|
||||||
|
})();
|
||||||
|
console.log(a += 0);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
void ++a;
|
||||||
|
console.log(a += 0);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
inlined_increment_postfix: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
(function() {
|
||||||
|
a++;
|
||||||
|
})();
|
||||||
|
console.log(a += 0);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
void a++;
|
||||||
|
console.log(a += 0);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
compound_assignment_to_property: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
1 + (0..p >>= 0) && console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
1 + (0..p >>= 0),
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2724,8 +2724,8 @@ issue_1814_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
!function() {
|
!function() {
|
||||||
!function(a) {
|
!function(a) {
|
||||||
console.log(a++, 42);
|
console.log(0, 42);
|
||||||
}(0);
|
}();
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
expect_stdout: "0 42"
|
expect_stdout: "0 42"
|
||||||
@@ -2751,8 +2751,8 @@ issue_1814_2: {
|
|||||||
expect: {
|
expect: {
|
||||||
!function() {
|
!function() {
|
||||||
!function(a) {
|
!function(a) {
|
||||||
console.log("321", a++);
|
console.log("321", 0);
|
||||||
}(0);
|
}();
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
expect_stdout: "321 0"
|
expect_stdout: "321 0"
|
||||||
|
|||||||
Reference in New Issue
Block a user