bytecodealliance / wasmtime

A fast and secure runtime for WebAssembly
https://wasmtime.dev/
Apache License 2.0
15.09k stars 1.26k forks source link

wasi-common / wiggle support for disjoint host/guest memory #7776

Open juntyr opened 7 months ago

juntyr commented 7 months ago

I am running WASI code in Wasmtime and the browser and am trying to reuse my WasiCtx implementation for both. While the Wasmtime host can access the guest's memory, which wiggle exposes by requiring a GuestMemory::base method implementation. In my browser use case, however, the "host" runs inside WASM itself and launches new guests as separate WASM instances. The backing memory for each instance, an ArrayBuffer, is disjoint, so any memory transfer has to go through copying read and write calls.

Feature

Would it be (or is it already) possible to generalise the GuestMemory trait to allow for guest memory implementations which are disjoint? If the GuestMemory::base method is required by current Wasmtime(-adjacen) code, it could be moved into an extension trait implemented by all current implementations.

Benefit

This more general approach would allow further code reuse even on platforms where the WASM host cannot directly access a guest's memory.

Thank you for your help!

juntyr commented 7 months ago

It seems like GuestSlice also assumes that the host has direct access to the guest as it implements Deref (and GuestSliceMut implements DerefMut). This seems to be a bigger issue as other uses of base() (mainly the primitive read and write implementations) can naturally also be implemented using only reads and writes.

alexcrichton commented 7 months ago

Unfortunately the traits now I think are really closely tied to everything being in the same address space. Updating the trait would be a significant refactoring to the internals of wiggle and wasi-common I suspect. This is also an area of the project we're not investing a ton of time and effort in to right now since it's part of the now-dated wasi-common crate and preview1 where we've sinced largely moved on to preview2 and the wasmtime-wasi crate.

If you're interested to game out the change that's ok, but if it's a significant refactoring it may be somewhat difficult to land.

juntyr commented 7 months ago

Thank you for your response! I tried to hack together a workaround using an intermediary copy buffer that translates device memory into short-lived (per each syscall) host copies that are reflected back to the guest (the same idea that the original WASI polyfill was based on). While https://github.com/rust-lang/rust/pull/119616 is being worked on, this should provide a useful workaround.

For the future, are there plans to provide some common WASI implementation primitives that can also be used with other runtimes? For instance, most host implementations for the preview-2 components could reside in a new wasi-common crate and be re-exported in wasmtime-wasi (which would also add Wasmtime-specific plumbing to link in these implementations). This would be extremely helpful in use cases such as mine where a different runtime is needed for different targets but I want to (1) reuse most components (2) control a few components (e.g. clock and RNG for full reproducibility) and (3) share as much of this implementation as possible.

Thank you again for your time and help and keep up your fantastic work!

alexcrichton commented 7 months ago

Right now we haven't really figured out the best way to do that. Currently the reusable abstraction layer is the WIT-generated traits. That's a good deal of surface area to implement, however, so it's likely not what you're looking for.

Beyond that it's difficult to build abstractions that keep it easy for us to actually keep working on the implementation as well as users not have to reimplement all of WASI.

All that to say it'd be something great to have, but isn't something we know what it looks like right now.

juntyr commented 7 months ago

GitHub's landing page recommendations just introduced me to https://github.com/bytecodealliance/WASI-Virt, which might be even more in the direction of what I'm looking for. What better way to achieve a fully reproducible WASI environment than to virtualise it and compile it into the module itself so that all/most (I usually still like printing to stdout) WASI calls are removed :D

Does it make sense to already move my pipeline to wasi-preview2? I'm compiling all WASM modules from Rust and have full control over their compilation, but since some use C dependencies that are compiled with the wasi-sdk (which seems to only just start to get preview-2 support), I'd probably compile to preview-1 for a while longer, then transform with the adapter, and then transform again with the virtualisation. Is this reasonably doable already?

pchickey commented 7 months ago

Yes, the workflow of compiling to preview 1, then turning that into a component using preview 2 with the component adapter is working now, for both pure Rust as well as using C dependencies compiled with wasi-sdk.

The preview 2 interfaces themselves are presently release candidates, but we consider wasmtime's implementations production ready. We expect the latest set of release candidates to be promoted to the release version of preview 2 at the upcoming WASI Subgroup meeting on Jan 25. Once that is complete, we will release wasmtime 17 and the rest of the tooling suite all supporting the released preview 2 interfaces, so you will be able to target stable interfaces there, rather than release candidates that have been changing about once a month.

Once you have a preview 2 component, wasi-virt may work for your use case. However, it is still very much under development and may not be complete and working for your use case. If it is not, and you require a totally deterministic implementation of preview 2, the wasmtime::component::bindgen tooling makes things much simpler than wiggle ever did for defining host implementations.

juntyr commented 7 months ago

That's really exciting, thank you so much for the preview of the timeline!

One current roadblock I just thought of for my usecase is that my WASM+WASI modules need to run both inside Wasmtime and the browser (right now I have a hacky WASI polyfill for the browser) and that I need to do some transformations on the WASM bytecode, for which I currently use walrus. Do you know if there is already a timeline for component model support in web browsers (I only just stumbled across jco)? Is there a walrus-like Rust library (even with less convenience functions) that allows me to re-implement the simple bytecode transformations (like NaN normalization and adding instruction counting) that I'm currently using?

In the future, most of my usecase will probably be covered by

pchickey commented 7 months ago

We believe that jco will provide support for the Component Model and WASI Preview 2 in the browser at some point soon. I don't think anyone can commit to an exact time line at the moment. The jco folks have focused hard on getting their node.js preview 2 implementation correct (conforming to the same test suite as wasmtime) for the past few months in order to show that the standard has two separate high quality implementations. With their focus freed up from making that milestone they will be able to devote time to the web embedding next, but I don't think anyone has assessed how much time they are spending on it and how much it needs in order to estimate exactly when that will be ready.