Skip to content

Copy the wasm exports object if we intend to modify it #8950

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ test-chrome: &test-chrome
# --no-sandbox becasue we are running as root and chrome requires
# this flag for now: https://crbug.com/638180
CHROME_FLAGS_BASE="--no-first-run -start-maximized --no-sandbox --use-gl=swiftshader"
CHROME_FLAGS_WASM="--enable-features=WebAssembly --enable-features=SharedArrayBuffer --disable-features=WebAssemblyTrapHandler --js-flags=\"--experimental-wasm-threads --harmony-sharedarraybuffer --no-wasm-disable-structured-cloning\""
CHROME_FLAGS_WASM="--enable-features=WebAssembly --enable-features=SharedArrayBuffer --disable-features=WebAssemblyTrapHandler --enable-experimental-web-platform-features --js-flags=\"--experimental-wasm-threads --harmony-sharedarraybuffer --no-wasm-disable-structured-cloning\""
export EMTEST_BROWSER="xvfb-run -a -e /dev/stdout /usr/bin/google-chrome-stable $CHROME_FLAGS_BASE $CHROME_FLAGS_WASM"
export EMTEST_LACKS_GRAPHICS_HARDWARE=1
export EMCC_CORES=4
Expand Down
5 changes: 0 additions & 5 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -1707,11 +1707,6 @@ def create_receiving(function_table_data, function_tables_defs, exported_impleme

shared.Settings.MODULE_EXPORTS = module_exports = exported_implemented_functions + function_tables(function_table_data)

# Currently USE PTHREADS + EXPORT ES6 doesn't work with the previously generated assertions.
# ES6 modules disallow re-assigning read-only properties.
if shared.Settings.USE_PTHREADS and shared.Settings.EXPORT_ES6 and shared.Settings.ASSERTIONS and receiving:
receiving = "assert(!ENVIRONMENT_IS_PTHREAD, 'Error: USE_PTHREADS and EXPORT_ES6 requires ASSERTIONS=0');\n" + receiving

if not shared.Settings.SWAPPABLE_ASM_MODULE:
if shared.Settings.DECLARE_ASM_MODULE_EXPORTS:
imported_exports = [s for s in module_exports if s not in initializers]
Expand Down
8 changes: 8 additions & 0 deletions src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,14 @@ function createWasm(env) {
// performing other necessary setup
function receiveInstance(instance, module) {
var exports = instance.exports;
// We want to modify the exports in some cases, however, in ES6 environments that
// may be illegal as the wasm exports are an ES6 export object, which is read-only.
// To work around that, we simply make a copy of them.
#if EXPORT_ES6 && (ASSERTIONS || BYSYNCIFY)
var originalExports = exports;
exports = {};
for (var x in originalExports) exports[x] = originalExports[x];
#endif
#if BYSYNCIFY
exports = Bysyncify.instrumentWasmExports(exports);
#endif
Expand Down
26 changes: 26 additions & 0 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4715,3 +4715,29 @@ def test_minimal_runtime_loader_shell(self):
for modularize in [[], ['-s', 'MODULARIZE=1']]:
print(str(args + wasm + modularize))
self.btest('minimal_hello.c', '0', args=args + wasm + modularize)

@no_firefox('need to enable es6 modules there somehow')
def _test_es6(self, args):
args = args + ['-s', 'EXPORT_ES6', '-s', 'MODULARIZE', '-s', 'MODULARIZE_INSTANCE', '-s', 'ASSERTIONS', '-o', 'test.mjs']
print(args)
create_test_file('src.c', self.with_report_result(open(path_from_root('tests', 'browser_test_hello_world.c')).read()))
self.compile_btest(['src.c'] + args)
create_test_file('test.html', '''
<script type="module" src="test.mjs"></script>
''')
self.run_browser('test.html', None, '/report_result?0')

def test_es6_O0(self):
self._test_es6([])

def test_es6_O3(self):
self._test_es6(['-O3'])

def test_es6_async(self):
self._test_es6(self.get_async_args())

@requires_threads
def test_es6_threads(self):
# TODO: use PROXY_TO_PTHREAD and/or '-s', 'PTHREAD_POOL_SIZE=1' once https://bugs.chromium.org/p/chromium/issues/detail?id=680046 is fixed
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work on Chrome if --enable-experimental-web-platform-features is set (sorry, forgot to mention that).
The Firefox bug is also: https://bugzilla.mozilla.org/show_bug.cgi?id=1540913

# firefox also errors, "SyntaxError: dynamic module import is not implemented"
self._test_es6(['-s', 'USE_PTHREADS', '-s', 'PROXY_TO_PTHREAD'])