add option to mangle names even if eval/with is in use
(for more fair comparison to Closure compiler)
This commit is contained in:
@@ -252,7 +252,7 @@ if (SCOPE_IS_NEEDED) {
|
|||||||
time_it("scope", function(){
|
time_it("scope", function(){
|
||||||
TOPLEVEL.figure_out_scope();
|
TOPLEVEL.figure_out_scope();
|
||||||
if (MANGLE) {
|
if (MANGLE) {
|
||||||
TOPLEVEL.compute_char_frequency();
|
TOPLEVEL.compute_char_frequency(MANGLE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
45
lib/scope.js
45
lib/scope.js
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function SymbolDef(scope, orig) {
|
function SymbolDef(scope, index, orig) {
|
||||||
this.name = orig.name;
|
this.name = orig.name;
|
||||||
this.orig = [ orig ];
|
this.orig = [ orig ];
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
@@ -52,15 +52,18 @@ function SymbolDef(scope, orig) {
|
|||||||
this.mangled_name = null;
|
this.mangled_name = null;
|
||||||
this.undeclared = false;
|
this.undeclared = false;
|
||||||
this.constant = false;
|
this.constant = false;
|
||||||
|
this.index = index;
|
||||||
};
|
};
|
||||||
|
|
||||||
SymbolDef.prototype = {
|
SymbolDef.prototype = {
|
||||||
unmangleable: function() {
|
unmangleable: function(options) {
|
||||||
return this.global || this.undeclared || this.scope.uses_eval || this.scope.uses_with;
|
return this.global
|
||||||
|
|| this.undeclared
|
||||||
|
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with));
|
||||||
},
|
},
|
||||||
mangle: function() {
|
mangle: function(options) {
|
||||||
if (!this.mangled_name && !this.unmangleable())
|
if (!this.mangled_name && !this.unmangleable(options))
|
||||||
this.mangled_name = this.scope.next_mangled();
|
this.mangled_name = this.scope.next_mangled(options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,13 +79,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
var self = this;
|
var self = this;
|
||||||
var scope = self.parent_scope = null;
|
var scope = self.parent_scope = null;
|
||||||
var labels = new Dictionary();
|
var labels = new Dictionary();
|
||||||
|
var nesting = 0;
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
node.init_scope_vars();
|
node.init_scope_vars(nesting);
|
||||||
var save_scope = node.parent_scope = scope;
|
var save_scope = node.parent_scope = scope;
|
||||||
|
++nesting;
|
||||||
scope = node;
|
scope = node;
|
||||||
descend();
|
descend();
|
||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
|
--nesting;
|
||||||
return true; // don't descend again in TreeWalker
|
return true; // don't descend again in TreeWalker
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Directive) {
|
if (node instanceof AST_Directive) {
|
||||||
@@ -185,7 +191,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
if (globals.has(name)) {
|
if (globals.has(name)) {
|
||||||
g = globals.get(name);
|
g = globals.get(name);
|
||||||
} else {
|
} else {
|
||||||
g = new SymbolDef(self, node);
|
g = new SymbolDef(self, globals.size(), node);
|
||||||
g.undeclared = true;
|
g.undeclared = true;
|
||||||
globals.set(name, g);
|
globals.set(name, g);
|
||||||
}
|
}
|
||||||
@@ -207,7 +213,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("init_scope_vars", function(){
|
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
||||||
this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
|
this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
|
||||||
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||||
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||||
@@ -216,6 +222,7 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(){
|
|||||||
this.parent_scope = null; // the parent scope
|
this.parent_scope = null; // the parent scope
|
||||||
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
|
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||||
this.cname = -1; // the current index for mangling functions/variables
|
this.cname = -1; // the current index for mangling functions/variables
|
||||||
|
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("strict", function(){
|
AST_Scope.DEFMETHOD("strict", function(){
|
||||||
@@ -223,7 +230,7 @@ AST_Scope.DEFMETHOD("strict", function(){
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
||||||
AST_Scope.prototype.init_scope_vars.call(this);
|
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||||
this.uses_arguments = false;
|
this.uses_arguments = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -236,6 +243,7 @@ AST_SymbolRef.DEFMETHOD("reference", function() {
|
|||||||
if (s === def.scope) break;
|
if (s === def.scope) break;
|
||||||
s = s.parent_scope;
|
s = s.parent_scope;
|
||||||
}
|
}
|
||||||
|
this.frame = this.scope.nesting - def.scope.nesting;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_SymbolDeclaration.DEFMETHOD("init_scope_vars", function(){
|
AST_SymbolDeclaration.DEFMETHOD("init_scope_vars", function(){
|
||||||
@@ -268,7 +276,7 @@ AST_Scope.DEFMETHOD("def_function", function(symbol){
|
|||||||
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
||||||
var def;
|
var def;
|
||||||
if (!this.variables.has(symbol.name)) {
|
if (!this.variables.has(symbol.name)) {
|
||||||
def = new SymbolDef(this, symbol);
|
def = new SymbolDef(this, this.variables.size(), symbol);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
def.global = !this.parent_scope;
|
def.global = !this.parent_scope;
|
||||||
} else {
|
} else {
|
||||||
@@ -278,7 +286,7 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
|||||||
return symbol.thedef = def;
|
return symbol.thedef = def;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("next_mangled", function(){
|
AST_Scope.DEFMETHOD("next_mangled", function(options){
|
||||||
var ext = this.enclosed, n = ext.length;
|
var ext = this.enclosed, n = ext.length;
|
||||||
out: while (true) {
|
out: while (true) {
|
||||||
var m = base54(++this.cname);
|
var m = base54(++this.cname);
|
||||||
@@ -288,7 +296,7 @@ AST_Scope.DEFMETHOD("next_mangled", function(){
|
|||||||
// inner scopes.
|
// inner scopes.
|
||||||
for (var i = n; --i >= 0;) {
|
for (var i = n; --i >= 0;) {
|
||||||
var sym = ext[i];
|
var sym = ext[i];
|
||||||
var name = sym.mangled_name || (sym.unmangleable() && sym.name);
|
var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
|
||||||
if (m == name) continue out;
|
if (m == name) continue out;
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
@@ -300,8 +308,8 @@ AST_Scope.DEFMETHOD("references", function(sym){
|
|||||||
return this.enclosed.indexOf(sym) < 0 ? null : sym;
|
return this.enclosed.indexOf(sym) < 0 ? null : sym;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("unmangleable", function(){
|
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
||||||
return this.definition().unmangleable();
|
return this.definition().unmangleable(options);
|
||||||
});
|
});
|
||||||
|
|
||||||
// labels are always mangleable
|
// labels are always mangleable
|
||||||
@@ -336,7 +344,8 @@ AST_Symbol.DEFMETHOD("global", function(){
|
|||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
except : []
|
except : [],
|
||||||
|
eval : false,
|
||||||
});
|
});
|
||||||
// We only need to mangle declaration nodes. Special logic wired
|
// We only need to mangle declaration nodes. Special logic wired
|
||||||
// into the code generator will display the mangled name if it's
|
// into the code generator will display the mangled name if it's
|
||||||
@@ -375,7 +384,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
to_mangle.forEach(function(def){ def.mangle(options) });
|
to_mangle.forEach(function(def){ def.mangle(options) });
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(){
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
||||||
var tw = new TreeWalker(function(node){
|
var tw = new TreeWalker(function(node){
|
||||||
if (node instanceof AST_Constant)
|
if (node instanceof AST_Constant)
|
||||||
base54.consider(node.print_to_string());
|
base54.consider(node.print_to_string());
|
||||||
@@ -433,7 +442,7 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(){
|
|||||||
base54.consider("catch");
|
base54.consider("catch");
|
||||||
else if (node instanceof AST_Finally)
|
else if (node instanceof AST_Finally)
|
||||||
base54.consider("finally");
|
base54.consider("finally");
|
||||||
else if (node instanceof AST_Symbol && node.unmangleable())
|
else if (node instanceof AST_Symbol && node.unmangleable(options))
|
||||||
base54.consider(node.name);
|
base54.consider(node.name);
|
||||||
else if (node instanceof AST_Unary || node instanceof AST_Binary)
|
else if (node instanceof AST_Unary || node instanceof AST_Binary)
|
||||||
base54.consider(node.operator);
|
base54.consider(node.operator);
|
||||||
|
|||||||
18
lib/utils.js
18
lib/utils.js
@@ -247,16 +247,30 @@ function makePredicate(words) {
|
|||||||
|
|
||||||
function Dictionary() {
|
function Dictionary() {
|
||||||
this._values = Object.create(null);
|
this._values = Object.create(null);
|
||||||
|
this._size = 0;
|
||||||
};
|
};
|
||||||
Dictionary.prototype = {
|
Dictionary.prototype = {
|
||||||
set: function(key, val) { return this._values["$" + key] = val, this },
|
set: function(key, val) {
|
||||||
|
if (!this.has(key)) ++this._size;
|
||||||
|
this._values["$" + key] = val;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
get: function(key) { return this._values["$" + key] },
|
get: function(key) { return this._values["$" + key] },
|
||||||
del: function(key) { return delete this._values["$" + key], this },
|
del: function(key) {
|
||||||
|
if (this.has(key)) {
|
||||||
|
--this._size;
|
||||||
|
delete this._values["$" + key];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
has: function(key) { return ("$" + key) in this._values },
|
has: function(key) { return ("$" + key) in this._values },
|
||||||
each: function(f) {
|
each: function(f) {
|
||||||
for (var i in this._values)
|
for (var i in this._values)
|
||||||
f(this._values[i], i.substr(1));
|
f(this._values[i], i.substr(1));
|
||||||
},
|
},
|
||||||
|
size: function() {
|
||||||
|
return this._size;
|
||||||
|
},
|
||||||
map: function(f) {
|
map: function(f) {
|
||||||
var ret = [];
|
var ret = [];
|
||||||
for (var i in this._values)
|
for (var i in this._values)
|
||||||
|
|||||||
Reference in New Issue
Block a user