diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-03-08 17:12:22 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-03-08 17:12:22 -0800 |
commit | dac020142d05493a1c47632e561f4069a85ee13a (patch) | |
tree | 220d4ab10a73f236b1611e180ec60465a3ede0ad /tools | |
parent | b31addd3ab55af8dddb703580ebf5d2a90660c61 (diff) |
minify globals in a pass before the functions
Diffstat (limited to 'tools')
-rw-r--r-- | tools/js-optimizer.js | 35 | ||||
-rw-r--r-- | tools/js_optimizer.py | 45 |
2 files changed, 69 insertions, 11 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 77ad0ba3..092c9f35 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -2159,6 +2159,37 @@ function eliminateMemSafe(ast) { eliminate(ast, true); } +function minifyGlobals(ast) { + var minified = {}; + var next = 0; + var first = true; // do not minify initial 'var asm =' + traverse(ast, function(node, type) { + if (type == 'var') { + if (first) { + first = false; + return; + } + var vars = node[1]; + for (var i = 0; i < vars.length; i++) { + var name = vars[i][0]; + vars[i][0] = minified[name] = minifierInfo.names[next++]; + } + } else if (type == 'name') { + var name = node[1]; + if (name in minified) { + node[1] = minified[name]; + } else if (name == 'EMSCRIPTEN_FUNCS') { + // minify all the globals + for (var i = 0; i < minifierInfo.globals.length; i++) { + name = minifierInfo.globals[i]; + minified[name] = minifierInfo.names[next++]; + } + } + } + }); + suffix = '// MINIFY_INFO:' + JSON.stringify(minified); +} + // Change +5 to DOT$ZERO(5). We then textually change 5 to 5.0 (uglify's ast cannot differentiate between 5 and 5.0 directly) function prepDotZero(ast) { traverse(ast, function(node, type) { @@ -2204,6 +2235,7 @@ var passes = { registerize: registerize, eliminate: eliminate, eliminateMemSafe: eliminateMemSafe, + minifyGlobals: minifyGlobals, compress: function() { compress = true }, noPrintMetadata: function() { printMetadata = false }, asm: function() { asm = true }, @@ -2212,6 +2244,8 @@ var passes = { // Main +var suffix = ''; + var src = read(arguments_[0]); var ast = srcToAst(src); //printErr(JSON.stringify(ast)); throw 1; @@ -2238,4 +2272,5 @@ do { } while (js != old); print(js); print('\n'); +print(suffix); diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 4661580b..cc7e8104 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -19,6 +19,8 @@ WINDOWS = sys.platform.startswith('win') DEBUG = os.environ.get('EMCC_DEBUG') +func_sig = re.compile('( *)function ([_\w$]+)\(') + class Minifier: ''' asm.js minification support. We calculate possible names and minification of @@ -26,7 +28,10 @@ class Minifier: during registerize perform minification of locals. ''' - def __init__(self): + def __init__(self, js, js_engine): + self.js = js + self.js_engine = js_engine + # Create list of valid short names MAX_NAMES = 200#60000 @@ -52,14 +57,30 @@ class Minifier: if curr not in INVALID_3: self.names.append(curr) #print >> sys.stderr, self.names - self.globs = {} + def minify_shell(self, shell): + #print >> sys.stderr, "MINIFY SHELL 1111111111", shell, "\n222222222222222" + # Run through js-optimizer.js to find and minify the global symbols + # We send it the globals, which it parses at the proper time. JS decides how + # to minify all global names, we receive a dictionary back, which is then + # used by the function processors + + # Find all globals in the JS functions code + self.globs = [m.group(2) for m in func_sig.finditer(self.js)] + + temp_file = temp_files.get('.minifyglobals.js').name + f = open(temp_file, 'w') + f.write(shell) + f.write('\n') + self + f.write('// MINIFY_INFO:' + self.serialize()) + f.close() - def add_glob(self, glob): - # Minify the globals (initials - asm imports, etc. - and functions) - # TODO: find how many times they are used and do this more optimally - ret = self.names[len(self.globs)] - self.globs[glob] = ret - return ret + output = subprocess.Popen(self.js_engine + [JS_OPTIMIZER, temp_file, 'minifyGlobals', 'noPrintMetadata'], stdout=subprocess.PIPE).communicate()[0] + assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + output + #print >> sys.stderr, "minified SHELL 3333333333333333", output, "\n44444444444444444444" + code, metadata = output.split('// MINIFY_INFO:') + self.globs = json.loads(metadata) + return output def serialize(self): return json.dumps({ @@ -135,11 +156,14 @@ def run_on_js(filename, passes, js_engine, jcache): asm_shell = js[start_asm + len(start_asm_marker):start_funcs + len(start_funcs_marker)] + ''' EMSCRIPTEN_FUNCS(); ''' + js[end_funcs + len(end_funcs_marker):end_asm + len(end_asm_marker)] - minified_asm_shell = asm_shell # TODO: minification of globals + js = js[start_funcs + len(start_funcs_marker):end_funcs] + + minifier = Minifier(js, js_engine) + minified_asm_shell = minifier.minify_shell(asm_shell) + asm_shell_pre, asm_shell_post = minified_asm_shell.split('EMSCRIPTEN_FUNCS();'); pre += asm_shell_pre post = asm_shell_post + post - js = js[start_funcs + len(start_funcs_marker):end_funcs] else: pre = '' post = '' @@ -148,7 +172,6 @@ EMSCRIPTEN_FUNCS(); # If we have metadata, we split only the generated code, and save the pre and post on the side (and do not optimize them) parts = map(lambda part: part, js.split('\n}\n')) funcs = [] - func_sig = re.compile('( *)function ([_\w$]+)\(') for i in range(len(parts)): func = parts[i] if i < len(parts)-1: func += '\n}\n' # last part needs no } |