Design: async / promise support

Created on 7 Jan 2018  ·  7Comments  ·  Source: WebAssembly/design

Many JavaScript libraries are async and I have not seen that WebAssembly supports promises yet.
In order to easily write performant applications that leverage the JS ecosystem I'd suggest to add support of promises in imported functions.

For instance this should work:

const importObject = { 
  returnOneAsync: () => new Promise(done => done(1)) 
};
extern "C" int returnOneAsync();

int main(){
  int x = returnOneAsync(); // should suspend main until promise resolved.
  return x+x;
}

Most helpful comment

I think you misunderstand the computational model of the web. JavaScript isn't multi-threaded, so suspending a computation would halt the engine, and in fact the entire renderer hosting it. The page would freeze and no other code could run (other than separate workers). You'd need a way of reifying and later restoring continuations to make suspension fly, which is not something engines currently can do.

All 7 comments

Any support of JS promises would have to be part of the JS host bindings proposal.

But I'm afraid it cannot possibly work like your example suggests, since that would require C itself to understand async execution and suspension, which it doesn't. Also, there is nothing async in your example, it just creates a promise, so the equivalent code wouldn't even suspend in JS itself, but just produce a string like "[object Promise][object Promise]".

Also, there is nothing async in your example

Well, the value is not available until the eventloop processes the promise.
The idea is to suspend the execution of the webassembly engine until the value is available.
The provided example is of course very trivial. A more concrete example could be making a db query over the network: getAgeOf: (name) => db.find({name}).then(x=>x.age)

C itself to understand async execution and suspension, which it doesn't

That's incorrect. There are various coroutine implementations for C.
Furthermore LLVM-5.0 and upwards supports coroutines and async/await.

https://llvm.org/docs/Coroutines.html

And as an addendum to C++17 there is the coroutine-ts that has been implemented since clang-5.0.
There are couple of experimental libraries using it already:
https://github.com/lewissbaker/cppcoro#generator

Implementations of coroutines in C do not magically interoperate with JavaScript's event loop. Also, they usually rely on implementation-specific behaviour. To reliably and portably implement something like coroutines or async you'd need a form of delimited continuations in the language. The closest C has to offer is longjmp, which isn't enough and cannot currently be implemented in Wasm itself (with Emscripten, longjmp is implemented in JS with JS exceptions). Wasm cannot currently express suspension, although there are plans to add something along these lines eventually. C++ coroutines aren't standard yet and cannot be handled by Emscripten AFAICT.

I see where you are coming from.
I think I haven't expressed my idea well enough.
I'm not suggesting to to support coroutines nor promises in C/C++ or realise that in the wasm bytecode.

But I'm afraid it cannot possibly work like your example suggests, since that would require C itself to understand async execution and suspension, which it doesn't

Why do you think it is required for C to understand async execution?

What's the technical difficulty to suspend the wasm execution engine until the promise is resolved?

I understand that wasm is supposed to be ahead-of-time compiled to x86 but it does not mean you have no control over the flow of execution.
An common way to stop the execution is to use hardware interrupts and syscalls like ptrace; that's how debugger work. We know exactly which functions are imported and we could inject the appropriate (x86) opcodes to accomplish that. Although this will slowdown the execution of those functions - it wouldn't matter as we are waiting in those cases for the promise to resolve anyway.
That is how we implemented suspend/debug/resume in our LLVM based C++JIT/AoT.

I guess this issue should be filed in the host-bindings repo...

I think you misunderstand the computational model of the web. JavaScript isn't multi-threaded, so suspending a computation would halt the engine, and in fact the entire renderer hosting it. The page would freeze and no other code could run (other than separate workers). You'd need a way of reifying and later restoring continuations to make suspension fly, which is not something engines currently can do.

I think you misunderstand the computational model of the web. JavaScript isn't multi-threaded, so suspending a computation would halt the engine, and in fact the entire renderer hosting it. The page would freeze and no other code could run (other than separate workers). You'd need a way of reifying and later restoring continuations to make suspension fly, which is not something engines currently can do.

Exactly, wasm should be run inside workers as they both created for computation tasks rather than dealing with UI.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  ·  7Comments

cretz picture cretz  ·  5Comments

arunetm picture arunetm  ·  7Comments

jfbastien picture jfbastien  ·  6Comments

badumt55 picture badumt55  ·  8Comments