Skip to content
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

[js-api] No (easy) access to memory from imported function #1175

Closed
surma opened this issue Apr 5, 2020 · 3 comments
Closed

[js-api] No (easy) access to memory from imported function #1175

surma opened this issue Apr 5, 2020 · 3 comments

Comments

@surma
Copy link
Contributor

surma commented Apr 5, 2020

Here’s an excerpt from a project where I am loading a Wasm module that was written in AssemblyScript:

const instance = await WebAssembly.instantiate(module, {
  env: {
    abort(messagePtr, fileNamePtr, line, column) {
      const { buffer } = instance.exports.memory;

      const message = decodeString(buffer, messagePtr);
      const fileName = decodeString(buffer, fileNamePtr);
      console.log(`${fileName}:${line}:${column}${"\n"}${message}`);
    }
  }
});

The function abort() is an exception handler invoked by the AssemblyScript runtime and provides an error description, as well as a file name and position where the exception was thrown. The values for the strings are pointers into the module’s memory, so to decode them I need to access the instance’s memory. Here, I solved this by closing over the instance variable.

This workaround does not work if the module has a start function that ends up invoking abort(), as WebAssembly.instantiate wouldn’t have finished and so instance is still undefined. Additionally, this requires me to create new closures for every instance I create rather than being able to write a reusable function.

Proposal

What if imported function are always invoked with the invoking instance bound to this? This would enable me to write a reusable abort() function as follows:

function abort(messagePtr, fileNamePtr, line, column) {
  const { buffer } = this.exports.memory;

  const message = decodeString(buffer, messagePtr);
  const fileName = decodeString(buffer, fileNamePtr);
  console.log(`${fileName}:${line}:${column}${"\n"}${message}`);
}

const instance = await WebAssembly.instantiate(module, {
  env: {abort}
});

(cc @dcodeIO @RReverser as an FYI)

@RReverser
Copy link
Member

RReverser commented Apr 5, 2020

This workaround does not work if the module has a start function

FWIW this is a known and in some ways intentional limitation and the reason why almost everyone uses real _start export instead of a start section for non-trivial initializers, e.g. you might be interested in reading this old discussion on WASI spec or wasm-ld docs which use _start as the entry point for symbol garbage collection.

@dcodeIO
Copy link

dcodeIO commented Apr 5, 2020

Btw, AssemblyScript also supports an explicit _start function by compiling with --explicitStart for that reason, so the instantiation can return before memory is first accessed. Still an unfortunate workaround.

@rossberg
Copy link
Member

rossberg commented Aug 4, 2022

Closing as "won't fix", since it would require a proposal for change.

@rossberg rossberg closed this as completed Aug 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants