improve compress (#3814)
- avoid identifier overflow through consecutive API calls - simplify `reduce_vars` - enhance `unsafe` `evaluate`
This commit is contained in:
@@ -460,7 +460,7 @@ merge(Compressor.prototype, {
|
|||||||
return def.fixed instanceof AST_Defun;
|
return def.fixed instanceof AST_Defun;
|
||||||
}
|
}
|
||||||
|
|
||||||
function safe_to_assign(tw, def, scope, value) {
|
function safe_to_assign(tw, def, value) {
|
||||||
if (def.fixed === undefined) return true;
|
if (def.fixed === undefined) return true;
|
||||||
if (def.fixed === null && def.safe_ids) {
|
if (def.fixed === null && def.safe_ids) {
|
||||||
def.safe_ids[def.id] = false;
|
def.safe_ids[def.id] = false;
|
||||||
@@ -471,11 +471,8 @@ merge(Compressor.prototype, {
|
|||||||
if (!safe_to_read(tw, def)) return false;
|
if (!safe_to_read(tw, def)) return false;
|
||||||
if (def.fixed === false) return false;
|
if (def.fixed === false) return false;
|
||||||
if (def.fixed != null && (!value || def.references.length > def.assignments)) return false;
|
if (def.fixed != null && (!value || def.references.length > def.assignments)) return false;
|
||||||
if (def.fixed instanceof AST_Defun) {
|
|
||||||
return value instanceof AST_Node && def.fixed.parent_scope === scope;
|
|
||||||
}
|
|
||||||
return all(def.orig, function(sym) {
|
return all(def.orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolDefun || sym instanceof AST_SymbolLambda);
|
return !(sym instanceof AST_SymbolLambda);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,7 +554,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (sym.fixed) delete sym.fixed;
|
if (sym.fixed) delete sym.fixed;
|
||||||
var d = sym.definition();
|
var d = sym.definition();
|
||||||
var safe = safe_to_assign(tw, d, sym.scope, node.right);
|
var safe = safe_to_assign(tw, d, node.right);
|
||||||
d.assignments++;
|
d.assignments++;
|
||||||
var fixed = d.fixed;
|
var fixed = d.fixed;
|
||||||
if (!fixed && node.operator != "=") return;
|
if (!fixed && node.operator != "=") return;
|
||||||
@@ -820,7 +817,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (exp.fixed) delete exp.fixed;
|
if (exp.fixed) delete exp.fixed;
|
||||||
var d = exp.definition();
|
var d = exp.definition();
|
||||||
var safe = safe_to_assign(tw, d, exp.scope, true);
|
var safe = safe_to_assign(tw, d, true);
|
||||||
d.assignments++;
|
d.assignments++;
|
||||||
var fixed = d.fixed;
|
var fixed = d.fixed;
|
||||||
if (!fixed) return;
|
if (!fixed) return;
|
||||||
@@ -846,7 +843,7 @@ merge(Compressor.prototype, {
|
|||||||
var node = this;
|
var node = this;
|
||||||
var d = node.name.definition();
|
var d = node.name.definition();
|
||||||
if (node.value) {
|
if (node.value) {
|
||||||
if (safe_to_assign(tw, d, node.name.scope, node.value)) {
|
if (safe_to_assign(tw, d, node.value)) {
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return node.value;
|
return node.value;
|
||||||
};
|
};
|
||||||
@@ -3195,7 +3192,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Statement, function() {
|
def(AST_Statement, function() {
|
||||||
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
||||||
});
|
});
|
||||||
def(AST_Lambda, return_this);
|
def(AST_Accessor, return_this);
|
||||||
def(AST_Node, return_this);
|
def(AST_Node, return_this);
|
||||||
def(AST_Constant, function() {
|
def(AST_Constant, function() {
|
||||||
return this.value;
|
return this.value;
|
||||||
@@ -3213,7 +3210,7 @@ merge(Compressor.prototype, {
|
|||||||
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
return value === node ? this : value;
|
return value === node ? this : value;
|
||||||
});
|
});
|
||||||
def(AST_Function, function(compressor) {
|
def(AST_Lambda, function(compressor) {
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var fn = function() {};
|
var fn = function() {};
|
||||||
fn.node = this;
|
fn.node = this;
|
||||||
|
|||||||
29
lib/scope.js
29
lib/scope.js
@@ -43,23 +43,21 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function SymbolDef(scope, orig, init) {
|
function SymbolDef(id, scope, orig, init) {
|
||||||
|
this.eliminated = 0;
|
||||||
|
this.global = false;
|
||||||
|
this.id = id;
|
||||||
|
this.init = init;
|
||||||
|
this.lambda = orig instanceof AST_SymbolLambda;
|
||||||
|
this.mangled_name = null;
|
||||||
this.name = orig.name;
|
this.name = orig.name;
|
||||||
this.orig = [ orig ];
|
this.orig = [ orig ];
|
||||||
this.init = init;
|
|
||||||
this.eliminated = 0;
|
|
||||||
this.scope = scope;
|
|
||||||
this.references = [];
|
this.references = [];
|
||||||
this.replaced = 0;
|
this.replaced = 0;
|
||||||
this.global = false;
|
this.scope = scope;
|
||||||
this.mangled_name = null;
|
|
||||||
this.undeclared = false;
|
this.undeclared = false;
|
||||||
this.id = SymbolDef.next_id++;
|
|
||||||
this.lambda = orig instanceof AST_SymbolLambda;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolDef.next_id = 1;
|
|
||||||
|
|
||||||
SymbolDef.prototype = {
|
SymbolDef.prototype = {
|
||||||
unmangleable: function(options) {
|
unmangleable: function(options) {
|
||||||
return this.global && !options.toplevel
|
return this.global && !options.toplevel
|
||||||
@@ -151,6 +149,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
scope.def_variable(node).defun = defun;
|
scope.def_variable(node).defun = defun;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
self.next_def_id = 0;
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
// pass 2: find back references and eval
|
// pass 2: find back references and eval
|
||||||
@@ -240,12 +239,18 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Scope.DEFMETHOD("make_def", function(orig, init) {
|
||||||
|
var top = this;
|
||||||
|
while (top.parent_scope) top = top.parent_scope;
|
||||||
|
return new SymbolDef(++top.next_def_id, this, orig, init);
|
||||||
|
});
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||||
var globals = this.globals, name = node.name;
|
var globals = this.globals, name = node.name;
|
||||||
if (globals.has(name)) {
|
if (globals.has(name)) {
|
||||||
return globals.get(name);
|
return globals.get(name);
|
||||||
} else {
|
} else {
|
||||||
var g = new SymbolDef(this, node);
|
var g = this.make_def(node);
|
||||||
g.undeclared = true;
|
g.undeclared = true;
|
||||||
g.global = true;
|
g.global = true;
|
||||||
globals.set(name, g);
|
globals.set(name, g);
|
||||||
@@ -310,7 +315,7 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
|||||||
def.orig.push(symbol);
|
def.orig.push(symbol);
|
||||||
if (def.init instanceof AST_Function) def.init = init;
|
if (def.init instanceof AST_Function) def.init = init;
|
||||||
} else {
|
} else {
|
||||||
def = new SymbolDef(this, symbol, init);
|
def = this.make_def(symbol, init);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
def.global = !this.parent_scope;
|
def.global = !this.parent_scope;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,6 +223,25 @@ unsafe_evaluate: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_defun: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
function f() {}
|
||||||
|
return ++f;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(NaN);
|
||||||
|
}
|
||||||
|
expect_stdout: "NaN"
|
||||||
|
}
|
||||||
|
|
||||||
unsafe_evaluate_side_effect_free_1: {
|
unsafe_evaluate_side_effect_free_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user