Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Borrowing non-resource types #473

Closed
segeljakt opened this issue Mar 18, 2025 · 4 comments
Closed

Borrowing non-resource types #473

segeljakt opened this issue Mar 18, 2025 · 4 comments

Comments

@segeljakt
Copy link

Currently, resource types can be passed to a wasm component by reference with borrow<...>:

package my-package:my-world;
world my-world {
    export my-interface: interface {
        resource image;

        load-image: func(bytes: list<u8>) -> image;
        resize-image: func(self: borrow<image>, width:u32, height:u32) -> image;
        image-to-bytes: func(self: borrow<image>) -> list<u8>;
    }
}

According to the documentation, it is not possible to pass non-resource types by reference. Are there any plans of adding this feature? I found the repo https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md, but it seems to be archived.

I am using wasm components to implement filters for streaming applications and it would be nice if the filter could take the data by-reference to avoid copying:

package my-package:my-world;
world my-world {
    export my-interface: interface {
        filter: func(data: borrow<list<string>>) -> bool;
    }
}
@badeend
Copy link
Contributor

badeend commented Mar 18, 2025

it would be nice if the filter could take the data by-reference to avoid copying

I suspect there's some confusion due to the use of Rust's "borrowing" terminology. In Rust a "borrow" is generally implemented as a pointer to some memory. In the Component Model, "borrows" only apply to Resources, which from the components POV are just an opaque index into an table maintained by the host - out of reach from the guest. Similar to file descriptors in POSIX.

it is not possible to pass non-resource types by reference.

That's right. It's not possible to hand out direct memory references between components due to the shared nothing architecture, which is a pillar of the CM design and enabler for many other key features like sandboxing and "colorblind" async.

Are there any plans of adding this feature?

I'll defer to Luke for the definitive answer here, but I guess: No. If a particular parameter is too large to copy around between components at once, maybe streams or resources are a better fit?

@lukewagner
Copy link
Member

Agreed with @badeend that the main challenge with borrowing values in memory is that when the caller and callee are both wasm components, the callee necessarily has a disjoint linear memory from the caller and thus some sort of copy is necessary today. However, when the receiver of a value is the host, since the host can always see all of wasm's linear memory, even the plain function filter: func(data: list<string>) -> bool can be thought of as a "borrow" from the host's POV when the host defines filter. So if your use case is component-to-host or host-to-component, you might already have what you need in Preview 2.

But for achieving zero-copy in component-to-component scenarios, I think the following 2 steps are promising:

  1. Caller provided buffers question #369 discusses adding readable-buffer<T>/writable-buffer<T> types (sketch in this comment) which would have borrow-like lifetimes and where T can be any value type. These types can allow the host to achieve zero-copy in more-complex scenarios (e.g., wasi-i2c's transaction). However, component-to-component scenarios would still inevitably require the built-in buffer read/write operations to copy between linear memories.
  2. WAMR has a pretty neat extension to core wasm called shared-heaps that I think might solve some long-standing browser use cases too ("how do I efficiently access an arbitrary (not-mmap()-able) ArrayBuffer from core wasm w/o copying it into linear memory?") so I think it is a pretty compelling candidate for a new core wasm standards proposal. (It would have to be a core wasm proposal b/c it extends the basic semantics of linear memory.) I'm encouraging the folks who are using shared-heaps to present at a future wasm CG meeting, and I think they will before long. If something like shared-heaps was a standard core wasm feature, then I expect we could safely add the ability to map (as shared heaps) readable-buffer and writable-buffer and perhaps add a new readable-and-writable buffer type in a way that preserved shared-nothing-ness and virtualizability while still achieving zero-copy.

Lots of hypotheticals in there, and nothing imminent, but I thought I'd share the new ideas.

@segeljakt
Copy link
Author

Hi, thank you for the answers and sorry about the late response. The design decision now makes a lot of sense. The heaps are disjoint to enforce isolation.

I'll defer to Luke for the definitive answer here, but I guess: No. If a particular parameter is too large to copy around between components at once, maybe streams or resources are a better fit?

Are there any example yet of how to use streams and futures, or are these features not yet available? I found https://www.fermyon.com/blog/looking-ahead-to-wasip3 so far which shows how to use wasm components with HTTP.

@dicej
Copy link
Collaborator

dicej commented Mar 25, 2025

Are there any example yet of how to use streams and futures, or are these features not yet available? I found https://www.fermyon.com/blog/looking-ahead-to-wasip3 so far which shows how to use wasm components with HTTP.

Streams and futures are part of the async support being developed in this repo and incrementally upstreamed to the main Wasmtime repo. There aren't many examples yet besides what's in that blog post, but there are some tests you can look at, e.g.:

Both the implementation and the spec are still evolving, so I don't recommend doing anything serious with them yet, but feel free to experiment and provide feedback!

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

No branches or pull requests

4 participants