improve reset_opt_flags() (#2610)
This commit is contained in:
618
lib/compress.js
618
lib/compress.js
@@ -293,14 +293,12 @@ merge(Compressor.prototype, {
|
||||
if (index >= 0) {
|
||||
node.body[index] = node.body[index].transform(tt);
|
||||
}
|
||||
}
|
||||
if (node instanceof AST_If) {
|
||||
} else if (node instanceof AST_If) {
|
||||
node.body = node.body.transform(tt);
|
||||
if (node.alternative) {
|
||||
node.alternative = node.alternative.transform(tt);
|
||||
}
|
||||
}
|
||||
if (node instanceof AST_With) {
|
||||
} else if (node instanceof AST_With) {
|
||||
node.body = node.body.transform(tt);
|
||||
}
|
||||
return node;
|
||||
@@ -308,292 +306,10 @@ merge(Compressor.prototype, {
|
||||
self.transform(tt);
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
|
||||
var reduce_vars = compressor.option("reduce_vars");
|
||||
var unused = compressor.option("unused");
|
||||
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
||||
// properly assigned before use:
|
||||
// - `push()` & `pop()` when visiting conditional branches
|
||||
// - backup & restore via `save_ids` when visiting out-of-order sections
|
||||
var safe_ids = Object.create(null);
|
||||
var suppressor = new TreeWalker(function(node) {
|
||||
if (!(node instanceof AST_Symbol)) return;
|
||||
var d = node.definition();
|
||||
if (!d) return;
|
||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||
d.fixed = false;
|
||||
});
|
||||
var in_loop = null;
|
||||
var loop_ids = Object.create(null);
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
if (reduce_vars) {
|
||||
if (node instanceof AST_Toplevel) node.globals.each(reset_def);
|
||||
if (node instanceof AST_Scope) node.variables.each(reset_def);
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var d = node.definition();
|
||||
d.references.push(node);
|
||||
if (d.references.length == 1
|
||||
&& !d.fixed
|
||||
&& d.orig[0] instanceof AST_SymbolDefun) {
|
||||
loop_ids[d.id] = in_loop;
|
||||
}
|
||||
var value;
|
||||
if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") {
|
||||
d.fixed = false;
|
||||
} else if (d.fixed) {
|
||||
value = node.fixed_value();
|
||||
if (value && ref_once(d)) {
|
||||
d.single_use = value instanceof AST_Lambda
|
||||
|| d.scope === node.scope && value.is_constant_expression();
|
||||
} else {
|
||||
d.single_use = false;
|
||||
}
|
||||
if (is_modified(node, value, 0, is_immutable(value))) {
|
||||
if (d.single_use) {
|
||||
d.single_use = "m";
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
mark_escaped(d, node.scope, node, value, 0);
|
||||
}
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
node.definition().fixed = false;
|
||||
}
|
||||
if (node instanceof AST_VarDef) {
|
||||
var d = node.name.definition();
|
||||
if (d.fixed === undefined || safe_to_assign(d, node.value)) {
|
||||
if (node.value) {
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
};
|
||||
loop_ids[d.id] = in_loop;
|
||||
mark(d, false);
|
||||
descend();
|
||||
} else {
|
||||
d.fixed = null;
|
||||
}
|
||||
mark(d, true);
|
||||
return true;
|
||||
} else if (node.value) {
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
if (node instanceof AST_Assign
|
||||
&& node.operator == "="
|
||||
&& node.left instanceof AST_SymbolRef) {
|
||||
var d = node.left.definition();
|
||||
if (safe_to_assign(d, node.right)
|
||||
|| d.fixed === undefined && all(d.orig, function(sym) {
|
||||
return sym instanceof AST_SymbolVar;
|
||||
})) {
|
||||
d.references.push(node.left);
|
||||
d.fixed = function() {
|
||||
return node.right;
|
||||
};
|
||||
mark(d, false);
|
||||
node.right.walk(tw);
|
||||
mark(d, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (node instanceof AST_Defun) {
|
||||
node.inlined = false;
|
||||
var d = node.name.definition();
|
||||
if (compressor.exposed(d) || safe_to_read(d)) {
|
||||
d.fixed = false;
|
||||
} else {
|
||||
d.fixed = node;
|
||||
d.single_use = ref_once(d);
|
||||
loop_ids[d.id] = in_loop;
|
||||
mark(d, true);
|
||||
}
|
||||
var save_ids = safe_ids;
|
||||
safe_ids = Object.create(null);
|
||||
descend();
|
||||
safe_ids = save_ids;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Function) {
|
||||
node.inlined = false;
|
||||
push();
|
||||
var iife;
|
||||
if (!node.name
|
||||
&& (iife = tw.parent()) instanceof AST_Call
|
||||
&& iife.expression === node) {
|
||||
// Virtually turn IIFE parameters into variable definitions:
|
||||
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
|
||||
// So existing transformation rules can work on them.
|
||||
node.argnames.forEach(function(arg, i) {
|
||||
var d = arg.definition();
|
||||
if (!node.uses_arguments && d.fixed === undefined) {
|
||||
d.fixed = function() {
|
||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||
};
|
||||
loop_ids[d.id] = in_loop;
|
||||
mark(d, true);
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
descend();
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Accessor) {
|
||||
push();
|
||||
descend();
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Binary && lazy_op(node.operator)) {
|
||||
node.left.walk(tw);
|
||||
push();
|
||||
node.right.walk(tw);
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Conditional) {
|
||||
node.condition.walk(tw);
|
||||
push();
|
||||
node.consequent.walk(tw);
|
||||
pop();
|
||||
push();
|
||||
node.alternative.walk(tw);
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_If) {
|
||||
node.condition.walk(tw);
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
if (node.alternative) {
|
||||
push();
|
||||
node.alternative.walk(tw);
|
||||
pop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Do) {
|
||||
var saved_loop = in_loop;
|
||||
in_loop = node;
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
node.condition.walk(tw);
|
||||
pop();
|
||||
in_loop = saved_loop;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_While) {
|
||||
var saved_loop = in_loop;
|
||||
in_loop = node;
|
||||
push();
|
||||
node.condition.walk(tw);
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
in_loop = saved_loop;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_LabeledStatement) {
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_For) {
|
||||
if (node.init) node.init.walk(tw);
|
||||
var saved_loop = in_loop;
|
||||
in_loop = node;
|
||||
if (node.condition) {
|
||||
push();
|
||||
node.condition.walk(tw);
|
||||
pop();
|
||||
}
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
if (node.step) {
|
||||
push();
|
||||
node.step.walk(tw);
|
||||
pop();
|
||||
}
|
||||
in_loop = saved_loop;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_ForIn) {
|
||||
node.init.walk(suppressor);
|
||||
node.object.walk(tw);
|
||||
var saved_loop = in_loop;
|
||||
in_loop = node;
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
in_loop = saved_loop;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Try) {
|
||||
push();
|
||||
walk_body(node, tw);
|
||||
pop();
|
||||
if (node.bcatch) {
|
||||
push();
|
||||
node.bcatch.walk(tw);
|
||||
pop();
|
||||
}
|
||||
if (node.bfinally) node.bfinally.walk(tw);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SwitchBranch) {
|
||||
push();
|
||||
descend();
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.walk(tw);
|
||||
(function(def){
|
||||
def(AST_Node, noop);
|
||||
|
||||
function mark(def, safe) {
|
||||
safe_ids[def.id] = safe;
|
||||
}
|
||||
|
||||
function safe_to_read(def) {
|
||||
if (safe_ids[def.id]) {
|
||||
if (def.fixed == null) {
|
||||
var orig = def.orig[0];
|
||||
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
|
||||
def.fixed = make_node(AST_Undefined, orig);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return def.fixed instanceof AST_Defun;
|
||||
}
|
||||
|
||||
function safe_to_assign(def, value) {
|
||||
if (!HOP(safe_ids, def.id)) return false;
|
||||
if (!safe_to_read(def)) return false;
|
||||
if (def.fixed === false) return false;
|
||||
if (def.fixed != null && (!value || def.references.length > 0)) return false;
|
||||
return all(def.orig, function(sym) {
|
||||
return !(sym instanceof AST_SymbolDefun
|
||||
|| sym instanceof AST_SymbolLambda);
|
||||
});
|
||||
}
|
||||
|
||||
function push() {
|
||||
safe_ids = Object.create(safe_ids);
|
||||
}
|
||||
|
||||
function pop() {
|
||||
safe_ids = Object.getPrototypeOf(safe_ids);
|
||||
}
|
||||
|
||||
function reset_def(def) {
|
||||
function reset_def(compressor, def) {
|
||||
def.direct_access = false;
|
||||
def.escaped = false;
|
||||
if (def.scope.uses_eval || def.scope.uses_with) {
|
||||
@@ -608,12 +324,53 @@ merge(Compressor.prototype, {
|
||||
def.single_use = undefined;
|
||||
}
|
||||
|
||||
function ref_once(def) {
|
||||
return unused
|
||||
function reset_variables(compressor, node) {
|
||||
node.variables.each(function(def) {
|
||||
reset_def(compressor, def);
|
||||
});
|
||||
}
|
||||
|
||||
function push(tw) {
|
||||
tw.safe_ids = Object.create(tw.safe_ids);
|
||||
}
|
||||
|
||||
function pop(tw) {
|
||||
tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
|
||||
}
|
||||
|
||||
function mark(tw, def, safe) {
|
||||
tw.safe_ids[def.id] = safe;
|
||||
}
|
||||
|
||||
function safe_to_read(tw, def) {
|
||||
if (tw.safe_ids[def.id]) {
|
||||
if (def.fixed == null) {
|
||||
var orig = def.orig[0];
|
||||
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
|
||||
def.fixed = make_node(AST_Undefined, orig);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return def.fixed instanceof AST_Defun;
|
||||
}
|
||||
|
||||
function safe_to_assign(tw, def, value) {
|
||||
if (!HOP(tw.safe_ids, def.id)) return false;
|
||||
if (!safe_to_read(tw, def)) return false;
|
||||
if (def.fixed === false) return false;
|
||||
if (def.fixed != null && (!value || def.references.length > 0)) return false;
|
||||
return all(def.orig, function(sym) {
|
||||
return !(sym instanceof AST_SymbolDefun
|
||||
|| sym instanceof AST_SymbolLambda);
|
||||
});
|
||||
}
|
||||
|
||||
function ref_once(tw, compressor, def) {
|
||||
return compressor.option("unused")
|
||||
&& !def.scope.uses_eval
|
||||
&& !def.scope.uses_with
|
||||
&& def.references.length == 1
|
||||
&& loop_ids[def.id] === in_loop;
|
||||
&& tw.loop_ids[def.id] === tw.in_loop;
|
||||
}
|
||||
|
||||
function is_immutable(value) {
|
||||
@@ -642,7 +399,7 @@ merge(Compressor.prototype, {
|
||||
return value instanceof AST_SymbolRef && value.fixed_value() || value;
|
||||
}
|
||||
|
||||
function is_modified(node, value, level, immutable) {
|
||||
function is_modified(tw, node, value, level, immutable) {
|
||||
var parent = tw.parent(level);
|
||||
if (is_lhs(node, parent)
|
||||
|| !immutable
|
||||
@@ -652,16 +409,16 @@ merge(Compressor.prototype, {
|
||||
|| !(parent instanceof AST_New) && value.contains_this())) {
|
||||
return true;
|
||||
} else if (parent instanceof AST_Array) {
|
||||
return is_modified(parent, parent, level + 1);
|
||||
return is_modified(tw, parent, parent, level + 1);
|
||||
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
|
||||
var obj = tw.parent(level + 1);
|
||||
return is_modified(obj, obj, level + 2);
|
||||
return is_modified(tw, obj, obj, level + 2);
|
||||
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||
return !immutable && is_modified(parent, read_property(value, parent.property), level + 1);
|
||||
return !immutable && is_modified(tw, parent, read_property(value, parent.property), level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function mark_escaped(d, scope, node, value, level) {
|
||||
function mark_escaped(tw, d, scope, node, value, level) {
|
||||
var parent = tw.parent(level);
|
||||
if (value) {
|
||||
if (value.is_constant()) return;
|
||||
@@ -677,17 +434,278 @@ merge(Compressor.prototype, {
|
||||
|| 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(d, scope, parent, parent, level + 1);
|
||||
mark_escaped(tw, d, scope, parent, parent, level + 1);
|
||||
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
|
||||
var obj = tw.parent(level + 1);
|
||||
mark_escaped(d, scope, obj, obj, level + 2);
|
||||
mark_escaped(tw, d, scope, obj, obj, level + 2);
|
||||
} else if (parent instanceof AST_PropAccess && node === parent.expression) {
|
||||
value = read_property(value, parent.property);
|
||||
mark_escaped(d, scope, parent, value, level + 1);
|
||||
mark_escaped(tw, d, scope, parent, value, level + 1);
|
||||
if (value) return;
|
||||
}
|
||||
if (level == 0) d.direct_access = true;
|
||||
}
|
||||
|
||||
var suppressor = new TreeWalker(function(node) {
|
||||
if (!(node instanceof AST_Symbol)) return;
|
||||
var d = node.definition();
|
||||
if (!d) return;
|
||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||
d.fixed = false;
|
||||
});
|
||||
def(AST_Accessor, function(tw, descend) {
|
||||
push(tw);
|
||||
descend();
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
def(AST_Assign, function(tw) {
|
||||
var node = this;
|
||||
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
|
||||
var d = node.left.definition();
|
||||
if (safe_to_assign(tw, d, node.right)
|
||||
|| d.fixed === undefined && all(d.orig, function(sym) {
|
||||
return sym instanceof AST_SymbolVar;
|
||||
})) {
|
||||
d.references.push(node.left);
|
||||
d.fixed = function() {
|
||||
return node.right;
|
||||
};
|
||||
mark(tw, d, false);
|
||||
node.right.walk(tw);
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
def(AST_Binary, function(tw) {
|
||||
if (!lazy_op(this.operator)) return;
|
||||
this.left.walk(tw);
|
||||
push(tw);
|
||||
this.right.walk(tw);
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
def(AST_Conditional, function(tw) {
|
||||
this.condition.walk(tw);
|
||||
push(tw);
|
||||
this.consequent.walk(tw);
|
||||
pop(tw);
|
||||
push(tw);
|
||||
this.alternative.walk(tw);
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
def(AST_Defun, function(tw, descend, compressor) {
|
||||
reset_variables(compressor, this);
|
||||
this.inlined = false;
|
||||
var d = this.name.definition();
|
||||
if (compressor.exposed(d) || safe_to_read(tw, d)) {
|
||||
d.fixed = false;
|
||||
} else {
|
||||
d.fixed = this;
|
||||
d.single_use = ref_once(tw, compressor, d);
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, true);
|
||||
}
|
||||
var save_ids = tw.safe_ids;
|
||||
tw.safe_ids = Object.create(null);
|
||||
descend();
|
||||
tw.safe_ids = save_ids;
|
||||
return true;
|
||||
});
|
||||
def(AST_Do, function(tw) {
|
||||
var saved_loop = tw.in_loop;
|
||||
tw.in_loop = this;
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
this.condition.walk(tw);
|
||||
pop(tw);
|
||||
tw.in_loop = saved_loop;
|
||||
return true;
|
||||
});
|
||||
def(AST_For, function(tw) {
|
||||
if (this.init) this.init.walk(tw);
|
||||
var saved_loop = tw.in_loop;
|
||||
tw.in_loop = this;
|
||||
if (this.condition) {
|
||||
push(tw);
|
||||
this.condition.walk(tw);
|
||||
pop(tw);
|
||||
}
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
pop(tw);
|
||||
if (this.step) {
|
||||
push(tw);
|
||||
this.step.walk(tw);
|
||||
pop(tw);
|
||||
}
|
||||
tw.in_loop = saved_loop;
|
||||
return true;
|
||||
});
|
||||
def(AST_ForIn, function(tw) {
|
||||
this.init.walk(suppressor);
|
||||
this.object.walk(tw);
|
||||
var saved_loop = tw.in_loop;
|
||||
tw.in_loop = this;
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
pop(tw);
|
||||
tw.in_loop = saved_loop;
|
||||
return true;
|
||||
});
|
||||
def(AST_Function, function(tw, descend, compressor) {
|
||||
var node = this;
|
||||
reset_variables(compressor, node);
|
||||
node.inlined = false;
|
||||
push(tw);
|
||||
var iife;
|
||||
if (!node.name
|
||||
&& (iife = tw.parent()) instanceof AST_Call
|
||||
&& iife.expression === node) {
|
||||
// Virtually turn IIFE parameters into variable definitions:
|
||||
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
|
||||
// So existing transformation rules can work on them.
|
||||
node.argnames.forEach(function(arg, i) {
|
||||
var d = arg.definition();
|
||||
if (!node.uses_arguments && d.fixed === undefined) {
|
||||
d.fixed = function() {
|
||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||
};
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, true);
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
descend();
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
def(AST_If, function(tw) {
|
||||
this.condition.walk(tw);
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
pop(tw);
|
||||
if (this.alternative) {
|
||||
push(tw);
|
||||
this.alternative.walk(tw);
|
||||
pop(tw);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
def(AST_LabeledStatement, function(tw) {
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
def(AST_SwitchBranch, function(tw, descend) {
|
||||
push(tw);
|
||||
descend();
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
def(AST_SymbolCatch, function() {
|
||||
this.definition().fixed = false;
|
||||
});
|
||||
def(AST_SymbolRef, function(tw, descend, compressor) {
|
||||
var d = this.definition();
|
||||
d.references.push(this);
|
||||
if (d.references.length == 1
|
||||
&& !d.fixed
|
||||
&& d.orig[0] instanceof AST_SymbolDefun) {
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
}
|
||||
var value;
|
||||
if (d.fixed === undefined || !safe_to_read(tw, d) || d.single_use == "m") {
|
||||
d.fixed = false;
|
||||
} else if (d.fixed) {
|
||||
value = this.fixed_value();
|
||||
if (value && ref_once(tw, compressor, d)) {
|
||||
d.single_use = value instanceof AST_Lambda
|
||||
|| d.scope === this.scope && value.is_constant_expression();
|
||||
} else {
|
||||
d.single_use = false;
|
||||
}
|
||||
if (is_modified(tw, this, value, 0, is_immutable(value))) {
|
||||
if (d.single_use) {
|
||||
d.single_use = "m";
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
mark_escaped(tw, d, this.scope, this, value, 0);
|
||||
});
|
||||
def(AST_Toplevel, function(tw, descend, compressor) {
|
||||
this.globals.each(function(def) {
|
||||
reset_def(compressor, def);
|
||||
});
|
||||
reset_variables(compressor, this);
|
||||
});
|
||||
def(AST_Try, function(tw) {
|
||||
push(tw);
|
||||
walk_body(this, tw);
|
||||
pop(tw);
|
||||
if (this.bcatch) {
|
||||
push(tw);
|
||||
this.bcatch.walk(tw);
|
||||
pop(tw);
|
||||
}
|
||||
if (this.bfinally) this.bfinally.walk(tw);
|
||||
return true;
|
||||
});
|
||||
def(AST_VarDef, function(tw, descend) {
|
||||
var node = this;
|
||||
var d = node.name.definition();
|
||||
if (d.fixed === undefined || safe_to_assign(tw, d, node.value)) {
|
||||
if (node.value) {
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
};
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, false);
|
||||
descend();
|
||||
} else {
|
||||
d.fixed = null;
|
||||
}
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
} else if (node.value) {
|
||||
d.fixed = false;
|
||||
}
|
||||
});
|
||||
def(AST_While, function(tw) {
|
||||
var saved_loop = tw.in_loop;
|
||||
tw.in_loop = this;
|
||||
push(tw);
|
||||
this.condition.walk(tw);
|
||||
this.body.walk(tw);
|
||||
pop(tw);
|
||||
tw.in_loop = saved_loop;
|
||||
return true;
|
||||
});
|
||||
})(function(node, func){
|
||||
node.DEFMETHOD("reduce_vars", func);
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
|
||||
var reduce_vars = compressor.option("reduce_vars");
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
if (reduce_vars) return node.reduce_vars(tw, descend, compressor);
|
||||
});
|
||||
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
||||
// properly assigned before use:
|
||||
// - `push()` & `pop()` when visiting conditional branches
|
||||
// - backup & restore via `save_ids` when visiting out-of-order sections
|
||||
tw.safe_ids = Object.create(null);
|
||||
tw.in_loop = null;
|
||||
tw.loop_ids = Object.create(null);
|
||||
this.walk(tw);
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("fixed_value", function() {
|
||||
|
||||
Reference in New Issue
Block a user