Skip to content

WASM_ASYNC_COMPILATION=0 && ASSERTIONS=1 #11045

@waywardmonkeys

Description

@waywardmonkeys

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions