-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
As discussed in #6092, when using sync loading with assertions enabled, you get an error due to the wrapper functions that are installed by ASSERTIONS
:
asm["__wasm_call_ctors"] = function() {
^
TypeError: Cannot assign to read only property '__wasm_call_ctors' of object '[object Object]'
at /Users/bruce/.../embind_test.js:4697:26
The relevant code is from within the generated JS is:
var asm = createWasm();
var real____wasm_call_ctors = asm["__wasm_call_ctors"];
asm["__wasm_call_ctors"] = function() {
assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
return real____wasm_call_ctors.apply(null, arguments);
};
This happens because WebAssembly.Instance.exports
is a read-only object as defined here (and in the spec): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance/exports
You can see that it gets asm
by calling createWasm
.
In src/preamble.js
, the end of the createWasm
function looks like:
#if WASM_ASYNC_COMPILATION
#if RUNTIME_LOGGING
err('asynchronously preparing wasm');
#endif
instantiateAsync();
#if LOAD_SOURCE_MAP
getSourceMapPromise().then(receiveSourceMapJSON);
#endif
return {}; // no exports yet; we'll fill them in later
#else
instantiateSync();
return Module['asm']; // exports were assigned here
#endif
}
So, in the async case, it just returns {}
, while in the sync case, it is returning Module[asm]
.
Module[asm]
is set up in the start of receiveInstance
:
// Load the wasm module and create an instance of using native support in the JS engine.
// handle a generated wasm instance, receiving its exports and
// performing other necessary setup
/** @param {WebAssembly.Module=} module*/
function receiveInstance(instance, module) {
var exports = instance.exports;
#if RELOCATABLE
exports = relocateExports(exports, GLOBAL_BASE, 0);
#endif
#if WASM_BACKEND && ASYNCIFY
exports = Asyncify.instrumentWasmExports(exports);
#endif
Module['asm'] = exports;
So here, we can see that it is getting assigned the read-only value from WebAssembly.Instance.exports
.
This does not require a browser to reproduce. I'm hitting it running some automated tests under Node, trying to see if I can enable ASSERTIONS
for the tests. We use sync compilation for other reasons that will be difficult to address in the near term future.