alexcrichton commented on Issue #727:
I've posted a draft of this to https://github.com/bytecodealliance/wasmtime/pull/1384
alexcrichton closed Issue #727:
I think this is a large enough proposal and change that I'd like to split this off of https://github.com/bytecodealliance/wasmtime/issues/708. This issue is specifically about improving the experience of using
Instance::new
, which currently looks like this:impl Instance { pub fn new( store: &HostRef<Store>, module: &HostRef<Module>, externs: &[Extern] ) -> Result<Instance>; }After #708 that will instead look like:
impl Instance { pub fn new(module: &Module, externs: &[Extern]) -> Result<Instance>; }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):
impl Instance { fn builder(module: &Module) -> InstanceBuilder; // ... } struct InstanceBuilder { ... } impl InstanceBuilder { // Provide an import by module/name, panics if `module` or `name` is taken fn provide(&mut self, module: &str, name: &str, item: impl Into<Extern>) -> &mut Self; // Hook up an entire instance under the name `module`. Panics if `module` already used fn provide_instance(&mut self, module: &str, instance: &Instance) -> &mut Self; // Provides `wasi_unstable` module fn provide_wasi_snapshot0(&mut self, config: &WasiSnapshot0Config) -> &mut Self; // Provides `wasi_snapshot_preview1` module fn provide_wasi_snapshot1(&mut self, config: &WasiSnapshot1Config) -> &mut Self; // Does all the name resolution. fn build(&mut self) -> Result<Instance>; }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:let module = ...; let instance = Instance::builder(&module) .provide_wasi_snapshot0(&Default::default()) .provide("my-custom-api", "add", |a: i32, b: i32| a + b) .build()?; // ...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:#[wasmtime::host_module] trait MyWasmHostModule { fn function1(&self); fn function2(&self, input: &str) -> String; } // generates ... // trait MyWasmHostModuleExt { ... } // impl MyWasmHostModuleExt for wasmtime::InstanceBuilder { // fn provide_my_wasm_host_module(&mut self, instance: impl MyWasmHostModule) // ... // } // } impl MyWasmHostModule for MyStruct { // ... } Instace::builder(&module) .provide_my_wasm_host_module(&MyStruct) .build()?;(but that's naturally much further in the future)
Last updated: Dec 23 2024 at 12:05 UTC