Pause, and resume... and Scheme targeting wasm

Hello all :)


I was asked to redirect my query to this mailing list [0].

[0] https://github.com/WebAssembly/design/issues/1294

Like the title suggest I am working on a compiler for Scheme that
targets web assembly. I think the problem I face is more general.

It is independent of the frontend language, it is not even specific
to web assembly, in Linux there is select and epoll to solve the
problem I have.

The gist of the problem is:

> How to make efficient use of cpu and memory in the context of
> interactive application?

In the backend, that means somehow relying on select, epoll, kqueue,
or even io_uring (liburing).

Inside a web assembly module, there is no concept of file descriptor,
and no way to passively wait for an event happening outside the wasm
module.

That is the case, and the most common case targeted by web assembly
that is: interacting with the browser DOM (or a canvas inside the DOM)
or doing XHR.

Another common case for web assembly is calling from the JS VM to a
web assembly module that does some number crushing such as optimizing
a jpeg file or such. My informal proposal is not useful in that case.

In the case of a game or a Single Page Application, JS and web
assembly need to cooperate: web assembly need to yield back control to
JS side, so that the browser event loop can process events, and pass
any completed events to web assembly.

As far as I understand, at this stage, most likely the JS side, will
have control, and wake up web assembly at a given frequency to process
events and the "event loop" web assembly side will process those and
issue appropriate drawing instruction and register new io events.

Web assembly side, my problem is how to implement the event loop
without relying on a trampoline.

My current approach is to rely a continuation-passing-style (cps)
transformation and a trampoline. Every web assembly function returns
at least two values: pause, and a continuation callback.  If pause is
true, the continuation callback is saved in global mutable variable,
the trampoline function returns, and yields back control to JS side.
Otherwise, when pause is false, the continuation callback is called.

Note: The call stack inside trampoline, inside the wasm module is at
most one, so tail calls do not grow the stack.

IF I am not mistaken, there is an alternative approach that still
require a global cps to implement Scheme's call/cc, but given the formal
tail call proposal, and two new operations it would aleviate the
need for a trampoline to pause the wasm module:

   (call_with_pause (ref.func $myfunc))

will pause the wasm module, in other words save the current
environment and yield back control to js. JavaScript side, when the
wasm_module.resume function is called, it will unpause the wasm module
by calling $myfunc.

There is also `call_with_pause_indirect`. And prolly maybe, the tail
equivalent of those.

`select`-like function could be implemented with `call_with_pause`.

What do you think?

-

Amirouche ~ https://hyper.dev

Received on Monday, 17 May 2021 07:10:00 UTC