enforce toplevel on other compress options (#1855)

Respect "funcs" and "vars" properly.

fixes #1850
This commit is contained in:
Alex Lam S.L
2017-04-30 22:52:36 +08:00
committed by GitHub
parent bbb5f2a89c
commit 2cb55b2ad0
2 changed files with 362 additions and 265 deletions

View File

@@ -109,6 +109,14 @@ function Compressor(options, false_by_default) {
return top_retain.indexOf(def.name) >= 0; return top_retain.indexOf(def.name) >= 0;
}; };
} }
var toplevel = this.options["toplevel"];
if (typeof toplevel == "string") {
this.toplevel.funcs = /funcs/.test(toplevel);
this.toplevel.vars = /vars/.test(toplevel);
} else {
this.toplevel = toplevel ? return_true : return_false;
this.toplevel.funcs = this.toplevel.vars = toplevel;
}
var sequences = this.options["sequences"]; var sequences = this.options["sequences"];
this.sequences_limit = sequences == 1 ? 800 : sequences | 0; this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
this.warnings_produced = {}; this.warnings_produced = {};
@@ -117,6 +125,12 @@ function Compressor(options, false_by_default) {
Compressor.prototype = new TreeTransformer; Compressor.prototype = new TreeTransformer;
merge(Compressor.prototype, { merge(Compressor.prototype, {
option: function(key) { return this.options[key] }, option: function(key) { return this.options[key] },
toplevel: function(def) {
for (var i = 0, len = def.orig.length; i < len; i++)
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
return false;
return true;
},
compress: function(node) { compress: function(node) {
if (this.option("expression")) { if (this.option("expression")) {
node.process_expression(true); node.process_expression(true);
@@ -249,7 +263,6 @@ merge(Compressor.prototype, {
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) { AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
var reduce_vars = rescan && compressor.option("reduce_vars"); var reduce_vars = rescan && compressor.option("reduce_vars");
var toplevel = compressor.option("toplevel");
var safe_ids = Object.create(null); var safe_ids = Object.create(null);
var suppressor = new TreeWalker(function(node) { var suppressor = new TreeWalker(function(node) {
if (node instanceof AST_Symbol) { if (node instanceof AST_Symbol) {
@@ -310,7 +323,7 @@ merge(Compressor.prototype, {
} }
if (node instanceof AST_Defun) { if (node instanceof AST_Defun) {
var d = node.name.definition(); var d = node.name.definition();
if (!toplevel && d.global || safe_to_read(d)) { if (d.global && !compressor.toplevel(d) || safe_to_read(d)) {
d.fixed = false; d.fixed = false;
} else { } else {
d.fixed = node; d.fixed = node;
@@ -469,7 +482,7 @@ merge(Compressor.prototype, {
} }
function reset_def(def) { function reset_def(def) {
if (toplevel || !def.global || def.orig[0] instanceof AST_SymbolConst) { if (!def.global || def.orig[0] instanceof AST_SymbolConst || compressor.toplevel(def)) {
def.fixed = undefined; def.fixed = undefined;
} else { } else {
def.fixed = false; def.fixed = false;
@@ -643,7 +656,6 @@ merge(Compressor.prototype, {
// in the statement with the var value and then erase the var definition. // in the statement with the var value and then erase the var definition.
var scope = compressor.find_parent(AST_Scope); var scope = compressor.find_parent(AST_Scope);
var toplevel = compressor.option("toplevel");
var stat_index; var stat_index;
var prev_stat_index; var prev_stat_index;
var def_stat_index; var def_stat_index;
@@ -694,7 +706,8 @@ merge(Compressor.prototype, {
// Only interested in cases with just one reference to the variable. // Only interested in cases with just one reference to the variable.
var def = var_decl.name.definition(); var def = var_decl.name.definition();
if (def.references.length !== 1 if (def.references.length !== 1
|| var_name == "arguments" || (!toplevel && def.global)) { || var_name == "arguments"
|| def.global && !compressor.toplevel(def)) {
side_effects_encountered = true; side_effects_encountered = true;
continue; continue;
} }
@@ -1825,19 +1838,14 @@ merge(Compressor.prototype, {
}); });
AST_Scope.DEFMETHOD("drop_unused", function(compressor){ AST_Scope.DEFMETHOD("drop_unused", function(compressor){
if (!compressor.option("unused")) return;
if (compressor.has_directive("use asm")) return;
var self = this; var self = this;
if (compressor.has_directive("use asm")) return self; if (self.uses_eval || self.uses_with) return;
var toplevel = compressor.option("toplevel"); var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
if (compressor.option("unused") var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
&& (!(self instanceof AST_Toplevel) || toplevel) if (!drop_funcs && !drop_vars) return;
&& !self.uses_eval
&& !self.uses_with) {
var assign_as_unused = !/keep_assign/.test(compressor.option("unused")); var assign_as_unused = !/keep_assign/.test(compressor.option("unused"));
var drop_funcs = /funcs/.test(toplevel);
var drop_vars = /vars/.test(toplevel);
if (!(self instanceof AST_Toplevel) || toplevel == true) {
drop_funcs = drop_vars = true;
}
var in_use = []; var in_use = [];
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
if (self instanceof AST_Toplevel && compressor.top_retain) { if (self instanceof AST_Toplevel && compressor.top_retain) {
@@ -2107,7 +2115,6 @@ merge(Compressor.prototype, {
} }
); );
self.transform(tt); self.transform(tt);
}
}); });
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){ AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
@@ -3683,7 +3690,7 @@ merge(Compressor.prototype, {
} }
var name = d.name.length; var name = d.name.length;
var overhead = 0; var overhead = 0;
if (compressor.option("unused") && (!d.global || compressor.option("toplevel"))) { if (compressor.option("unused") && (!d.global || compressor.toplevel(d))) {
overhead = (name + 2 + value) / d.references.length; overhead = (name + 2 + value) / d.references.length;
} }
d.should_replace = value <= name + overhead ? fn : false; d.should_replace = value <= name + overhead ? fn : false;

View File

@@ -2327,3 +2327,93 @@ iife_assign: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
issue_1850_1: {
options = {
reduce_vars: true,
toplevel: false,
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect_stdout: true
}
issue_1850_2: {
options = {
reduce_vars: true,
toplevel: "funcs",
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
var a = 1;
(function() {
console.log(a, a, a);
})();
}
expect_stdout: true
}
issue_1850_3: {
options = {
reduce_vars: true,
toplevel: "vars",
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect_stdout: true
}
issue_1850_4: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
var a = 1;
(function() {
console.log(a, a, a);
})();
}
expect_stdout: true
}