Skip to content

3-component re-exporter resource chains: implement shim module approach #92

@avrabe

Description

@avrabe

Context

Epic #69 has been extensively investigated across multiple sessions. 70/73 runtime tests pass. The remaining 3 fixtures (resource_floats, resource_with_lists, resource-import-and-export) are 3-component re-exporter chains that fuse successfully but crash at runtime.

Root cause (proven)

The re-exporter's generated code (wit-bindgen) has conflicting requirements for borrow params:

  1. Dereference: The code uses the value directly as a raw pointer (*(value as *const FloatRep)) — needs the REP
  2. Drop: Rust's Drop impl calls resource.drop(value) — needs a valid wasmtime HANDLE

With shared wasmtime resource types, these are incompatible: REPs are memory addresses (large), handles are sequential integers (small). No adapter-level fix can make one value serve both purposes.

Solution: Re-exporter shim module

Instead of trying to replicate canon lift/lower in the adapter, generate a proper shim module for re-exporter boundaries that preserves the component model's resource table semantics.

The shim module would:

  1. Export the re-exporter's functions with proper canon lift wrapping
  2. Handle borrow handle creation/destruction in the re-exporter's resource table
  3. Convert between the caller's and callee's resource representations
  4. Be instantiated as a separate core module within the P2 wrapper

This is the approach used by wit-component (the reference implementation) for re-exported resources.

Files to modify

  • merger.rs: Export re-exporter's internal functions from the fused module
  • resolver.rs: Skip adapter creation for re-exporter-targeted calls, mark them for shim handling
  • component_wrap.rs: Generate the shim module with canon lift/lower for re-exporter functions
  • lib.rs: Skip wire_adapter_indices for shim-handled calls

Key findings from investigation

  • resource.rep in the re-exporter is identity (the generated code doesn't call wasmtime's resource.rep)
  • The re-exporter stores inner handles from canon lower in FloatRep.inner — these must be memory addresses (from the re-exporter's resource table), not sequential integers
  • [method] functions extract inner handles via double indirection (struct field access); [static] functions forward reps directly from the stack — different indirection levels through the same 3→0 adapter
  • The cleanup path (function 417 → 353 → resource.drop) drops values via the imported type's resource.drop, which must receive valid handles

Related PRs

Labels

Epic #69, enhancement

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions