use wasm_encoder::{BlockType, EntityType, Function, ImportSection, TypeSection, ValType};
pub(crate) const INTRINSIC_MODULE: &str = "$root";
const WAITABLE_SET_NEW: &str = "[waitable-set-new]";
const WAITABLE_JOIN: &str = "[waitable-join]";
const WAITABLE_SET_WAIT: &str = "[waitable-set-wait]";
const WAITABLE_SET_DROP: &str = "[waitable-set-drop]";
const SUBTASK_DROP: &str = "[subtask-drop]";
pub(crate) struct AsyncTypes {
pub waitable_new_ty: u32,
pub waitable_join_ty: u32,
pub waitable_wait_ty: u32,
pub void_i32_ty: u32,
}
pub(crate) struct AsyncFuncs {
pub waitable_new: u32,
pub waitable_join: u32,
pub waitable_wait: u32,
pub waitable_drop: u32,
pub subtask_drop: u32,
pub event_ptr: i32,
}
pub(crate) fn emit_types(types: &mut TypeSection, mut alloc_ty: impl FnMut() -> u32) -> AsyncTypes {
types.ty().function([], [ValType::I32]);
let waitable_new_ty = alloc_ty();
types.ty().function([ValType::I32, ValType::I32], []);
let waitable_join_ty = alloc_ty();
types
.ty()
.function([ValType::I32, ValType::I32], [ValType::I32]);
let waitable_wait_ty = alloc_ty();
types.ty().function([ValType::I32], []);
let void_i32_ty = alloc_ty();
AsyncTypes {
waitable_new_ty,
waitable_join_ty,
waitable_wait_ty,
void_i32_ty,
}
}
pub(crate) fn import_intrinsics(
imports: &mut ImportSection,
types: &AsyncTypes,
event_ptr: i32,
mut alloc_func: impl FnMut() -> u32,
) -> AsyncFuncs {
let mut import = |name: &str, ty: u32| -> u32 {
imports.import(INTRINSIC_MODULE, name, EntityType::Function(ty));
alloc_func()
};
let waitable_new = import(WAITABLE_SET_NEW, types.waitable_new_ty);
let waitable_join = import(WAITABLE_JOIN, types.waitable_join_ty);
let waitable_wait = import(WAITABLE_SET_WAIT, types.waitable_wait_ty);
let waitable_drop = import(WAITABLE_SET_DROP, types.void_i32_ty);
let subtask_drop = import(SUBTASK_DROP, types.void_i32_ty);
AsyncFuncs {
waitable_new,
waitable_join,
waitable_wait,
waitable_drop,
subtask_drop,
event_ptr,
}
}
pub(crate) fn emit_call_and_wait(
f: &mut Function,
hook_idx: u32,
st: u32,
ws: u32,
art: &AsyncFuncs,
) {
f.instructions().call(hook_idx);
f.instructions().local_set(st);
emit_wait_loop(f, st, ws, art);
}
pub(crate) fn emit_wait_loop(f: &mut Function, st: u32, ws: u32, art: &AsyncFuncs) {
f.instructions().local_get(st);
f.instructions().i32_const(4);
f.instructions().i32_shr_u();
f.instructions().local_set(st);
f.instructions().local_get(st);
f.instructions().if_(BlockType::Empty);
f.instructions().call(art.waitable_new);
f.instructions().local_set(ws);
f.instructions().local_get(st);
f.instructions().local_get(ws);
f.instructions().call(art.waitable_join);
f.instructions().local_get(ws);
f.instructions().i32_const(art.event_ptr);
f.instructions().call(art.waitable_wait);
f.instructions().drop();
f.instructions().local_get(st);
f.instructions().call(art.subtask_drop);
f.instructions().local_get(ws);
f.instructions().call(art.waitable_drop);
f.instructions().end();
}