aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/uglifyjs22
-rw-r--r--lib/scope.js45
-rw-r--r--lib/utils.js18
3 files changed, 44 insertions, 21 deletions
diff --git a/bin/uglifyjs2 b/bin/uglifyjs2
index aadda7cf..1706629c 100755
--- a/bin/uglifyjs2
+++ b/bin/uglifyjs2
@@ -252,7 +252,7 @@ if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
TOPLEVEL.figure_out_scope();
if (MANGLE) {
- TOPLEVEL.compute_char_frequency();
+ TOPLEVEL.compute_char_frequency(MANGLE);
}
});
}
diff --git a/lib/scope.js b/lib/scope.js
index fcd9de18..27cd5259 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -43,7 +43,7 @@
"use strict";
-function SymbolDef(scope, orig) {
+function SymbolDef(scope, index, orig) {
this.name = orig.name;
this.orig = [ orig ];
this.scope = scope;
@@ -52,15 +52,18 @@ function SymbolDef(scope, orig) {
this.mangled_name = null;
this.undeclared = false;
this.constant = false;
+ this.index = index;
};
SymbolDef.prototype = {
- unmangleable: function() {
- return this.global || this.undeclared || this.scope.uses_eval || this.scope.uses_with;
+ unmangleable: function(options) {
+ return this.global
+ || this.undeclared
+ || (!options.eval && (this.scope.uses_eval || this.scope.uses_with));
},
- mangle: function() {
- if (!this.mangled_name && !this.unmangleable())
- this.mangled_name = this.scope.next_mangled();
+ mangle: function(options) {
+ if (!this.mangled_name && !this.unmangleable(options))
+ this.mangled_name = this.scope.next_mangled(options);
}
};
@@ -76,13 +79,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
var self = this;
var scope = self.parent_scope = null;
var labels = new Dictionary();
+ var nesting = 0;
var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_Scope) {
- node.init_scope_vars();
+ node.init_scope_vars(nesting);
var save_scope = node.parent_scope = scope;
+ ++nesting;
scope = node;
descend();
scope = save_scope;
+ --nesting;
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_Directive) {
@@ -185,7 +191,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
if (globals.has(name)) {
g = globals.get(name);
} else {
- g = new SymbolDef(self, node);
+ g = new SymbolDef(self, globals.size(), node);
g.undeclared = true;
globals.set(name, g);
}
@@ -207,7 +213,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
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.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)
@@ -216,6 +222,7 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(){
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.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(){
@@ -223,7 +230,7 @@ AST_Scope.DEFMETHOD("strict", 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;
});
@@ -236,6 +243,7 @@ AST_SymbolRef.DEFMETHOD("reference", function() {
if (s === def.scope) break;
s = s.parent_scope;
}
+ this.frame = this.scope.nesting - def.scope.nesting;
});
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){
var def;
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);
def.global = !this.parent_scope;
} else {
@@ -278,7 +286,7 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol){
return symbol.thedef = def;
});
-AST_Scope.DEFMETHOD("next_mangled", function(){
+AST_Scope.DEFMETHOD("next_mangled", function(options){
var ext = this.enclosed, n = ext.length;
out: while (true) {
var m = base54(++this.cname);
@@ -288,7 +296,7 @@ AST_Scope.DEFMETHOD("next_mangled", function(){
// inner scopes.
for (var i = n; --i >= 0;) {
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;
}
return m;
@@ -300,8 +308,8 @@ AST_Scope.DEFMETHOD("references", function(sym){
return this.enclosed.indexOf(sym) < 0 ? null : sym;
});
-AST_Symbol.DEFMETHOD("unmangleable", function(){
- return this.definition().unmangleable();
+AST_Symbol.DEFMETHOD("unmangleable", function(options){
+ return this.definition().unmangleable(options);
});
// labels are always mangleable
@@ -336,7 +344,8 @@ AST_Symbol.DEFMETHOD("global", function(){
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = defaults(options, {
- except : []
+ except : [],
+ eval : false,
});
// We only need to mangle declaration nodes. Special logic wired
// 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) });
});
-AST_Toplevel.DEFMETHOD("compute_char_frequency", function(){
+AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
var tw = new TreeWalker(function(node){
if (node instanceof AST_Constant)
base54.consider(node.print_to_string());
@@ -433,7 +442,7 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(){
base54.consider("catch");
else if (node instanceof AST_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);
else if (node instanceof AST_Unary || node instanceof AST_Binary)
base54.consider(node.operator);
diff --git a/lib/utils.js b/lib/utils.js
index 27b79753..15eed9ba 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -247,16 +247,30 @@ function makePredicate(words) {
function Dictionary() {
this._values = Object.create(null);
+ this._size = 0;
};
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] },
- 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 },
each: function(f) {
for (var i in this._values)
f(this._values[i], i.substr(1));
},
+ size: function() {
+ return this._size;
+ },
map: function(f) {
var ret = [];
for (var i in this._values)