aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2011-11-19 23:00:04 -0800
committerAlon Zakai <alonzakai@gmail.com>2011-11-19 23:00:04 -0800
commitb27d8da1c798d2a4cfbf8d63585004ce77cf2c71 (patch)
tree638bc1aea154c1fe603f4c50322347bbe8d8a0a6
parenta6e94183b9ed09f3c07ed921745bde179bca3f9c (diff)
partial work to remove assigns of undefined in js optimizer
-rw-r--r--src/utility.js4
-rw-r--r--tools/js-optimizer.js34
-rw-r--r--tools/test-js-optimizer-output.js1
3 files changed, 28 insertions, 11 deletions
diff --git a/src/utility.js b/src/utility.js
index 53555aa5..91c4abe3 100644
--- a/src/utility.js
+++ b/src/utility.js
@@ -272,3 +272,7 @@ function copy(x) {
return JSON.parse(JSON.stringify(x));
}
+function jsonCompare(x, y) {
+ return JSON.stringify(x) == JSON.stringify(y);
+}
+
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 372cbea3..f88b7d95 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -92,7 +92,7 @@ function traverseWithVariables(ast, callback) {
}, []);
}
-function makeEmptyNode() {
+function emptyNode() {
return ['toplevel', []]
}
@@ -112,18 +112,15 @@ function unGlobalize(ast) {
var value = varItem[1];
if (!value) return true;
var possible = false;
- if (value[0] == 'name' && value[1] == 'null') {
- possible = true;
- } else if (value[0] == 'unary-prefix' && value[1] == 'void' && value[2] && value[2].length == 2 && value[2][0] == 'num' && value[2][1] == 0) {
- possible = true;
- } else if (value[0] == 'unary-prefix' && value[1] == '!' && value[2] && value[2].length == 2 && value[2][0] == 'num' && value[2][1] == 0) {
- possible = true;
- } else if (value[0] == 'unary-prefix' && value[1] == '!' && value[2] && value[2].length == 2 && value[2][0] == 'num' && value[2][1] == 1) {
+ if (jsonCompare(value, ['name', 'null']) ||
+ jsonCompare(value, ['unary-prefix', 'void', ['num', 0]]) ||
+ jsonCompare(value, ['unary-prefix', '!', ['num', 0]]) ||
+ jsonCompare(value, ['unary-prefix', '!', ['num', 1]])) {
possible = true;
}
if (!possible) return true;
// Make sure there are no assignments to this variable. (This isn't fast, we traverse many times..)
- ast[1][i][1][j] = makeEmptyNode();
+ ast[1][i][1][j] = emptyNode();
var assigned = false;
traverseWithVariables(ast, function(node, type, allVars) {
if (type == 'assign' && node[2][0] == 'name' && node[2][1] == ident) assigned = true;
@@ -137,7 +134,7 @@ function unGlobalize(ast) {
});
if (node[1].length == 0) {
- ast[1][i] = makeEmptyNode();
+ ast[1][i] = emptyNode();
}
});
traverseWithVariables(ast, function(node, type, allVars) {
@@ -150,6 +147,22 @@ function unGlobalize(ast) {
});
}
+// Closure compiler, when inlining, will insert assignments to
+// undefined for the shared variables. However, in compiled code
+// - and in library/shell code too! - we should never rely on
+// undefined being assigned. So we can simply remove those assignments.
+//
+// This pass assumes that unGlobalize has been run, so undefined
+// is now explicit.
+function removeAssignsToUndefined(ast) {
+ // TODO: in vars too
+ traverse(ast, function(node, type) {
+ if (type == 'assign' && jsonCompare(node[3], ['unary-prefix', 'void', ['num', 0]])) {
+ return emptyNode();
+ }
+ });
+}
+
// Main
var src = fs.readFileSync('/dev/stdin').toString();
@@ -157,6 +170,7 @@ var src = fs.readFileSync('/dev/stdin').toString();
var ast = uglify.parser.parse(src);
unGlobalize(ast);
+removeAssignsToUndefined(ast);
print(uglify.uglify.gen_code(ast, {
ascii_only: true,
diff --git a/tools/test-js-optimizer-output.js b/tools/test-js-optimizer-output.js
index a6e790c8..a08be0ca 100644
--- a/tools/test-js-optimizer-output.js
+++ b/tools/test-js-optimizer-output.js
@@ -6,7 +6,6 @@ function abc() {
var cheez = [ void 0 ];
var fleefl;
cheez = 10;
- fleefl = void 0;
var waka = void 0, flake = void 0, marfoosh = void 0;
var waka2 = 5, flake2 = void 0, marfoosh2 = void 0;
var waka3 = void 0, flake3 = 5, marfoosh3 = void 0;