WebAssembly Coroutines
コルーチンとは
コルーチン(英: co-routine)とはプログラミングの構造の一種。サブルーチンがエントリーからリターンまでを一つの処理単位とするのに対し、コルーチンはいったん処理を中断した後、続きから処理を再開できる。接頭辞 co は協調を意味するが、複数のコルーチンが中断・継続により協調動作を行うことによる。
https://ja.wikipedia.org/wiki/コルーチン
https://mametter.hatenablog.com/entry/2019/03/27/211140
JavaScript だと(非対称)コルーチンが Generator Functions で実装することができる。
WebAssembly Coroutines
WebAssembly は最初の仕様が MVP だったため、コルーチンの機能は Future Features となっている。
https://github.com/WebAssembly/design/blob/master/FutureFeatures.md#coroutines
具体的な提案。これを使えば WebAssembly でも容易にコルーチンが実装できそう。
https://github.com/WebAssembly/stack-switching
今のところはまだそんな便利な命令はないため、実装にはコンパイル時に工夫が必要。
どう実装するか
愚直にトランスパイルする
Global や Memory にコルーチン内の変数を退避させ、さらに状態を指す変数を使って goto (switch) を実装すればよい。
code: (js)
function* generate() {
const a = 0;
const b = yield a;
yield b;
for (let i = 0; i < 5; ++i) {
yield i;
}
}
AssemblyScript Like な疑似コード
code: (ts)
let context: i32 = 0;
let a, b, i;
export function coroutine(next: i32): value: i32, done: boolean {
for (;;) {
switch (context) {
case 0:
a = 0;
context = 1;
return a, false;
case 1:
b = next;
context = 2;
return b, false;
case 2:
// loop init
i = 0;
case 3:
// loop end
if (!(i < 5)) {
context = 5;
break;
}
context = 4;
return i, false;
case 4:
++i;
context = 3;
break;
case 5:
return 0, true;
}
}
}
SharedArrayBuffer と Atomics API を使う
WebAssembly を Web Worker 内で起動し、一時停止したい部分で atomics.wait する。
absurd-sql がこの方法を使っている。
参考
facebook/regenerator
https://github.com/facebook/regenerator
コルーチンの実装を考える - Twitter
https://twitter.com/i/events/1041304658747088896
How to make coroutines in Wasm? - Stack Overflow
https://stackoverflow.com/questions/63443442/how-to-make-coroutines-in-wasm
A future for SQL on the web
https://jlongster.com/future-sql-web