summaryrefslogtreecommitdiff
path: root/emcc
diff options
context:
space:
mode:
Diffstat (limited to 'emcc')
-rwxr-xr-xemcc96
1 files changed, 85 insertions, 11 deletions
diff --git a/emcc b/emcc
index 83ce4529..6bf74707 100755
--- a/emcc
+++ b/emcc
@@ -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