diff options
Diffstat (limited to 'emcc')
-rwxr-xr-x | emcc | 96 |
1 files changed, 85 insertions, 11 deletions
@@ -1206,8 +1206,10 @@ try: jcache = False fastcomp_opts = ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] - if not shared.Settings.DISABLE_EXCEPTION_CATCHING: + if shared.Settings.DISABLE_EXCEPTION_CATCHING != 1: fastcomp_opts += ['-enable-emscripten-cxx-exceptions'] + if len(shared.Settings.EXCEPTION_CATCHING_WHITELIST) > 0: + fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST)] if shared.Settings.ASM_JS: assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above' @@ -1960,27 +1962,36 @@ try: # It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing js_optimizer_queue = [] js_optimizer_extra_info = {} + js_optimizer_queue_history = [] def flush_js_optimizer_queue(): - global final, js_optimizer_queue, js_optimizer_extra_info + global final, js_optimizer_queue, js_optimizer_extra_info, js_optimizer_queue_history if len(js_optimizer_extra_info) == 0: js_optimizer_extra_info = None if len(js_optimizer_queue) > 0 and not(not shared.Settings.ASM_JS and len(js_optimizer_queue) == 1 and js_optimizer_queue[0] == 'last'): - if DEBUG != '2': + + def add_opt_args(args): if shared.Settings.ASM_JS: - js_optimizer_queue = ['asm'] + js_optimizer_queue + args = ['asm'] + args + if shared.Settings.PRECISE_F32: + args = ['asmPreciseF32'] + args + return args + + if DEBUG != '2': + js_optimizer_queue = add_opt_args(js_optimizer_queue) logging.debug('applying js optimization passes: %s', js_optimizer_queue) final = shared.Building.js_optimizer(final, js_optimizer_queue, jcache, debug_level >= 4, js_optimizer_extra_info) js_transform_tempfiles.append(final) if DEBUG: save_intermediate('js_opts') else: for name in js_optimizer_queue: - passes = [name] + passes = add_opt_args([name]) if shared.Settings.ASM_JS: passes = ['asm'] + passes logging.debug('applying js optimization pass: %s', passes) final = shared.Building.js_optimizer(final, passes, jcache, debug_level >= 4, js_optimizer_extra_info) js_transform_tempfiles.append(final) save_intermediate(name) + js_optimizer_queue_history += js_optimizer_queue js_optimizer_queue = [] js_optimizer_extra_info = {} @@ -2066,15 +2077,78 @@ try: html.write(shell.replace('{{{ SCRIPT }}}', '<script>' + open(shared.path_from_root('src', 'proxyClient.js')).read().replace('{{{ filename }}}', target_basename) + '</script>')) shutil.move(final, js_target) elif not Compression.on: + # Normal code generation path if debug_level >= 4: generate_source_map(target) shutil.move(final, js_target) - # TODO: use an async blob, which would allow code rewriting on the client: - # var blob = new Blob([codeString]); - # var script = document.createElement('script'); - # script.src = URL.createObjectURL(blob); - # document.body.appendChild(script); - script_tag = '''<script async type="text/javascript" src="%s"></script>''' % base_js_target + need_mods = shared.Settings.PRECISE_F32 == 2 + if not need_mods: + # Non-modifiable code, just load the code directly + script_tag = '''<script async type="text/javascript" src="%s"></script>''' % base_js_target + else: + # Potentially-modifiable code, load as text, modify, then execute. This lets you + # patch the code on the client machine right before it is executed, perhaps based + # on information about the client. + checks = [] + mods = [] + if shared.Settings.PRECISE_F32 == 2: + checks.append('!Math.fround') + if 'minifyNames' not in js_optimizer_queue_history: + # simple dumb replace + mods.append(''' +console.log('optimizing out Math.fround calls'); +code = code.replace(/Math_fround\(/g, '(').replace("'use asm'", "'almost asm'") +''') + else: + # minified, not quite so simple - TODO + mods.append(''' +try { + console.log('optimizing out Math.fround calls'); + var m = /var ([^=]+)=global\.Math\.fround;/.exec(code); + var minified = m[1]; + if (!minified) throw 'fail'; + var startAsm = code.indexOf('// EMSCRIPTEN_START_FUNCS'); + var endAsm = code.indexOf('// EMSCRIPTEN_END_FUNCS'); + var asm = code.substring(startAsm, endAsm); + do { + var moar = false; // we need to re-do, as x(x( will not be fixed + asm = asm.replace(new RegExp('[^a-zA-Z0-9\\\\$\\\\_]' + minified + '\\\\(', 'g'), function(s) { moar = true; return s[0] + '(' }); + } while (moar); + code = code.substring(0, startAsm) + asm + code.substring(endAsm); + code = code.replace("'use asm'", "'almost asm'"); +} catch(e) { console.log('failed to optimize out Math.fround calls ' + e) } +''') + + fixes = '' + for i in range(len(checks)): + fixes += 'if (' + checks[i] + ') { ' + mods[i] + ' }\n' + + # if all the checks are negative, just emit a script tag normally, that's better. + # otherwise, do an xhr to get the code as text, modify, and load asynchronously + code = 'if (!(' + ' || '.join(checks) + ''')) { + var script = document.createElement('script'); + script.src = "''' + base_js_target + '''"; + document.body.appendChild(script); +} else { + var codeXHR = new XMLHttpRequest(); + codeXHR.open('GET', '%s', true); + codeXHR.onload = function() { + var code = codeXHR.responseText; + %s + var blob = new Blob([code], { type: 'text/javascript' }); + codeXHR = null; + var src = URL.createObjectURL(blob); + var script = document.createElement('script'); + script.src = URL.createObjectURL(blob); + script.onload = function() { + URL.revokeObjectURL(script.src); + }; + document.body.appendChild(script); + }; + codeXHR.send(null); +} +''' % (base_js_target, fixes) + script_tag = '''<script>%s</script>''' % code html.write(shell.replace('{{{ SCRIPT }}}', script_tag)) else: # Compress the main code |