aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-03-08 17:12:22 -0800
committerAlon Zakai <alonzakai@gmail.com>2013-03-08 17:12:22 -0800
commitdac020142d05493a1c47632e561f4069a85ee13a (patch)
tree220d4ab10a73f236b1611e180ec60465a3ede0ad /tools
parentb31addd3ab55af8dddb703580ebf5d2a90660c61 (diff)
minify globals in a pass before the functions
Diffstat (limited to 'tools')
-rw-r--r--tools/js-optimizer.js35
-rw-r--r--tools/js_optimizer.py45
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 }