add --closure 2 option, to run closure even on the asm.js output

This commit is contained in:
Alon Zakai 2014-08-22 13:07:02 -07:00
Родитель ae14052569
Коммит 919556db48
5 изменённых файлов: 71 добавлений и 31 удалений

24
emcc
Просмотреть файл

@ -920,8 +920,11 @@ try:
assert not (shared.Settings.NO_DYNAMIC_EXECUTION and closure), 'cannot have both NO_DYNAMIC_EXECUTION and closure compiler enabled at the same time'
if closure:
shared.Settings.CLOSURE_COMPILER = 1
shared.Settings.CLOSURE_COMPILER = closure
assert os.path.exists(shared.CLOSURE_COMPILER), logging.error('fatal: Closure compiler (%s) does not exist', shared.CLOSURE_COMPILER)
if closure == 2 and shared.Settings.ASM_JS == 1:
logging.warning('not all asm.js optimizations are possible with --closure 2, disabling those')
shared.Settings.ASM_JS = 2
assert shared.LLVM_TARGET in shared.COMPILER_OPTS
if shared.LLVM_TARGET == 'i386-pc-linux-gnu':
@ -1352,7 +1355,7 @@ try:
js_optimizer_extra_info = {}
if opt_level >= 1 and js_opts:
logging.debug('running pre-closure post-opts')
logging.debug('running js post-opts')
if DEBUG == '2':
# Clean up the syntax a bit
@ -1399,28 +1402,37 @@ try:
js_optimizer_queue += ['outline']
js_optimizer_extra_info['sizeToOutline'] = shared.Settings.OUTLINING_LIMIT
if opt_level >= 2 and (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3:
if opt_level >= 2 and (not closure or shared.Settings.ASM_JS or closure == 2) and shared.Settings.RELOOP and debug_level < 3:
if shared.Settings.ASM_JS and opt_level >= 3:
js_optimizer_queue += ['registerizeHarder']
else:
js_optimizer_queue += ['registerize']
if opt_level >= 2:
if debug_level < 2 and shared.Settings.ASM_JS:
if debug_level < 2 and shared.Settings.ASM_JS and not closure == 2:
js_optimizer_queue += ['minifyNames']
if emit_symbol_map: js_optimizer_queue += ['symbolMap='+target+'.symbols']
if debug_level == 0: js_optimizer_queue += ['minifyWhitespace']
if shared.Settings.ASM_JS:
if closure:
if closure == 1:
js_optimizer_queue += ['closure']
elif debug_level <= 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE:
elif debug_level <= 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE and not closure:
js_optimizer_queue += ['cleanup']
if not shared.Settings.SIDE_MODULE: js_optimizer_queue += ['last'] # side modules are not finalized until after relocation
flush_js_optimizer_queue()
if shared.Settings.ASM_JS and closure == 2:
flush_js_optimizer_queue()
logging.debug('running closure')
# no need to add this to js_transform_tempfiles, because closure and
# debug_level > 0 are never simultaneously true
final = shared.Building.closure_compiler(final, pretty=debug_level >= 1)
if DEBUG: save_intermediate('closure')
log_time('js opts')
# Remove some trivial whitespace # TODO: do not run when compress has already been done on all parts of the code

Просмотреть файл

@ -1124,12 +1124,24 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
asm_setup += '\n' + shared.JS.make_extcall(sig) + '\n'
basic_funcs.append('extCall_%s' % sig)
def quote(prop):
if settings['CLOSURE_COMPILER'] == 2:
return "'" + prop + "'"
else:
return prop
def access_quote(prop):
if settings['CLOSURE_COMPILER'] == 2:
return "['" + prop + "']"
else:
return '.' + prop
# calculate exports
exported_implemented_functions = list(exported_implemented_functions) + metadata['initializers']
exported_implemented_functions.append('runPostSets')
exports = []
for export in exported_implemented_functions + asm_runtime_funcs + function_tables:
exports.append("%s: %s" % (export, export))
exports.append(quote(export) + ": " + export)
exports = '{ ' + ', '.join(exports) + ' }'
# calculate globals
try:
@ -1141,9 +1153,9 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
global_funcs = list(set([key for key, value in forwarded_json['Functions']['libraryFunctions'].iteritems() if value != 2]).difference(set(global_vars)).difference(implemented_functions))
def math_fix(g):
return g if not g.startswith('Math_') else g.split('_')[1]
asm_global_funcs = ''.join([' var ' + g.replace('.', '_') + '=global.' + g + ';\n' for g in maths]) + \
''.join([' var ' + g + '=env.' + math_fix(g) + ';\n' for g in basic_funcs + global_funcs])
asm_global_vars = ''.join([' var ' + g + '=env.' + g + '|0;\n' for g in basic_vars + global_vars])
asm_global_funcs = ''.join([' var ' + g.replace('.', '_') + '=global' + access_quote(g) + ';\n' for g in maths]) + \
''.join([' var ' + g + '=env' + access_quote(math_fix(g)) + ';\n' for g in basic_funcs + global_funcs])
asm_global_vars = ''.join([' var ' + g + '=env' + access_quote(g) + '|0;\n' for g in basic_vars + global_vars])
# In linkable modules, we need to add some explicit globals for global variables that can be linked and used across modules
if settings.get('MAIN_MODULE') or settings.get('SIDE_MODULE'):
assert settings.get('TARGET_ASMJS_UNKNOWN_EMSCRIPTEN'), 'TODO: support x86 target when linking modules (needs offset of 4 and not 8 here)'
@ -1167,6 +1179,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
return real_''' + s + '''.apply(null, arguments);
};
''' for s in exported_implemented_functions if s not in ['_malloc', '_free', '_memcpy', '_memset']])
receiving += ';\n'.join(['var ' + s + ' = Module["' + s + '"] = asm["' + s + '"]' for s in exported_implemented_functions + function_tables])
# finalize
@ -1184,15 +1197,23 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
// EMSCRIPTEN_START_ASM
var asm = (function(global, env, buffer) {
%s
var HEAP8 = new global.Int8Array(buffer);
var HEAP16 = new global.Int16Array(buffer);
var HEAP32 = new global.Int32Array(buffer);
var HEAPU8 = new global.Uint8Array(buffer);
var HEAPU16 = new global.Uint16Array(buffer);
var HEAPU32 = new global.Uint32Array(buffer);
var HEAPF32 = new global.Float32Array(buffer);
var HEAPF64 = new global.Float64Array(buffer);
''' % (asm_setup, "'use asm';" if not metadata.get('hasInlineJS') and not settings['SIDE_MODULE'] and settings['ASM_JS'] == 1 else "'almost asm';") + '\n' + asm_global_vars + '''
var HEAP8 = new global%s(buffer);
var HEAP16 = new global%s(buffer);
var HEAP32 = new global%s(buffer);
var HEAPU8 = new global%s(buffer);
var HEAPU16 = new global%s(buffer);
var HEAPU32 = new global%s(buffer);
var HEAPF32 = new global%s(buffer);
var HEAPF64 = new global%s(buffer);
''' % (asm_setup, "'use asm';" if not metadata.get('hasInlineJS') and not settings['SIDE_MODULE'] and settings['ASM_JS'] == 1 else "'almost asm';",
access_quote('Int8Array'),
access_quote('Int16Array'),
access_quote('Int32Array'),
access_quote('Uint8Array'),
access_quote('Uint16Array'),
access_quote('Uint32Array'),
access_quote('Float32Array'),
access_quote('Float64Array')) + '\n' + asm_global_vars + '''
var __THREW__ = 0;
var threwValue = 0;
var setjmpId = 0;

Просмотреть файл

@ -218,11 +218,16 @@ Options that are modified or new in *emcc* are listed below:
* "1": Run closure compiler. This greatly reduces code size
and may in some cases increase runtime speed (although the
opposite can also occur). Note that it takes time to run, and
may require some changes to the code.
may require some changes to the code. In **asm.js** mode,
closure will only be used on the 'shell' code around the
compiled code (the compiled code will be processed by the
custom **asm.js** minifier).
In **asm.js** mode, closure will only be used on the 'shell' code
around the compiled code (the compiled code will be processed by
the custom **asm.js** minifier).
* "2": Run closure compiler on *all* the emitted code, even on
**asm.js** output in **asm.js** mode. This can further reduce
code size, but does prevent a significant amount of **asm.js**
optimizations, so it is not recommended unless you want to
reduce code size at all costs.
Note: * If closure compiler hits an out-of-memory, try adjusting

Просмотреть файл

@ -158,9 +158,8 @@ Options that are modified or new in *emcc* are listed below:
Runs the :term:`Closure Compiler`. Possible ``on`` values are:
- ``0``: No closure compiler (default in ``-O2`` and below).
- ``1``: Run closure compiler. This greatly reduces code size and may in some cases increase runtime speed (although the opposite can also occur). Note that it takes time to run, and may require some changes to the code.
In **asm.js** mode, closure will only be used on the 'shell' code around the compiled code (the compiled code will be processed by the custom **asm.js** minifier).
- ``1``: Run closure compiler. This greatly reduces code size and may in some cases increase runtime speed (although the opposite can also occur). Note that it takes time to run, and may require some changes to the code. In **asm.js** mode, closure will only be used on the 'shell' code around the compiled code (the compiled code will be processed by the custom **asm.js** minifier).
- ``2``: Run closure compiler on *all* the emitted code, even on **asm.js** output in **asm.js** mode. This can further reduce code size, but does prevent a significant amount of **asm.js** optimizations, so it is not recommended unless you want to reduce code size at all costs.
.. note::

Просмотреть файл

@ -3978,12 +3978,13 @@ main(const int argc, const char * const * const argv)
test(['-O1'])
def test_no_nuthin(self):
def test(opts, ratio):
def test(opts, ratio, absolute):
print opts
def get_size(name):
return os.stat(name).st_size
sizes = {}
def do(name, moar_opts):
self.clear()
Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-o', name + '.js'] + opts + moar_opts).communicate()
sizes[name] = get_size(name + '.js')
self.assertContained('hello, world!', run_js(name + '.js'))
@ -3997,10 +3998,12 @@ main(const int argc, const char * const * const argv)
assert sizes['no_nuthin'] < sizes['no_fs']
assert sizes['no_nuthin'] < sizes['no_browser']
assert sizes['no_nuthin'] < ratio*sizes['normal']
test([], 0.66)
test(['-O1'], 0.66)
test(['-O2'], 0.50)
test(['-O3', '--closure', '1'], 0.60)
assert sizes['no_nuthin'] < absolute
test([], 0.66, 250000)
test(['-O1'], 0.66, 225000)
test(['-O2'], 0.50, 75000)
test(['-O3', '--closure', '1'], 0.60, 60000)
test(['-O3', '--closure', '2'], 0.60, 40000) # might change now and then
def test_stat_fail_alongtheway(self):
open('src.cpp', 'w').write(r'''