-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
When transpiling WebAssembly modules that use WASI imports, the generated code for call_indirect dispatch fails to compile — either host is not in scope, or the wrong number of arguments is passed.
Root Cause (3 related bugs)
Bug 1 — Wrong caller check in dispatch codegen
generate_call_indirect checks !info.func_imports.is_empty() (module-level) to decide whether to emit host in dispatch arms. This emits host even in functions that have no host parameter in scope because they don't directly call any imports.
Bug 2 — Missing needs_host propagation through call_indirect in IR builder
IrFunction.needs_host is set by function_calls_imports in assembly.rs, which only checks for direct CallImport instructions and imported global accesses. Functions that use call_indirect to dispatch to WASI functions are never given needs_host = true, so they don't receive a host parameter at all.
Bug 3 — Monolithic dispatch args
All arms of the call_indirect match share one argument string, but individual target functions may differ in whether they accept host.
Fix
Step 1 — Failing regression test
Add crates/herkos-tests/data/wat/indirect_call_import.wat and crates/herkos-tests/tests/indirect_call_import.rs to reproduce the bug: a module with a WASI import where $dispatcher uses call_indirect to reach $writer (which calls the import directly) — $dispatcher has no direct import call itself.
Step 2 — IR builder (assembly.rs)
Update function_calls_imports to return true for functions containing CallIndirect when the module has any imports. Pass has_imports = !module_info.func_imports.is_empty() at the call site in enrich_ir_functions.
Step 3 — Codegen (instruction.rs, function.rs)
Add caller_has_host: bool to generate_instruction_with_info, computed per-function in function.rs using the existing has_import_calls / has_global_import_access helpers. Thread it into generate_call_indirect.
Step 4 — Per-arm dispatch args (instruction.rs)
Replace the shared args_str in generate_call_indirect with per-arm generation: for each dispatch target look up ir_func.needs_host from info.ir_functions and build call args individually.
Files
crates/herkos-tests/data/wat/indirect_call_import.wat(new)crates/herkos-tests/tests/indirect_call_import.rs(new)crates/herkos-core/src/ir/builder/assembly.rscrates/herkos-core/src/codegen/instruction.rscrates/herkos-core/src/codegen/function.rs