fix unsafe on evaluate of reduce_vars (#1870)
Determine if variables with non-constant values can escape and be modified. fixes #1865
This commit is contained in:
@@ -283,6 +283,14 @@ merge(Compressor.prototype, {
|
||||
if (d.fixed === undefined || !safe_to_read(d)
|
||||
|| is_modified(node, 0, is_immutable(node.fixed_value()))) {
|
||||
d.fixed = false;
|
||||
} else {
|
||||
var parent = tw.parent();
|
||||
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|
||||
|| parent instanceof AST_Call && node !== parent.expression
|
||||
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|
||||
|| parent instanceof AST_VarDef && node === parent.value) {
|
||||
d.escaped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
@@ -482,6 +490,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function reset_def(def) {
|
||||
def.escaped = false;
|
||||
if (!def.global || def.orig[0] instanceof AST_SymbolConst || compressor.toplevel(def)) {
|
||||
def.fixed = undefined;
|
||||
} else {
|
||||
@@ -1595,23 +1604,20 @@ merge(Compressor.prototype, {
|
||||
: ev(this.alternative, compressor);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor){
|
||||
if (this._evaluating) throw def;
|
||||
if (!compressor.option("reduce_vars") || this._evaluating) throw def;
|
||||
this._evaluating = true;
|
||||
try {
|
||||
var fixed = this.fixed_value();
|
||||
if (compressor.option("reduce_vars") && fixed) {
|
||||
if (compressor.option("unsafe")) {
|
||||
if (!HOP(fixed, "_evaluated")) {
|
||||
fixed._evaluated = ev(fixed, compressor);
|
||||
}
|
||||
return fixed._evaluated;
|
||||
}
|
||||
return ev(fixed, compressor);
|
||||
}
|
||||
if (!fixed) throw def;
|
||||
var value = ev(fixed, compressor);
|
||||
if (!HOP(fixed, "_eval")) fixed._eval = function() {
|
||||
return value;
|
||||
};
|
||||
if (value && typeof value == "object" && this.definition().escaped) throw def;
|
||||
return value;
|
||||
} finally {
|
||||
this._evaluating = false;
|
||||
}
|
||||
throw def;
|
||||
});
|
||||
def(AST_PropAccess, function(compressor){
|
||||
if (compressor.option("unsafe")) {
|
||||
|
||||
@@ -297,7 +297,7 @@ unsafe_evaluate_array: {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe_evaluate_equality: {
|
||||
unsafe_evaluate_equality_1: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
reduce_vars : true,
|
||||
@@ -307,45 +307,60 @@ unsafe_evaluate_equality: {
|
||||
input: {
|
||||
function f0() {
|
||||
var a = {};
|
||||
console.log(a === a);
|
||||
return a === a;
|
||||
}
|
||||
|
||||
function f1() {
|
||||
var a = [];
|
||||
console.log(a === a);
|
||||
return a === a;
|
||||
}
|
||||
console.log(f0(), f1());
|
||||
}
|
||||
expect: {
|
||||
function f0() {
|
||||
return true;
|
||||
}
|
||||
function f1() {
|
||||
return true;
|
||||
}
|
||||
console.log(f0(), f1());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_evaluate_equality_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate : true,
|
||||
passes : 2,
|
||||
reduce_vars : true,
|
||||
unsafe : true,
|
||||
unused : true
|
||||
}
|
||||
input: {
|
||||
function f2() {
|
||||
var a = {a:1, b:2};
|
||||
var b = a;
|
||||
var c = a;
|
||||
console.log(b === c);
|
||||
return b === c;
|
||||
}
|
||||
|
||||
function f3() {
|
||||
var a = [1, 2, 3];
|
||||
var b = a;
|
||||
var c = a;
|
||||
console.log(b === c);
|
||||
return b === c;
|
||||
}
|
||||
console.log(f2(), f3());
|
||||
}
|
||||
expect: {
|
||||
function f0(){
|
||||
console.log(true);
|
||||
}
|
||||
|
||||
function f1(){
|
||||
console.log(true);
|
||||
}
|
||||
|
||||
function f2() {
|
||||
console.log(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
function f3() {
|
||||
console.log(true);
|
||||
return true;
|
||||
}
|
||||
console.log(f2(), f3());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
passes: {
|
||||
@@ -2417,3 +2432,32 @@ issue_1850_4: {
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1865: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
a.b = false;
|
||||
}
|
||||
console.log(function() {
|
||||
var some = { thing: true };
|
||||
f(some);
|
||||
return some.thing;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
a.b = false;
|
||||
}
|
||||
console.log(function() {
|
||||
var some = { thing: true };
|
||||
f(some);
|
||||
return some.thing;
|
||||
}());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user