diff --git a/emcc.py b/emcc.py index 2e1ebc291e9d9..d3cfa07fe11f9 100755 --- a/emcc.py +++ b/emcc.py @@ -1298,7 +1298,8 @@ def check(input_file): if shared.Building.is_wasm_only() and shared.Settings.EVAL_CTORS: logging.debug('disabling EVAL_CTORS, as in wasm-only mode it hurts more than it helps. TODO: a wasm version of it') shared.Settings.EVAL_CTORS = 0 - if shared.Settings.BINARYEN_ASYNC_COMPILATION == 1 and shared.Building.is_wasm_only(): + # async compilation requires wasm-only mode, and also not interpreting (the interpreter needs sync input) + if shared.Settings.BINARYEN_ASYNC_COMPILATION == 1 and shared.Building.is_wasm_only() and 'interpret' not in shared.Settings.BINARYEN_METHOD: # async compilation requires a swappable module - we swap it in when it's ready shared.Settings.SWAPPABLE_ASM_MODULE = 1 else: @@ -2339,7 +2340,7 @@ def un_src(): # use this if you want to modify the script and need it to be inli else: assert len(asm_mods) == 0, 'no --separate-asm means no client code mods are possible' - if shared.Settings.BINARYEN: + if shared.Settings.BINARYEN and not shared.Settings.BINARYEN_ASYNC_COMPILATION: # We need to load the wasm file before anything else, it has to be synchronously ready TODO: optimize un_src() script_inline = ''' diff --git a/src/preamble.js b/src/preamble.js index 486b54c99a132..adc5873262151 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -2153,16 +2153,28 @@ function integrateWasmJS(Module) { function getBinary() { var binary; - if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + if (Module['wasmBinary']) { binary = Module['wasmBinary']; - assert(binary, "on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)"); binary = new Uint8Array(binary); - } else { + } else if (Module['readBinary']) { binary = Module['readBinary'](wasmBinaryFile); + } else { + throw "on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)"; } return binary; } + function getBinaryPromise() { + // if we don't have the binary yet, and have the Fetch api, use that + if (!Module['wasmBinary'] && typeof fetch === 'function') { + return fetch(wasmBinaryFile).then(function(response) { return response.arrayBuffer() }); + } + // Otherwise, getBinary should be able to get it synchronously + return new Promise(function(resolve, reject) { + resolve(getBinary()); + }); + } + // do-method functions function doJustAsm(global, env, providedBuffer) { @@ -2212,7 +2224,9 @@ function integrateWasmJS(Module) { #if BINARYEN_ASYNC_COMPILATION Module['printErr']('asynchronously preparing wasm'); addRunDependency('wasm-instantiate'); // we can't run yet - WebAssembly.instantiate(getBinary(), info).then(function(output) { + getBinaryPromise().then(function(binary) { + return WebAssembly.instantiate(binary, info) + }).then(function(output) { // receiveInstance() will swap in the exports (to Module.asm) so they can be called receiveInstance(output.instance); removeRunDependency('wasm-instantiate'); @@ -2221,7 +2235,7 @@ function integrateWasmJS(Module) { Module['quit'](1, reason); }); return {}; // no exports yet; we'll fill them in later -#endif +#else var instance; try { instance = new WebAssembly.Instance(new WebAssembly.Module(getBinary()), info) @@ -2234,6 +2248,7 @@ function integrateWasmJS(Module) { } receiveInstance(instance); return exports; +#endif } function doWasmPolyfill(global, env, providedBuffer, method) { diff --git a/src/shell.js b/src/shell.js index d0046ea5592ea..e562a7986e6a6 100644 --- a/src/shell.js +++ b/src/shell.js @@ -169,6 +169,16 @@ else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { return xhr.responseText; }; + if (ENVIRONMENT_IS_WORKER) { + Module['readBinary'] = function read(url) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + xhr.responseType = 'arraybuffer'; + xhr.send(null); + return xhr.response; + }; + } + Module['readAsync'] = function readAsync(url, onload, onerror) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); diff --git a/tests/test_browser.py b/tests/test_browser.py index 861f54370bab2..c4e06bcc1c685 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1352,7 +1352,7 @@ def test_egl_width_height(self): Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl_width_height.c'), '-o', 'page.html', '-lEGL', '-lGL']).communicate() self.run_browser('page.html', 'Should print "(300, 150)" -- the size of the canvas in pixels', '/report_result?1') - def test_worker(self): + def do_test_worker(self, args=[]): # Test running in a web worker open('file.dat', 'w').write('data for worker') html_file = open('main.html', 'w') @@ -1374,15 +1374,17 @@ def test_worker(self): ''') html_file.close() - # no file data - for file_data in [0, 1]: - print 'file data', file_data - output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_worker.cpp'), '-o', 'worker.js'] + (['--preload-file', 'file.dat'] if file_data else []) , stdout=PIPE, stderr=PIPE).communicate() - assert len(output[0]) == 0, output[0] - assert os.path.exists('worker.js'), output - if not file_data: self.assertContained('you should not see this text when in a worker!', run_js('worker.js')) # code should run standalone + for file_data in [1, 0]: + cmd = [PYTHON, EMCC, path_from_root('tests', 'hello_world_worker.cpp'), '-o', 'worker.js'] + (['--preload-file', 'file.dat'] if file_data else []) + args + print cmd + subprocess.check_call(cmd) + assert os.path.exists('worker.js') self.run_browser('main.html', '', '/report_result?hello%20from%20worker,%20and%20|' + ('data%20for%20w' if file_data else '') + '|') + def test_worker(self): + self.do_test_worker() + self.assertContained('you should not see this text when in a worker!', run_js('worker.js')) # code should run standalone too + def test_chunked_synchronous_xhr(self): main = 'chunked_sync_xhr.html' worker_filename = "download_and_checksum_worker.js" @@ -3337,6 +3339,9 @@ def test_binaryen_async(self): print opts, expect self.btest('binaryen_async.c', expected=str(expect), args=['-s', 'BINARYEN=1', '--shell-file', 'shell.html'] + opts) + def test_binaryen_worker(self): + self.do_test_worker(['-s', 'WASM=1']) + def test_utf8_textdecoder(self): self.btest('benchmark_utf8.cpp', expected='0', args=['--embed-file', path_from_root('tests/utf8_corpus.txt') + '@/utf8_corpus.txt'])