Skip to content

feat: callback-driving adapter for P3 async fusion#95

Merged
avrabe merged 6 commits intomainfrom
fix/issue-92-reexporter-handle-tables
Apr 14, 2026
Merged

feat: callback-driving adapter for P3 async fusion#95
avrabe merged 6 commits intomainfrom
fix/issue-92-reexporter-handle-tables

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented Apr 13, 2026

Summary

Implements P3 async cross-component call fusion using a callback-driving adapter that runs entirely in core wasm — no canon lift/canon lower inside the fused component, no call_might_be_recursive trap.

The adapter drives the callee's [async-lift] + [callback] loop directly:

  1. Call [async-lift] entry → packed i32 (EXIT/WAIT/YIELD)
  2. Loop: if WAIT, call waitable-set-poll; call [callback] with event
  3. After EXIT, read result from task.return shim globals

Key changes

  • Callback-driving adapter (fact.rs): generates core wasm function that drives the async callback protocol
  • Task.return shims (lib.rs): in-module functions that store result values to globals, replacing canonical task.return
  • Per-site shim matching: maps each async function to its specific shim by original function name
  • Retptr support: handles the return-pointer convention for multi-value results
  • Cross-memory string copy: copies string results from callee to caller memory via cabi_realloc + memory.copy
  • Cleanup: removed dead AsyncLiftLower code path from component_wrap.rs
  • Handle tables (issue 3-component re-exporter resource chains: implement shim module approach #92): infrastructure for re-exporter resource chains (WIP)

Runtime results on stock wasmtime 41

prime 7      → 7 is prime           ✅
fibonacci 10 → fibonacci(10) = 55   ✅
factorial 5  → factorial(5) = 120   ✅
collatz 27   → collatz(27) = 111    ✅
analyze      → needs param copy     ❌ (string params not yet copied)

No wasmtime fork. No special flags beyond -W component-model-async=y.

Remaining

Test plan

  • 73/73 P2 runtime tests pass
  • P3 core module validates
  • P3 component validates with --features cm-async
  • P3 compute functions correct on stock wasmtime
  • P3 text functions (blocked on param cross-memory copy)

🤖 Generated with Claude Code

avrabe and others added 6 commits April 6, 2026 22:36
Complete handle table infrastructure:
- ht_new/ht_rep/ht_drop in linear memory for re-exporter components
- Function bodies re-rewritten to use ht_* for resource ops
- Component wrapper routes LocalResource through $ht_*_N exports
- Adapter uses ht_rep for caller extraction when caller has handle table
  (fixes handle escape from re-exporter→definer calls)

Status: "unknown handle index" error fixed (handle no longer escapes
to canonical resource table). Now hits "unreachable" trap — likely
an initialization or argument issue in the handle table functions.

73/73 runtime tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Replace the canon lift/lower approach with a core wasm adapter that
drives the callee's [async-lift] + [callback] loop directly. This
eliminates the component boundary for internal async calls, avoiding
call_might_be_recursive entirely.

The adapter protocol (from the canonical ABI spec):
1. Call [async-lift] entry -> packed i32 (EXIT/WAIT/YIELD)
2. Loop: if WAIT, call waitable-set-poll; call [callback] with event
3. After EXIT, retrieve result via host intrinsic

Merger: async adapter sites now resolved like sync sites.
Result retrieval stubbed pending host API finalization.

73/73 P2 runtime tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Fix task.return shim matching: use original function name (extracted
from callee component's core module imports) instead of type-based
matching. This correctly routes each async function to its own shim
globals.

Add retptr convention support: when the caller uses the return-pointer
convention (void return, extra param), write shim globals to the
retptr address in caller memory instead of pushing to stack.

All 4 P3 compute functions now produce correct results on stock
wasmtime 41 (no fork, no special flags beyond component-model-async):

  prime 7      -> 7 is prime
  fibonacci 10 -> fibonacci(10) = 55
  factorial 5  -> factorial(5) = 120
  collatz 27   -> collatz(27) = 111 steps

String-returning functions (analyze, search, etc.) still need
cross-memory string copy in the result path.

73/73 P2 runtime tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add cross-memory string copy for async adapter retptr results:
when the result is a (ptr, len) pair referencing callee memory,
the adapter allocates in caller memory via cabi_realloc and copies
the data with memory.copy.

Remove the dead AsyncLiftLower code path from component_wrap.rs.
Async imports are now fully handled by the callback-driving adapter
in core wasm — no canon lift/lower needed inside the component.

73/73 P2 runtime tests pass. P3 compute functions correct on
stock wasmtime.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1. --validate now supports component output format (enables
   COMPONENT_MODEL, CM_ASYNC, MULTI_MEMORY features in validator)
2. --emit-import-map includes 'kind' field classifying each import
   as 'p3-builtin', 'resource', 'wasi', or 'function'
3. Downgrade UNMAPPED func import messages from warn to debug
   (cosmetic noise from indirect table stubs)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@avrabe avrabe merged commit 7526a64 into main Apr 14, 2026
4 checks passed
@avrabe avrabe deleted the fix/issue-92-reexporter-handle-tables branch April 14, 2026 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant