use a Dictionary object instead of plain object for hashes
to mitigate the `__proto__` issue related to #30
This commit is contained in:
@@ -1026,7 +1026,7 @@ merge(Compressor.prototype, {
|
|||||||
if (hoist_funs || hoist_vars) {
|
if (hoist_funs || hoist_vars) {
|
||||||
var dirs = [];
|
var dirs = [];
|
||||||
var hoisted = [];
|
var hoisted = [];
|
||||||
var vars = {}, vars_found = 0, var_decl = 0;
|
var vars = new Dictionary(), vars_found = 0, var_decl = 0;
|
||||||
// let's count var_decl first, we seem to waste a lot of
|
// let's count var_decl first, we seem to waste a lot of
|
||||||
// space if we hoist `var` when there's only one.
|
// space if we hoist `var` when there's only one.
|
||||||
self.walk(new TreeWalker(function(node){
|
self.walk(new TreeWalker(function(node){
|
||||||
@@ -1051,7 +1051,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Var && hoist_vars) {
|
if (node instanceof AST_Var && hoist_vars) {
|
||||||
node.definitions.forEach(function(def){
|
node.definitions.forEach(function(def){
|
||||||
vars[def.name.name] = def;
|
vars.set(def.name.name, def);
|
||||||
++vars_found;
|
++vars_found;
|
||||||
});
|
});
|
||||||
var seq = node.to_assignments();
|
var seq = node.to_assignments();
|
||||||
@@ -1075,8 +1075,8 @@ merge(Compressor.prototype, {
|
|||||||
);
|
);
|
||||||
self = self.transform(tt);
|
self = self.transform(tt);
|
||||||
if (vars_found > 0) hoisted.unshift(make_node(AST_Var, self, {
|
if (vars_found > 0) hoisted.unshift(make_node(AST_Var, self, {
|
||||||
definitions: Object.keys(vars).map(function(name){
|
definitions: vars.map(function(def){
|
||||||
var def = vars[name].clone();
|
def = def.clone();
|
||||||
def.value = null;
|
def.value = null;
|
||||||
return def;
|
return def;
|
||||||
})
|
})
|
||||||
|
|||||||
38
lib/scope.js
38
lib/scope.js
@@ -75,7 +75,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
// pass 1: setup scope chaining and handle definitions
|
// pass 1: setup scope chaining and handle definitions
|
||||||
var self = this;
|
var self = this;
|
||||||
var scope = self.parent_scope = null;
|
var scope = self.parent_scope = null;
|
||||||
var labels = Object.create(null);
|
var labels = new Dictionary();
|
||||||
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();
|
||||||
@@ -97,11 +97,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_LabeledStatement) {
|
if (node instanceof AST_LabeledStatement) {
|
||||||
var l = node.label;
|
var l = node.label;
|
||||||
if (labels[l.name])
|
if (labels.has(l.name))
|
||||||
throw new Error(string_template("Label {name} defined twice", l));
|
throw new Error(string_template("Label {name} defined twice", l));
|
||||||
labels[l.name] = l;
|
labels.set(l.name, l);
|
||||||
descend();
|
descend();
|
||||||
delete labels[l.name];
|
labels.del(l.name);
|
||||||
return true; // no descend again
|
return true; // no descend again
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolDeclaration) {
|
if (node instanceof AST_SymbolDeclaration) {
|
||||||
@@ -151,7 +151,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
scope.def_variable(node);
|
scope.def_variable(node);
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LabelRef) {
|
if (node instanceof AST_LabelRef) {
|
||||||
var sym = labels[node.name];
|
var sym = labels.get(node.name);
|
||||||
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
|
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
|
||||||
name: node.name,
|
name: node.name,
|
||||||
line: node.start.line,
|
line: node.start.line,
|
||||||
@@ -164,7 +164,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
|
|
||||||
// pass 2: find back references and eval
|
// pass 2: find back references and eval
|
||||||
var func = null;
|
var func = null;
|
||||||
var globals = self.globals = Object.create(null);
|
var globals = self.globals = new Dictionary();
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Lambda) {
|
||||||
var prev_func = func;
|
var prev_func = func;
|
||||||
@@ -182,12 +182,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
var sym = node.scope.find_variable(name);
|
var sym = node.scope.find_variable(name);
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
var g;
|
var g;
|
||||||
if (globals[name]) {
|
if (globals.has(name)) {
|
||||||
g = globals[name];
|
g = globals.get(name);
|
||||||
} else {
|
} else {
|
||||||
g = new SymbolDef(self, node);
|
g = new SymbolDef(self, node);
|
||||||
g.undeclared = true;
|
g.undeclared = true;
|
||||||
globals[name] = g;
|
globals.set(name, g);
|
||||||
}
|
}
|
||||||
node.thedef = g;
|
node.thedef = g;
|
||||||
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
||||||
@@ -209,8 +209,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
|
|
||||||
AST_Scope.DEFMETHOD("init_scope_vars", function(){
|
AST_Scope.DEFMETHOD("init_scope_vars", function(){
|
||||||
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 = Object.create(null); // 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 = Object.create(null); // map name to AST_SymbolDefun (functions defined in this scope)
|
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||||
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||||
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||||
this.parent_scope = null; // the parent scope
|
this.parent_scope = null; // the parent scope
|
||||||
@@ -252,7 +252,7 @@ AST_LabelRef.DEFMETHOD("reference", function(){
|
|||||||
|
|
||||||
AST_Scope.DEFMETHOD("find_variable", function(name){
|
AST_Scope.DEFMETHOD("find_variable", function(name){
|
||||||
if (name instanceof AST_Symbol) name = name.name;
|
if (name instanceof AST_Symbol) name = name.name;
|
||||||
return this.variables[name]
|
return this.variables.get(name)
|
||||||
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -262,17 +262,17 @@ AST_Scope.DEFMETHOD("has_directive", function(value){
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
||||||
this.functions[symbol.name] = this.def_variable(symbol);
|
this.functions.set(symbol.name, this.def_variable(symbol));
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
||||||
var def;
|
var def;
|
||||||
if (!this.variables[symbol.name]) {
|
if (!this.variables.has(symbol.name)) {
|
||||||
def = new SymbolDef(this, symbol);
|
def = new SymbolDef(this, symbol);
|
||||||
this.variables[symbol.name] = def;
|
this.variables.set(symbol.name, def);
|
||||||
def.global = !this.parent_scope;
|
def.global = !this.parent_scope;
|
||||||
} else {
|
} else {
|
||||||
def = this.variables[symbol.name];
|
def = this.variables.get(symbol.name);
|
||||||
def.orig.push(symbol);
|
def.orig.push(symbol);
|
||||||
}
|
}
|
||||||
return symbol.thedef = def;
|
return symbol.thedef = def;
|
||||||
@@ -355,15 +355,13 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
var p = tw.parent();
|
var p = tw.parent();
|
||||||
var is_setget = p instanceof AST_ObjectSetter || p instanceof AST_ObjectGetter;
|
var is_setget = p instanceof AST_ObjectSetter || p instanceof AST_ObjectGetter;
|
||||||
var a = node.variables;
|
node.variables.each(function(symbol){
|
||||||
for (var i in a) {
|
|
||||||
var symbol = a[i];
|
|
||||||
if (!(is_setget && symbol instanceof AST_SymbolLambda)) {
|
if (!(is_setget && symbol instanceof AST_SymbolLambda)) {
|
||||||
if (options.except.indexOf(symbol.name) < 0) {
|
if (options.except.indexOf(symbol.name) < 0) {
|
||||||
to_mangle.push(symbol);
|
to_mangle.push(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
|
|||||||
20
lib/utils.js
20
lib/utils.js
@@ -244,3 +244,23 @@ function makePredicate(words) {
|
|||||||
}
|
}
|
||||||
return new Function("str", f);
|
return new Function("str", f);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function Dictionary() {
|
||||||
|
this._values = Object.create(null);
|
||||||
|
};
|
||||||
|
Dictionary.prototype = {
|
||||||
|
set: function(key, val) { return this._values["$" + key] = val, this },
|
||||||
|
get: function(key) { return this._values["$" + key] },
|
||||||
|
del: function(key) { return delete this._values["$" + key], 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));
|
||||||
|
},
|
||||||
|
map: function(f) {
|
||||||
|
var ret = [];
|
||||||
|
for (var i in this._values)
|
||||||
|
ret.push(f(this._values[i], i.substr(1)));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user