diff options
author | Alon Zakai <alonzakai@gmail.com> | 2011-11-19 23:00:04 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2011-11-19 23:00:04 -0800 |
commit | b27d8da1c798d2a4cfbf8d63585004ce77cf2c71 (patch) | |
tree | 638bc1aea154c1fe603f4c50322347bbe8d8a0a6 | |
parent | a6e94183b9ed09f3c07ed921745bde179bca3f9c (diff) |
partial work to remove assigns of undefined in js optimizer
-rw-r--r-- | src/utility.js | 4 | ||||
-rw-r--r-- | tools/js-optimizer.js | 34 | ||||
-rw-r--r-- | tools/test-js-optimizer-output.js | 1 |
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; |