-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Improving Instance::new
experience
#727
Comments
That builder looks pretty nice. The order you call each provides function will matter, since earlier calls take precedence over later calls. What if you wanted to load in an entire module (like a wasi module), but then override a specific import? Maybe we could let later calls to provide() override earlier calls? So you could do something like: let instance = Instance::builder(&module)
.provide_wasi_snapshot1(&Default::default())
.provide("wasi_snapshot_preview1", "environ_get", my_environ_get)
.build()?; Maybe a use case for this would be if you wanted to customize what data gets provided to the module (so in this example with If this behavior isn't wanted, perhaps all of the checking for duplicates could be deferred until impl InstanceBuilder {
// Does all the name resolution.
fn build(&mut self, allow_overrides: bool) -> Result<Instance>;
} let instance = Instance::builder(&module)
.provide("env", "add", |a: i32, b: i32| a + b)
.provide("env", "add", |a: i32, b: i32| a + b)
.build(false)?; // returns `Err` |
Yeah that was one case I was worried about, and I was thinking we'd just panic for now to be conservative if any imports look like they overlap one way or another. |
I really like this proposal! This would substantially simplify embedding and providing functions, both by taking all the necessary information from the function itself, and by automatically handling type mismatches in arguments. (We'll need some more advanced approaches to create an Regarding duplicates, in the short term I'd suggest returning an error for duplicate exports, and perhaps providing a function to explicitly delete or replace an export by name if you want to intentionally override one. |
To address @eminence 's question about being able to override individual syscalls, what about the concept of middleware? In other words, inside the builder you can add a middleware trait object and it will get invoked before and potentially after each call (in either direction). This way we could choose to completely override/block a syscall, or we could add additional functionality, logging, tracing, etc. Maybe... let instance = Instance::builder()
.foo()
.something()
.with_middleware(FileBlocker::new())
.build()?; |
Sometimes, it is useful to have an escape hatch for resolving imports when instantiating modules. For example, wasm allows a module to import several functions with the same signature. I.e. something like this: (import "env" "print" (param i32))
(import "env" "print" (param i32 i32)) Another example, is that sometimes you want to have full control over resolving of imports. Basically, having something like |
This commit reimplements the `wasmtime-wasi` crate on top of the `wasmtime` API crate, instead of being placed on top of the `wasmtime-*` family of internal crates. The purpose here is to continue to exercise the API as well as avoid usage of internals wherever possible and instead use the safe API as much as possible. The `wasmtime-wasi` crate's API has been updated as part of this PR as well. The general outline of it is now: * Each module snapshot has a `WasiCtxBuilder`, `WasiCtx`, and `Wasi` type. * The `WasiCtx*` types are reexported from `wasi-common`. * The `Wasi` type is synthesized by the `wig` crate's procedural macro * The `Wasi` type exposes one constructor which takes a `Store` and a `WasiCtx`, and produces a `Wasi` * Each `Wasi` struct fields for all the exported functions in that wasi module. They're all public an they all have type `wasmtime::Func` * The `Wasi` type has a `get_export` method to fetch an struct field by name. The intention here is that we can continue to make progress on bytecodealliance#727 by integrating WASI construction into the `Instance::new` experience, but it requires everything to be part of the same system! The main oddity required by the `wasmtime-wasi` crate is that it needs access to the caller's `memory` export, if any. This is currently done with a bit of a hack and is expected to go away once interface types are more fully baked in.
* Reimplement `wasmtime-wasi` on top of `wasmtime` This commit reimplements the `wasmtime-wasi` crate on top of the `wasmtime` API crate, instead of being placed on top of the `wasmtime-*` family of internal crates. The purpose here is to continue to exercise the API as well as avoid usage of internals wherever possible and instead use the safe API as much as possible. The `wasmtime-wasi` crate's API has been updated as part of this PR as well. The general outline of it is now: * Each module snapshot has a `WasiCtxBuilder`, `WasiCtx`, and `Wasi` type. * The `WasiCtx*` types are reexported from `wasi-common`. * The `Wasi` type is synthesized by the `wig` crate's procedural macro * The `Wasi` type exposes one constructor which takes a `Store` and a `WasiCtx`, and produces a `Wasi` * Each `Wasi` struct fields for all the exported functions in that wasi module. They're all public an they all have type `wasmtime::Func` * The `Wasi` type has a `get_export` method to fetch an struct field by name. The intention here is that we can continue to make progress on #727 by integrating WASI construction into the `Instance::new` experience, but it requires everything to be part of the same system! The main oddity required by the `wasmtime-wasi` crate is that it needs access to the caller's `memory` export, if any. This is currently done with a bit of a hack and is expected to go away once interface types are more fully baked in. * Remove now no-longer-necessary APIs from `wasmtime` * rustfmt * Rename to from_abi
This commit adds a new type to the `wasmtime` crate, a `Linker`. This linker is intended to vastly simplify calling `Instance::new` by easily performing name resolution and incrementally defining state over time. The goal here is to start down a path of making linking wasm modules in `wasmtime` a first-class and ergonomic operation. This is highly likely to evolve over time and get tweaked through releases as we iterate towards a design well-suited for `wasmtime`, but this is intended to at least be the initial foundation for such functionality. This commit additionally also adds a C API for the linker and switches the existing linking examples to using this linker in both Rust and C. One piece of future work I'd like to tackle next is to integrate WASI into the `wasmtime` crate in a more first-class manner. This [`Linker`] type provides a great location to hook into the instantiation process to easily instantiate modules with WASI imports. That's a relatively large refactoring for now though and I figured it'd be best left for a different time. Closes bytecodealliance#727
I've posted a draft of this to #1384 |
* Add a `wasmtime::Linker` type This commit adds a new type to the `wasmtime` crate, a `Linker`. This linker is intended to vastly simplify calling `Instance::new` by easily performing name resolution and incrementally defining state over time. The goal here is to start down a path of making linking wasm modules in `wasmtime` a first-class and ergonomic operation. This is highly likely to evolve over time and get tweaked through releases as we iterate towards a design well-suited for `wasmtime`, but this is intended to at least be the initial foundation for such functionality. This commit additionally also adds a C API for the linker and switches the existing linking examples to using this linker in both Rust and C. One piece of future work I'd like to tackle next is to integrate WASI into the `wasmtime` crate in a more first-class manner. This [`Linker`] type provides a great location to hook into the instantiation process to easily instantiate modules with WASI imports. That's a relatively large refactoring for now though and I figured it'd be best left for a different time. Closes #727
I think this is a large enough proposal and change that I'd like to split this off of #708. This issue is specifically about improving the experience of using
Instance::new
, which currently looks like this:After #708 that will instead look like:
Somewhat radically, I would propose that this is actually what we want on
Instance
! The idea here is that the list ofexterns
is the same length of the list inmodule.imports()
, andexterns
line up 1:1 withmodule.imports()
.Now that being said this is a pretty bad API to use, and doesn't help instantiating things like WASI or dealing with name resolution at all. I think instead I think we should provide an API similar to the following (bikeshedding everything of course):
Generally the idea here is that we keep
Instance::new
as the "low level" API of instantiating a module. That's for use when name resolution won't cut it for one reason or another. Something likeInstanceBuilder
will allow providing lots of extensions, as necessary, for hooking into name resolution and such. That way usage might look like:The
Into<Extern>
part may be pretty tricky and still take some frobbing to get right. Super-long term I think it'd be awesome to do something like:(but that's naturally much further in the future)
The text was updated successfully, but these errors were encountered: