Skip to content

Fix: indirect calls missing host parameter for WASI functions #19

@arnoox

Description

@arnoox

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.rs
  • crates/herkos-core/src/codegen/instruction.rs
  • crates/herkos-core/src/codegen/function.rs

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions