Merged
Conversation
Two targeted fixes for 3-component re-exporter resource chain correctness: 1. merger.rs: Change `.insert()` to `.entry().or_insert()` for resource_rep_by_component and resource_new_by_component maps. Re-exporter components have multiple [resource-rep/new] imports for the same resource name across different interfaces — the first mapping must be preserved. 2. resolver.rs: Change resource graph override to downgrade-only. The graph's `defines_resource()` returns true for re-exporters (they have ResourceRep), incorrectly upgrading callee_defines_resource from false back to true. Now the graph can only downgrade (true→false) when it has definitive evidence the component is NOT the definer, never upgrade (false→true). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Upgrade wasmparser, wasm-encoder, and wasmprinter from 0.230 to 0.246. This enables parsing of P3 (component model async) components that use task.return, async lift/lower, streams, futures, and other P3 builtins. API migration: - ImportSection::into_imports() replaces direct iteration - CM_FIXED_SIZE_LIST → CM_FIXED_LENGTH_LISTS - fixed_size_list() → fixed_length_list() - New enum variants: TypeRef::FuncExact, HeapType::Exact, CanonicalOption::Gc, ExternalKind::FuncExact, ComponentDefinedType::Map - Enable CM_ASYNC feature flag in validator P3 components are now parsed and their async features detected. Fusion correctly rejects them with a descriptive error listing each P3 feature used, pending full P3 async fusion support. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
P3 components with async canonical operations (task.return, context.get/set, waitable-set.*, waitable.join, task.cancel) now fuse to valid core modules and component wrappers. Parser: store async/callback in CanonicalOptions, add ~31 CanonicalEntry variants for P3 builtins, fix creates_core_func for all P3 entries. Resolver: extend canon import name mapping for P3 entries, handle [async-lift] prefixed exports. Adapter: use callee_type_idx for non-retptr adapters so body matches callee's i32 task handle return type. Lib: add P3 async widening wrappers in wire_adapter_indices — when caller expects i64 but adapter returns i32, a thin wrapper with i64.extend_i32_u bridges the gap. Correct index arithmetic places wrappers before adapters. Component wrapper: add TaskBuiltin import resolution with P3BuiltinOp enum, emit canon task.return/context.get/set/waitable-set.*/waitable.join/ task.cancel, propagate async/callback options on canon lift exports. Validated: P3 core module + component wrapper pass wasm-tools validate (--features cm-async). All 73 P2 runtime tests + 11 release tests pass. Known limitation: P3 async runtime requires task context bridging for internal cross-component calls (canon lower elimination removes subtask context). Tracked as follow-up. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
P3 async cross-component calls cannot be fused into direct adapter calls because canon lower creates subtask contexts that async machinery (task.return, waitable-set) requires. Without these contexts, task.return has no matching task at runtime. Fix: mark async adapter sites (is_async_lift) and skip them in: - merger: leave async imports unresolved (not mapped to target export) - adapter generator: emit unreachable stub instead of real adapter - wire_adapter_indices: skip wiring for async sites The component wrapper detects these unresolved async imports by checking for matching [async-lift] exports in the fused module, then generates: alias [async-lift] core func → canon lift async (callback, realloc) → canon lower → provide as import to fused instance Type matching uses flattened canonical ABI comparison (including retptr convention) to find the correct Lift entry across flattened components. Result: P3 components fuse to valid core modules AND valid components (wasm-tools validate --features cm-async passes). All P2 tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Make canon lower options conditional based on core type complexity: only add memory/realloc/encoding for functions with compound params. Note: runtime still traps due to wasmtime limitation — same-component canon lift + canon lower always produces AlwaysTrap (wasmtime-environ inline.rs:564). Fix requires nested component to separate lift/lower into different component instances. The structural output is valid per wasm-tools validate --features cm-async. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
task.return,context.get/set,waitable-set.*,waitable.join,task.cancel, and ~25 moreTaskBuiltinimport resolution)async/callbackcanonical options oncanon liftexportscanon lift async+canon lower(not fused into direct adapters)Architecture
P3 async cross-component calls are handled differently from P2 sync calls:
canon lower/canon liftonly handles data marshaling → replaced by direct adapter callcanon lowercreates a subtask context needed bytask.return→ preserved as component-level operationsThe fused core module still merges all functions/memories/tables, but async boundaries stay as
canon lift async (callback) → canon lowerin the wrapper.Known limitation: wasmtime runtime
The fused component validates with
wasm-tools validate --features cm-async, but wasmtime 41.0 traps at runtime with "degenerate component adapter called".Root cause: wasmtime-environ
inline.rs:564— whencanon liftandcanon loweruse the same component instance (options_lift.instance == options_lower.instance), wasmtime generates anAlwaysTrapinstead of a proper fused adapter. This is intentional for sync functions (same-instance lift+lower is a no-op) but incorrect for async (the lift creates a task context, the lower creates a blocking wrapper).Fix path: wrap async lifts in a nested component so
frame.instancediffers between lift and lower, bypassing the same-instance check. Alternatively, upstream wasmtime could special-case async lift+lower.Test plan
cargo test --package meld-core— all tests passcargo run --bin meld -- fuse /tmp/p3_cli.wasm -o /tmp/p3_fused.wasm— core module validatescargo run --bin meld -- fuse /tmp/p3_cli.wasm -o /tmp/p3_fused.wasm --component— component validates with--features cm-async🤖 Generated with Claude Code