From 99fa99d33b687d95fd791125aba059e30da98d6a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 15 May 2020 15:30:23 -0700 Subject: [PATCH] Factor out instance initialization with `NewInstance`. This also separates instantiation from initialization in a manner similar to https://github.com/bytecodealliance/lucet/pull/506. --- RELEASES.md | 8 +- crates/c-api/src/instance.rs | 7 +- .../test-programs/tests/wasm_tests/runtime.rs | 25 +- crates/wasmtime/src/externals.rs | 6 +- crates/wasmtime/src/func.rs | 14 +- crates/wasmtime/src/instance.rs | 263 +++++++++++++----- crates/wasmtime/src/lib.rs | 2 +- crates/wasmtime/src/linker.rs | 29 +- crates/wasmtime/src/runtime.rs | 2 +- crates/wast/src/wast.rs | 6 +- docs/lang-rust.md | 4 +- docs/wasm-wat.md | 2 +- examples/fib-debug/main.rs | 2 +- examples/gcd.rs | 2 +- examples/hello.rs | 2 +- examples/interrupt.rs | 2 +- examples/linking.rs | 4 +- examples/memory.rs | 2 +- examples/multi.rs | 2 +- examples/wasi/main.c | 23 +- examples/wasi/main.rs | 2 +- src/commands/run.rs | 28 +- tests/all/custom_signal_handler.rs | 13 +- tests/all/func.rs | 3 +- tests/all/globals.rs | 2 +- tests/all/iloop.rs | 8 +- tests/all/import_calling_export.rs | 7 +- tests/all/import_indexes.rs | 2 +- tests/all/invoke_func_via_table.rs | 4 +- tests/all/linker.rs | 4 +- tests/all/memory_creator.rs | 6 +- tests/all/stack_overflow.rs | 2 +- tests/all/traps.rs | 46 +-- tests/host_segfault.rs | 15 +- 34 files changed, 339 insertions(+), 210 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 80ce30aca387..93fd097a0616 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -8,10 +8,10 @@ Unreleased ### Added -* The [WASI commands and reactors ABI] is now supported. To use, create a - `Linker` instance with `wasmtime_wasi::wasi_linker`, and instantiate modules - with `Linker::instantiate_wasi_abi`. This will automatically run commands - and automatically initialize reactors. +* The [WASI commands and reactors ABI] is now supported. `Instance::new` and + `Linker::instantiate` now return a `NewInstance`; to perform initialization + and obtain the `Instance`, call `.start`, `.run_command`, or + `.init_reactor` on it as needed. [WASI commands and reactors ABI]: https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi diff --git a/crates/c-api/src/instance.rs b/crates/c-api/src/instance.rs index 6d528530d647..310b60e40611 100644 --- a/crates/c-api/src/instance.rs +++ b/crates/c-api/src/instance.rs @@ -3,7 +3,7 @@ use crate::{wasm_store_t, wasmtime_error_t, ExternHost}; use anyhow::Result; use std::cell::RefCell; use std::ptr; -use wasmtime::{Extern, HostRef, Instance, Store, Trap}; +use wasmtime::{Extern, HostRef, Instance, NewInstance, Store, Trap}; #[repr(C)] #[derive(Clone)] @@ -115,7 +115,7 @@ fn _wasmtime_instance_new( } pub fn handle_instantiate( - instance: Result, + instance: Result, instance_ptr: &mut *mut wasm_instance_t, trap_ptr: &mut *mut wasm_trap_t, ) -> Option> { @@ -123,6 +123,9 @@ pub fn handle_instantiate( *ptr = Box::into_raw(Box::new(val)) } + // Run the wasm start function. + let instance = instance.and_then(NewInstance::minimal_init); + match instance { Ok(instance) => { write(instance_ptr, wasm_instance_t::new(instance)); diff --git a/crates/test-programs/tests/wasm_tests/runtime.rs b/crates/test-programs/tests/wasm_tests/runtime.rs index 3162e2892e52..5ea87f2be80c 100644 --- a/crates/test-programs/tests/wasm_tests/runtime.rs +++ b/crates/test-programs/tests/wasm_tests/runtime.rs @@ -65,18 +65,19 @@ pub fn instantiate( }) .collect::, _>>()?; - let instance = Instance::new_wasi_abi(&module, &imports).context(format!( - "error while instantiating Wasm module '{}'", - bin_name, - ))?; - - // If `module` is a command, `Instance::new_wasi_abi` will run it and - // return `None`. If we get `Some`, it means `module` wasn't a command. - if instance.is_some() { - bail!("expected module to be a command with a \"_start\" function") - } - - Ok(()) + Instance::new(&module, &imports) + .and_then(|new_instance| new_instance.run_command(&[])) + .and_then(|results| { + if !results.is_empty() { + bail!("unexpected result values from command") + } else { + Ok(()) + } + }) + .context(format!( + "error while instantiating Wasm module '{}'", + bin_name, + )) } #[cfg(unix)] diff --git a/crates/wasmtime/src/externals.rs b/crates/wasmtime/src/externals.rs index d97ccb22f94e..8b2cc86401d5 100644 --- a/crates/wasmtime/src/externals.rs +++ b/crates/wasmtime/src/externals.rs @@ -665,7 +665,7 @@ impl Memory { /// let memory = Memory::new(&store, memory_ty); /// /// let module = Module::new(&store, "(module (memory (import \"\" \"\") 1))")?; - /// let instance = Instance::new(&module, &[memory.into()])?; + /// let instance = Instance::new(&module, &[memory.into()])?.init_reactor(&[])?; /// // ... /// # Ok(()) /// # } @@ -688,7 +688,7 @@ impl Memory { /// # fn main() -> anyhow::Result<()> { /// let store = Store::default(); /// let module = Module::new(&store, "(module (memory (export \"mem\") 1))")?; - /// let instance = Instance::new(&module, &[])?; + /// let instance = Instance::new(&module, &[])?.init_reactor(&[])?; /// let memory = instance.get_memory("mem").unwrap(); /// let ty = memory.ty(); /// assert_eq!(ty.limits().min(), 1); @@ -800,7 +800,7 @@ impl Memory { /// # fn main() -> anyhow::Result<()> { /// let store = Store::default(); /// let module = Module::new(&store, "(module (memory (export \"mem\") 1 2))")?; - /// let instance = Instance::new(&module, &[])?; + /// let instance = Instance::new(&module, &[])?.init_reactor(&[])?; /// let memory = instance.get_memory("mem").unwrap(); /// /// assert_eq!(memory.size(), 1); diff --git a/crates/wasmtime/src/func.rs b/crates/wasmtime/src/func.rs index 70bf2843bc76..fdfd3965529f 100644 --- a/crates/wasmtime/src/func.rs +++ b/crates/wasmtime/src/func.rs @@ -40,7 +40,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody}; /// # fn main() -> anyhow::Result<()> { /// let store = Store::default(); /// let module = Module::new(&store, r#"(module (func (export "foo")))"#)?; -/// let instance = Instance::new(&module, &[])?; +/// let instance = Instance::new(&module, &[])?.init_reactor(&[])?; /// let foo = instance.get_func("foo").expect("export wasn't a function"); /// /// // Work with `foo` as a `Func` at this point, such as calling it @@ -90,7 +90,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody}; /// i32.add)) /// "#, /// )?; -/// let instance = Instance::new(&module, &[add.into()])?; +/// let instance = Instance::new(&module, &[add.into()])?.init_reactor(&[])?; /// let call_add_twice = instance.get_func("call_add_twice").expect("export wasn't a function"); /// let call_add_twice = call_add_twice.get0::()?; /// @@ -131,7 +131,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody}; /// (start $start)) /// "#, /// )?; -/// let instance = Instance::new(&module, &[double.into()])?; +/// let instance = Instance::new(&module, &[double.into()])?.init_reactor(&[])?; /// // .. work with `instance` if necessary /// # Ok(()) /// # } @@ -344,7 +344,7 @@ impl Func { /// call $add)) /// "#, /// )?; - /// let instance = Instance::new(&module, &[add.into()])?; + /// let instance = Instance::new(&module, &[add.into()])?.init_reactor(&[])?; /// let foo = instance.get_func("foo").unwrap().get2::()?; /// assert_eq!(foo(1, 2)?, 3); /// # Ok(()) @@ -375,7 +375,7 @@ impl Func { /// call $add)) /// "#, /// )?; - /// let instance = Instance::new(&module, &[add.into()])?; + /// let instance = Instance::new(&module, &[add.into()])?.init_reactor(&[])?; /// let foo = instance.get_func("foo").unwrap().get2::()?; /// assert_eq!(foo(1, 2)?, 3); /// assert!(foo(i32::max_value(), 1).is_err()); @@ -408,7 +408,7 @@ impl Func { /// call $debug)) /// "#, /// )?; - /// let instance = Instance::new(&module, &[debug.into()])?; + /// let instance = Instance::new(&module, &[debug.into()])?.init_reactor(&[])?; /// let foo = instance.get_func("foo").unwrap().get0::<()>()?; /// foo()?; /// # Ok(()) @@ -464,7 +464,7 @@ impl Func { /// (data (i32.const 4) "Hello, world!")) /// "#, /// )?; - /// let instance = Instance::new(&module, &[log_str.into()])?; + /// let instance = Instance::new(&module, &[log_str.into()])?.init_reactor(&[])?; /// let foo = instance.get_func("foo").unwrap().get0::<()>()?; /// foo()?; /// # Ok(()) diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index c43e2d96c1a7..e05816d9d3f7 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -1,5 +1,5 @@ use crate::trampoline::StoreInstanceHandle; -use crate::{Export, Extern, Func, Global, Memory, Module, Store, Table, Trap}; +use crate::{Export, Extern, Func, Global, Memory, Module, Store, Table, Trap, Val}; use anyhow::{bail, Error, Result}; use std::any::Any; use std::mem; @@ -56,22 +56,6 @@ fn instantiate( } })?; - // If a start function is present, now that we've got our compiled - // instance we can invoke it. Make sure we use all the trap-handling - // configuration in `store` as well. - if let Some(start) = instance.module().start_func { - let f = match instance.lookup_by_declaration(&EntityIndex::Function(start)) { - wasmtime_runtime::Export::Function(f) => f, - _ => unreachable!(), // valid modules shouldn't hit this - }; - super::func::catch_traps(instance.vmctx_ptr(), store, || { - mem::transmute::< - *const VMFunctionBody, - unsafe extern "C" fn(*mut VMContext, *mut VMContext), - >(f.address)(f.vmctx, instance.vmctx_ptr()) - })?; - } - Ok(instance) } } @@ -99,54 +83,6 @@ pub struct Instance { } impl Instance { - /// Creates a new [`Instance`] from the previously compiled [`Module`] and - /// list of `imports` specified, similar to `Instance::new`, and performs - /// [WASI ABI initialization]: - /// - If the module is a command, the `_start` function is run and `None` - /// is returned. - /// - If the module is a reactor, the `_initialize` function is run and - /// the initialized `Instance` is returned. - /// - /// [WASI ABI initialization]: https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi - pub fn new_wasi_abi(module: &Module, imports: &[Extern]) -> Result, Error> { - let instance = Instance::new(module, imports)?; - - // Invoke the WASI start function of the instance, if one is present. - let command_start = instance.get_export("_start"); - let reactor_start = instance.get_export("_initialize"); - match (command_start, reactor_start) { - (Some(command_start), None) => { - if let Some(func) = command_start.into_func() { - func.get0::<()>()?()?; - - // For commands, we consume the instance after running the program. - Ok(None) - } else { - bail!("_start must be a function".to_owned()) - } - } - (None, Some(reactor_start)) => { - if let Some(func) = reactor_start.into_func() { - func.get0::<()>()?()?; - - // For reactors, we return the instance after running the initialization. - Ok(Some(instance)) - } else { - bail!("_initialize must be a function".to_owned()) - } - } - (None, None) => { - // Treat modules which don't declare themselves as commands or reactors as - // reactors which have no initialization to do. - Ok(Some(instance)) - } - (Some(_), Some(_)) => { - // Module declares to be both a command and a reactor. - bail!("Program cannot be both a command and a reactor".to_owned()) - } - } - } - /// Creates a new [`Instance`] from the previously compiled [`Module`] and /// list of `imports` specified. /// @@ -157,9 +93,11 @@ impl Instance { /// automatically run (if provided) and then the [`Instance`] will be /// returned. /// - /// Note that this function does not perform `WASI` ABI initialization - /// (eg. it does not run the `_start` or `_initialize` functions). To - /// perform them, use `new_wasi_abi` instead. + /// This method returns a `NewInstance`, which is an instance which has + /// been created, however it has not yet been initialized -- wasm and WASI + /// initialization functions that it may have have not been run yet. Use + /// the methods on `NewInstance` to run the initialization and return the + /// actual `Instance`. /// /// ## Providing Imports /// @@ -195,7 +133,7 @@ impl Instance { /// [inst]: https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation /// [issue]: https://github.com/bytecodealliance/wasmtime/issues/727 /// [`ExternType`]: crate::ExternType - pub fn new(module: &Module, imports: &[Extern]) -> Result { + pub fn new(module: &Module, imports: &[Extern]) -> Result { let store = module.store(); // For now we have a restriction that the `Store` that we're working @@ -223,9 +161,11 @@ impl Instance { Box::new(info), )?; - Ok(Instance { - handle, - module: module.clone(), + Ok(NewInstance { + instance: Instance { + handle, + module: module.clone(), + }, }) } @@ -291,3 +231,182 @@ impl Instance { self.get_export(name)?.into_global() } } + +/// A newly created instance which has not yet been initialized. These are +/// returned by `Instance::new`. Its methods consume the `NewInstance`, +/// perform initialization, and return the `Instance`. +pub struct NewInstance { + instance: Instance, +} + +impl NewInstance { + /// Run the instance's wasm start function (and not WASI ABI initialization). + /// + /// This is public as it's used by the C API, which doesn't expose the `NewInstance` + /// type and needs a way to internally run initialization on a plain `Instance`. + #[doc(hidden)] + pub fn minimal_init(self) -> Result { + let start_func = self.instance.handle.module().start_func; + let instance = self.instance; + let store = instance.store(); + + // If a start function is present, invoke it. Make sure we use all the + // trap-handling configuration in `store` as well. + if let Some(start) = start_func { + let f = match instance + .handle + .lookup_by_declaration(&EntityIndex::Function(start)) + { + wasmtime_runtime::Export::Function(f) => f, + _ => unreachable!(), // valid modules shouldn't hit this + }; + let vmctx_ptr = instance.handle.vmctx_ptr(); + unsafe { + super::func::catch_traps(vmctx_ptr, store, || { + mem::transmute::< + *const VMFunctionBody, + unsafe extern "C" fn(*mut VMContext, *mut VMContext), + >(f.address)(f.vmctx, vmctx_ptr) + })?; + } + } + + Ok(instance) + } + + /// Run the instance's wasm start function and, if applicable, perform + /// [WASI ABI initialization]: + /// - If the module is a command, the `_start` function is run and `None` + /// is returned. + /// - If the module is a reactor, the `_initialize` function is run and + /// the initialized `Instance` is returned. + /// + /// If you know you're expecting to run a command or a reactor specifically, + /// you can use `run_command` or `init_reactor` instead, which offer a + /// more streamlined API. + /// + /// For now, `params` must be an empty slice, and the results will always be empty. + /// In the future, this will be extended to support arguments and return values. + /// + /// [WASI ABI initialization]: https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi + pub fn start(self, params: &[Val]) -> Result { + let instance = self.minimal_init()?; + + match wasi_abi_exec_model(instance)? { + ExecModel::Command(func) => Ok(Started::Command(run_command(func, params)?)), + ExecModel::Reactor((maybe_func, instance)) => Ok(Started::Reactor(init_reactor( + maybe_func, params, instance, + )?)), + } + } + + /// Given a command instance, run it. If the instance is not a command, + /// return an error. + /// + /// A command is an instance which is expected to be called only once. + /// Accordingly, this function consumes the `Instance`. + pub fn run_command(self, params: &[Val]) -> Result> { + let instance = self.minimal_init()?; + + if let ExecModel::Command(func) = wasi_abi_exec_model(instance)? { + return run_command(func, params); + } + + bail!("`run_command` called on module which is not a command"); + } + + /// Given a reactor instance, initialize it. If the instance is not a reactor, + /// return an error. + /// + /// A reactor is an instance which is expected to be called any number of + /// times. Accordingly, this function returns the initialized `Instance` + /// so that its exports can be called. + pub fn init_reactor(self, params: &[Val]) -> Result { + let instance = self.minimal_init()?; + + if let ExecModel::Reactor((maybe_func, instance)) = wasi_abi_exec_model(instance)? { + return init_reactor(maybe_func, params, instance); + } + + bail!("`init_reactor` called on module which is not a reactor"); + } +} + +/// Modules can be interpreted either as commands (instance lifetime ends +/// when the start function returns) or reactor (instance persists). +enum ExecModel { + /// The instance is a command, and this is its start function. The + /// instance should be consumed. + Command(Func), + + /// The instance is a reactor, and this is its initialization function, + /// along with the instance itself, which should persist. + Reactor((Option, Instance)), +} + +/// Classify the given instance as either a command or reactor and return +/// the information needed to initialize it. +fn wasi_abi_exec_model(instance: Instance) -> Result { + // Invoke the WASI start function of the instance, if one is present. + let command_start = instance.get_export("_start"); + let reactor_start = instance.get_export("_initialize"); + match (command_start, reactor_start) { + (Some(command_start), None) => { + if let Some(func) = command_start.into_func() { + Ok(ExecModel::Command(func)) + } else { + bail!("_start must be a function") + } + } + (None, Some(reactor_start)) => { + if let Some(func) = reactor_start.into_func() { + Ok(ExecModel::Reactor((Some(func), instance))) + } else { + bail!("_initialize must be a function") + } + } + (None, None) => { + // Module declares neither of the recognized functions, so treat + // it as a reactor with no initialization function. + Ok(ExecModel::Reactor((None, instance))) + } + (Some(_), Some(_)) => { + // Module declares itself to be both a command and a reactor. + bail!("Program cannot be both a command and a reactor") + } + } +} + +/// The result of running WASI ABI initialization on a wasm module. +pub enum Started { + /// The module was a command; the instance was consumed and this `Started` + /// holds the return values. + Command(Box<[Val]>), + + /// The module was a reactor; this `Started` holds the instance. + Reactor(Instance), +} + +/// Utility for running commands. +fn run_command(func: Func, params: &[Val]) -> Result> { + if !params.is_empty() { + bail!("passing arguments to a WASI-ABI command is not supported yet"); + } + + func.get0::<()>()?()?; + + return Ok(Vec::new().into_boxed_slice()); +} + +/// Utility for initializing reactors. +fn init_reactor(maybe_func: Option, params: &[Val], instance: Instance) -> Result { + if !params.is_empty() { + bail!("passing arguments to a WASI-ABI reactor is not supported yet"); + } + + if let Some(func) = maybe_func { + func.get0::<()>()?()?; + } + + Ok(instance) +} diff --git a/crates/wasmtime/src/lib.rs b/crates/wasmtime/src/lib.rs index e08fbb15f990..6e67e37ecf73 100644 --- a/crates/wasmtime/src/lib.rs +++ b/crates/wasmtime/src/lib.rs @@ -26,7 +26,7 @@ mod values; pub use crate::externals::*; pub use crate::frame_info::FrameInfo; pub use crate::func::*; -pub use crate::instance::Instance; +pub use crate::instance::{Instance, NewInstance, Started}; pub use crate::linker::*; pub use crate::module::Module; pub use crate::r#ref::{ExternRef, HostRef}; diff --git a/crates/wasmtime/src/linker.rs b/crates/wasmtime/src/linker.rs index 72f3153f03ec..964d4ccd9b4f 100644 --- a/crates/wasmtime/src/linker.rs +++ b/crates/wasmtime/src/linker.rs @@ -1,5 +1,6 @@ use crate::{ - Extern, ExternType, Func, FuncType, GlobalType, ImportType, Instance, IntoFunc, Module, Store, + Extern, ExternType, Func, FuncType, GlobalType, ImportType, Instance, IntoFunc, Module, + NewInstance, Store, }; use anyhow::{anyhow, bail, Result}; use std::collections::hash_map::{Entry, HashMap}; @@ -243,7 +244,7 @@ impl Linker { /// // Instantiate a small instance... /// let wat = r#"(module (func (export "run") ))"#; /// let module = Module::new(&store, wat)?; - /// let instance = linker.instantiate(&module)?; + /// let instance = linker.instantiate(&module)?.init_reactor(&[])?; /// /// // ... and inform the linker that the name of this instance is /// // `instance1`. This defines the `instance1::run` name for our next @@ -341,20 +342,6 @@ impl Linker { idx } - /// Attempts to instantiate the `module` provided, similar to - /// `Linker::instantiate`, and performs [WASI ABI initialization]: - /// - If the module is a command, the `_start` function is run and `None` - /// is returned. - /// - If the module is a reactor, the `_initialize` function is run and - /// the initialized `Instance` is returned. - /// - /// [WASI ABI initialization]: https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi - pub fn instantiate_wasi_abi(&self, module: &Module) -> Result> { - let imports = self.compute_imports(module)?; - - Instance::new_wasi_abi(module, &imports) - } - /// Attempts to instantiate the `module` provided. /// /// This method will attempt to assemble a list of imports that correspond @@ -367,6 +354,12 @@ impl Linker { /// incorrect signature or if it was not prevoiusly defined then an error /// will be returned because the import can not be satisfied. /// + /// This method returns a `NewInstance`, which is an instance which has + /// been created, however it has not yet been initialized -- wasm and WASI + /// initialization functions that it may have have not been run yet. Use + /// the methods on `NewInstance` to run the initialization and return the + /// actual `Instance`. + /// /// # Errors /// /// This method can fail because an import may not be found, or because @@ -388,11 +381,11 @@ impl Linker { /// ) /// "#; /// let module = Module::new(&store, wat)?; - /// linker.instantiate(&module)?; + /// linker.instantiate(&module)?.init_reactor(&[])?; /// # Ok(()) /// # } /// ``` - pub fn instantiate(&self, module: &Module) -> Result { + pub fn instantiate(&self, module: &Module) -> Result { let imports = self.compute_imports(module)?; Instance::new(module, &imports) diff --git a/crates/wasmtime/src/runtime.rs b/crates/wasmtime/src/runtime.rs index 2ba9f2fc4b41..0bfec6350631 100644 --- a/crates/wasmtime/src/runtime.rs +++ b/crates/wasmtime/src/runtime.rs @@ -892,7 +892,7 @@ impl Store { /// let module = Module::new(&store, r#" /// (func (export "run") (loop br 0)) /// "#)?; - /// let instance = Instance::new(&module, &[])?; + /// let instance = Instance::new(&module, &[])?.init_reactor(&[])?; /// let run = instance /// .get_func("run") /// .ok_or(anyhow::format_err!("failed to find `run` function export"))? diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs index 5c3c2253111f..44c9491130b4 100644 --- a/crates/wast/src/wast.rs +++ b/crates/wast/src/wast.rs @@ -81,7 +81,11 @@ impl WastContext { fn instantiate(&mut self, module: &[u8]) -> Result> { let module = Module::new(&self.store, module)?; self.modules.push(module.clone()); - let instance = match self.linker.instantiate(&module) { + let instance = match self + .linker + .instantiate(&module) + .and_then(|instance| instance.init_reactor(&[])) + { Ok(i) => i, Err(e) => return e.downcast::().map(Outcome::Trap), }; diff --git a/docs/lang-rust.md b/docs/lang-rust.md index 85aef3dbefa7..3e76187fc84d 100644 --- a/docs/lang-rust.md +++ b/docs/lang-rust.md @@ -69,7 +69,7 @@ fn main() -> Result<(), Box> { // After we have a compiled `Module` we can then instantiate it, creating // an `Instance` which we can actually poke at functions on. - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; // The `Instance` gives us access to various exported functions and items, // which we access here to pull out our `answer` exported function and @@ -160,7 +160,7 @@ fn main() -> Result<(), Box> { // When instantiating the module we now need to provide the imports to the // instantiation process. This is the second slice argument, where each // entry in the slice must line up with the imports in the module. - let instance = Instance::new(&module, &[log.into(), double.into()])?; + let instance = Instance::new(&module, &[log.into(), double.into()])?.init_reactor(&[])?; let run = instance .get_func("run") diff --git a/docs/wasm-wat.md b/docs/wasm-wat.md index 0f9153771696..c3f1b13d896c 100644 --- a/docs/wasm-wat.md +++ b/docs/wasm-wat.md @@ -46,7 +46,7 @@ let wat = r#" i32.add)) "#; let module = Module::new(&store, wat)?; -let instance = Instance::new(&module, &[])?; +let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let add = instance.get_func("add").unwrap(); let add = add.get2::()?; println!("1 + 2 = {}", add(1, 2)?); diff --git a/examples/fib-debug/main.rs b/examples/fib-debug/main.rs index ff35b8c83c10..52e9d7431dfc 100644 --- a/examples/fib-debug/main.rs +++ b/examples/fib-debug/main.rs @@ -18,7 +18,7 @@ fn main() -> Result<()> { let engine = Engine::new(Config::new().debug_info(true)); let store = Store::new(&engine); let module = Module::from_file(&store, "target/wasm32-unknown-unknown/debug/fib.wasm")?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; // Invoke `fib` export let fib = instance diff --git a/examples/gcd.rs b/examples/gcd.rs index 067ab7b2dff8..e92a69924d87 100644 --- a/examples/gcd.rs +++ b/examples/gcd.rs @@ -12,7 +12,7 @@ fn main() -> Result<()> { // can instantiate it. let store = Store::default(); let module = Module::from_file(&store, "examples/gcd.wat")?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; // Invoke `gcd` export let gcd = instance diff --git a/examples/hello.rs b/examples/hello.rs index 00772b22eb01..f057b5d338e9 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -30,7 +30,7 @@ fn main() -> Result<()> { // Note that this is where the wasm `start` function, if any, would run. println!("Instantiating module..."); let imports = [hello_func.into()]; - let instance = Instance::new(&module, &imports)?; + let instance = Instance::new(&module, &imports)?.init_reactor(&[])?; // Next we poke around a bit to extract the `run` function from the module. println!("Extracting export..."); diff --git a/examples/interrupt.rs b/examples/interrupt.rs index 696d8a2d952d..e1e661c57279 100644 --- a/examples/interrupt.rs +++ b/examples/interrupt.rs @@ -15,7 +15,7 @@ fn main() -> Result<()> { // Compile and instantiate a small example with an infinite loop. let module = Module::from_file(&store, "examples/interrupt.wat")?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let run = instance .get_func("run") .ok_or(anyhow::format_err!("failed to find `run` function export"))? diff --git a/examples/linking.rs b/examples/linking.rs index 4f9548739e6c..52f03f559c54 100644 --- a/examples/linking.rs +++ b/examples/linking.rs @@ -21,11 +21,11 @@ fn main() -> Result<()> { // Instantiate our first module which only uses WASI, then register that // instance with the linker since the next linking will use it. - let linking2 = linker.instantiate(&linking2)?; + let linking2 = linker.instantiate(&linking2)?.init_reactor(&[])?; linker.instance("linking2", &linking2)?; // And with that we can perform the final link and the execute the module. - let linking1 = linker.instantiate(&linking1)?; + let linking1 = linker.instantiate(&linking1)?.init_reactor(&[])?; let run = linking1.get_func("run").unwrap(); let run = run.get0::<()>()?; run()?; diff --git a/examples/memory.rs b/examples/memory.rs index 6f952dbb21b1..62386f7a7195 100644 --- a/examples/memory.rs +++ b/examples/memory.rs @@ -14,7 +14,7 @@ fn main() -> Result<()> { // instance from the compiled module all in one go. let wasmtime_store = Store::default(); let module = Module::from_file(&wasmtime_store, "examples/memory.wat")?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; // Load up our exports from the instance let memory = instance diff --git a/examples/multi.rs b/examples/multi.rs index 2fe75b0311c1..b8c1fcd0b475 100644 --- a/examples/multi.rs +++ b/examples/multi.rs @@ -35,7 +35,7 @@ fn main() -> Result<()> { // Instantiate. println!("Instantiating module..."); - let instance = Instance::new(&module, &[callback_func.into()])?; + let instance = Instance::new(&module, &[callback_func.into()])?.init_reactor(&[])?; // Extract exports. println!("Extracting export..."); diff --git a/examples/wasi/main.c b/examples/wasi/main.c index 1226f94ce21f..0be9e3cf791b 100644 --- a/examples/wasi/main.c +++ b/examples/wasi/main.c @@ -91,32 +91,11 @@ int main() { wasm_instance_t *instance = NULL; error = wasmtime_instance_new(module, imports, import_types.size, &instance, &trap); if (instance == NULL) - exit_with_error("failed to instantiate", error, trap); + exit_with_error("failed to run command", error, trap); free(imports); wasm_importtype_vec_delete(&import_types); - // Lookup our `_start` export function - wasm_extern_vec_t externs; - wasm_instance_exports(instance, &externs); - wasm_exporttype_vec_t exports; - wasm_module_exports(module, &exports); - wasm_extern_t *start_extern = NULL; - for (int i = 0; i < exports.size; i++) { - const wasm_name_t *name = wasm_exporttype_name(exports.data[i]); - if (strncmp(name->data, "_start", name->size) == 0) - start_extern = externs.data[i]; - } - assert(start_extern); - wasm_func_t *start = wasm_extern_as_func(start_extern); - assert(start != NULL); - error = wasmtime_func_call(start, NULL, 0, NULL, 0, &trap); - if (error != NULL || trap != NULL) - exit_with_error("failed to call `_start`", error, trap); - // Clean up after ourselves at this point - wasm_exporttype_vec_delete(&exports); - wasm_extern_vec_delete(&externs); - wasm_instance_delete(instance); wasm_module_delete(module); wasm_store_delete(store); wasm_engine_delete(engine); diff --git a/examples/wasi/main.rs b/examples/wasi/main.rs index 41eff8078721..9ecd4f8febd8 100644 --- a/examples/wasi/main.rs +++ b/examples/wasi/main.rs @@ -16,7 +16,7 @@ fn main() -> Result<()> { let linker = wasi_linker(&store, &[], &[], &[])?; // Instantiate and run our module with the imports we've created. - let _instance = linker.instantiate_wasi_abi(&module)?; + let _instance = linker.instantiate(&module)?.run_command(&[])?; Ok(()) } diff --git a/src/commands/run.rs b/src/commands/run.rs index 59c30066d4a7..24aeb8bc3adf 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -12,7 +12,7 @@ use std::{ }; use structopt::{clap::AppSettings, StructOpt}; use wasi_common::preopen_dir; -use wasmtime::{Engine, Instance, Linker, Module, Store, Trap, Val, ValType}; +use wasmtime::{Engine, Instance, Linker, Module, Started, Store, Trap, Val, ValType}; use wasmtime_wasi::wasi_linker; fn parse_module(s: &OsStr) -> Result { @@ -141,15 +141,15 @@ impl RunCommand { for (name, path) in self.preloads.iter() { // Read the wasm module binary either as `*.wat` or a raw binary let module = Module::from_file(linker.store(), path)?; - let instance = linker - .instantiate_wasi_abi(&module) + let started = linker + .instantiate(&module) + .and_then(|new_instance| new_instance.start(&[])) .context(format!("failed to instantiate {:?}", path))?; // If it was a command, don't register it. - let instance = if let Some(instance) = instance { - instance - } else { - continue; + let instance = match started { + Started::Command(_) => continue, + Started::Reactor(instance) => instance, }; linker.instance(name, &instance).with_context(|| { @@ -257,16 +257,18 @@ impl RunCommand { // Read the wasm module binary either as `*.wat` or a raw binary let module = Module::from_file(linker.store(), &self.module)?; - let instance = linker - .instantiate_wasi_abi(&module) + let started = linker + .instantiate(&module) + .and_then(|new_instance| new_instance.start(&[])) .context(format!("failed to instantiate {:?}", self.module))?; // If a function to invoke was given, invoke it. if let Some(name) = self.invoke.as_ref() { - if let Some(instance) = instance { - self.invoke_export(instance, name) - } else { - bail!("Cannot invoke exports on a command after it has executed") + match started { + Started::Command(_) => { + bail!("Cannot invoke exports on a command after it has executed") + } + Started::Reactor(instance) => self.invoke_export(instance, name), } } else { Ok(()) diff --git a/tests/all/custom_signal_handler.rs b/tests/all/custom_signal_handler.rs index 990c2af3781b..ef2bb67d5c0e 100644 --- a/tests/all/custom_signal_handler.rs +++ b/tests/all/custom_signal_handler.rs @@ -91,7 +91,7 @@ mod tests { let engine = Engine::new(&Config::default()); let store = Store::new(&engine); let module = Module::new(&store, WAT1)?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let (base, length) = set_up_memory(&instance); unsafe { @@ -154,7 +154,7 @@ mod tests { // Set up multiple instances - let instance1 = Instance::new(&module, &[])?; + let instance1 = Instance::new(&module, &[])?.init_reactor(&[])?; let instance1_handler_triggered = Rc::new(AtomicBool::new(false)); unsafe { @@ -196,7 +196,9 @@ mod tests { ); } - let instance2 = Instance::new(&module, &[]).expect("failed to instantiate module"); + let instance2 = Instance::new(&module, &[]) + .and_then(|new_instance| new_instance.init_reactor(&[])) + .expect("failed to instantiate module"); let instance2_handler_triggered = Rc::new(AtomicBool::new(false)); unsafe { @@ -245,7 +247,7 @@ mod tests { // instance1 which defines 'read' let module1 = Module::new(&store, WAT1)?; - let instance1 = Instance::new(&module1, &[])?; + let instance1 = Instance::new(&module1, &[])?.init_reactor(&[])?; let (base1, length1) = set_up_memory(&instance1); unsafe { store.set_signal_handler(move |signum, siginfo, _| { @@ -259,7 +261,8 @@ mod tests { // instance2 which calls 'instance1.read' let module2 = Module::new(&store, WAT2)?; - let instance2 = Instance::new(&module2, &[instance1_read.into_extern()])?; + let instance2 = + Instance::new(&module2, &[instance1_read.into_extern()])?.init_reactor(&[])?; // since 'instance2.run' calls 'instance1.read' we need to set up the signal handler to handle // SIGSEGV originating from within the memory of instance1 unsafe { diff --git a/tests/all/func.rs b/tests/all/func.rs index 16da165bab56..0c91803d52c0 100644 --- a/tests/all/func.rs +++ b/tests/all/func.rs @@ -200,6 +200,7 @@ fn trap_import() -> Result<()> { &module, &[Func::wrap(&store, || -> Result<(), Trap> { Err(Trap::new("foo")) }).into()], ) + .and_then(|new_instance| new_instance.init_reactor(&[])) .err() .unwrap() .downcast::()?; @@ -272,7 +273,7 @@ fn get_from_module() -> anyhow::Result<()> { "#, )?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let f0 = instance.get_func("f0").unwrap(); assert!(f0.get0::<()>().is_ok()); assert!(f0.get0::().is_err()); diff --git a/tests/all/globals.rs b/tests/all/globals.rs index d0e6896c1b98..17089e80d922 100644 --- a/tests/all/globals.rs +++ b/tests/all/globals.rs @@ -69,7 +69,7 @@ fn use_after_drop() -> anyhow::Result<()> { (global (export "foo") (mut i32) (i32.const 100))) "#, )?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let g = instance.get_global("foo").unwrap(); assert_eq!(g.get().i32(), Some(100)); g.set(101.into())?; diff --git a/tests/all/iloop.rs b/tests/all/iloop.rs index abfe5e4b3de2..531ed513ed77 100644 --- a/tests/all/iloop.rs +++ b/tests/all/iloop.rs @@ -26,7 +26,7 @@ fn hugely_recursive_module(store: &Store) -> anyhow::Result { fn loops_interruptable() -> anyhow::Result<()> { let store = interruptable_store(); let module = Module::new(&store, r#"(func (export "loop") (loop br 0))"#)?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let iloop = instance.get_func("loop").unwrap().get0::<()>()?; store.interrupt_handle()?.interrupt(); let trap = iloop().unwrap_err(); @@ -39,7 +39,7 @@ fn functions_interruptable() -> anyhow::Result<()> { let store = interruptable_store(); let module = hugely_recursive_module(&store)?; let func = Func::wrap(&store, || {}); - let instance = Instance::new(&module, &[func.into()])?; + let instance = Instance::new(&module, &[func.into()])?.init_reactor(&[])?; let iloop = instance.get_func("loop").unwrap().get0::<()>()?; store.interrupt_handle()?.interrupt(); let trap = iloop().unwrap_err(); @@ -73,7 +73,7 @@ fn loop_interrupt_from_afar() -> anyhow::Result<()> { let func = Func::wrap(&store, || { HITS.fetch_add(1, SeqCst); }); - let instance = Instance::new(&module, &[func.into()])?; + let instance = Instance::new(&module, &[func.into()])?.init_reactor(&[])?; // Use the instance's interrupt handle to wait for it to enter the loop long // enough and then we signal an interrupt happens. @@ -109,7 +109,7 @@ fn function_interrupt_from_afar() -> anyhow::Result<()> { let func = Func::wrap(&store, || { HITS.fetch_add(1, SeqCst); }); - let instance = Instance::new(&module, &[func.into()])?; + let instance = Instance::new(&module, &[func.into()])?.init_reactor(&[])?; // Use the instance's interrupt handle to wait for it to enter the loop long // enough and then we signal an interrupt happens. diff --git a/tests/all/import_calling_export.rs b/tests/all/import_calling_export.rs index 7affdd8759bc..92791183c11a 100644 --- a/tests/all/import_calling_export.rs +++ b/tests/all/import_calling_export.rs @@ -39,8 +39,9 @@ fn test_import_calling_export() { ); let imports = vec![callback_func.into()]; - let instance = - Instance::new(&module, imports.as_slice()).expect("failed to instantiate module"); + let instance = Instance::new(&module, imports.as_slice()) + .and_then(|new_instance| new_instance.init_reactor(&[])) + .expect("failed to instantiate module"); let run_func = instance .get_func("run") @@ -80,7 +81,7 @@ fn test_returns_incorrect_type() -> Result<()> { ); let imports = vec![callback_func.into()]; - let instance = Instance::new(&module, imports.as_slice())?; + let instance = Instance::new(&module, imports.as_slice())?.init_reactor(&[])?; let run_func = instance .get_func("run") diff --git a/tests/all/import_indexes.rs b/tests/all/import_indexes.rs index d13d100a9f0f..d55905bf402e 100644 --- a/tests/all/import_indexes.rs +++ b/tests/all/import_indexes.rs @@ -41,7 +41,7 @@ fn same_import_names_still_distinct() -> anyhow::Result<()> { ) .into(), ]; - let instance = Instance::new(&module, &imports)?; + let instance = Instance::new(&module, &imports)?.init_reactor(&[])?; let func = instance.get_func("foo").unwrap(); let results = func.call(&[])?; diff --git a/tests/all/invoke_func_via_table.rs b/tests/all/invoke_func_via_table.rs index 8f59fb17d8d5..47fb49180e24 100644 --- a/tests/all/invoke_func_via_table.rs +++ b/tests/all/invoke_func_via_table.rs @@ -14,7 +14,9 @@ fn test_invoke_func_via_table() -> Result<()> { ) "#; let module = Module::new(&store, wat).context("> Error compiling module!")?; - let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?; + let instance = Instance::new(&module, &[]) + .and_then(|new_instance| new_instance.init_reactor(&[])) + .context("> Error instantiating module!")?; let f = instance .get_table("table") diff --git a/tests/all/linker.rs b/tests/all/linker.rs index b84d7e9c1d36..95d752bbb239 100644 --- a/tests/all/linker.rs +++ b/tests/all/linker.rs @@ -75,7 +75,7 @@ fn interposition() -> Result<()> { r#"(module (func (export "export") (result i32) (i32.const 7)))"#, )?; for _ in 0..4 { - let instance = linker.instantiate(&module)?; + let instance = linker.instantiate(&module)?.init_reactor(&[])?; linker.define( "red", "green", @@ -89,7 +89,7 @@ fn interposition() -> Result<()> { )"#, )?; } - let instance = linker.instantiate(&module)?; + let instance = linker.instantiate(&module)?.init_reactor(&[])?; let func = instance.get_func("export").unwrap(); let func = func.get0::()?; assert_eq!(func()?, 112); diff --git a/tests/all/memory_creator.rs b/tests/all/memory_creator.rs index 013b68b02f1e..cb25425c2c3d 100644 --- a/tests/all/memory_creator.rs +++ b/tests/all/memory_creator.rs @@ -150,7 +150,7 @@ mod not_for_windows { ) "#, )?; - Instance::new(&module, &[])?; + Instance::new(&module, &[])?.init_reactor(&[])?; assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 1); @@ -171,8 +171,8 @@ mod not_for_windows { "#, )?; - let instance1 = Instance::new(&module, &[])?; - let instance2 = Instance::new(&module, &[])?; + let instance1 = Instance::new(&module, &[])?.init_reactor(&[])?; + let instance2 = Instance::new(&module, &[])?.init_reactor(&[])?; assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 2); diff --git a/tests/all/stack_overflow.rs b/tests/all/stack_overflow.rs index 9d63dbdc4ca8..95179793037a 100644 --- a/tests/all/stack_overflow.rs +++ b/tests/all/stack_overflow.rs @@ -23,7 +23,7 @@ fn host_always_has_some_stack() -> anyhow::Result<()> { "#, )?; let func = Func::wrap(&store, test_host_stack); - let instance = Instance::new(&module, &[func.into()])?; + let instance = Instance::new(&module, &[func.into()])?.init_reactor(&[])?; let foo = instance.get_func("foo").unwrap().get0::<()>()?; // Make sure that our function traps and the trap says that the call stack diff --git a/tests/all/traps.rs b/tests/all/traps.rs index f4ae458f4804..8cd9ecce825a 100644 --- a/tests/all/traps.rs +++ b/tests/all/traps.rs @@ -16,7 +16,7 @@ fn test_trap_return() -> Result<()> { let hello_type = FuncType::new(Box::new([]), Box::new([])); let hello_func = Func::new(&store, hello_type, |_, _, _| Err(Trap::new("test 123"))); - let instance = Instance::new(&module, &[hello_func.into()])?; + let instance = Instance::new(&module, &[hello_func.into()])?.init_reactor(&[])?; let run_func = instance.get_func("run").expect("expected function export"); let e = run_func @@ -42,7 +42,7 @@ fn test_trap_trace() -> Result<()> { "#; let module = Module::new(&store, wat)?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let run_func = instance.get_func("run").expect("expected function export"); let e = run_func @@ -88,7 +88,7 @@ fn test_trap_trace_cb() -> Result<()> { let fn_func = Func::new(&store, fn_type, |_, _, _| Err(Trap::new("cb throw"))); let module = Module::new(&store, wat)?; - let instance = Instance::new(&module, &[fn_func.into()])?; + let instance = Instance::new(&module, &[fn_func.into()])?.init_reactor(&[])?; let run_func = instance.get_func("run").expect("expected function export"); let e = run_func @@ -119,7 +119,7 @@ fn test_trap_stack_overflow() -> Result<()> { "#; let module = Module::new(&store, wat)?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let run_func = instance.get_func("run").expect("expected function export"); let e = run_func @@ -154,7 +154,7 @@ fn trap_display_pretty() -> Result<()> { "#; let module = Module::new(&store, wat)?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let run_func = instance.get_func("bar").expect("expected function export"); let e = run_func.call(&[]).err().expect("error calling function"); @@ -186,7 +186,7 @@ fn trap_display_multi_module() -> Result<()> { "#; let module = Module::new(&store, wat)?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let bar = instance.get_export("bar").unwrap(); let wat = r#" @@ -197,7 +197,7 @@ fn trap_display_multi_module() -> Result<()> { ) "#; let module = Module::new(&store, wat)?; - let instance = Instance::new(&module, &[bar])?; + let instance = Instance::new(&module, &[bar])?.init_reactor(&[])?; let bar2 = instance.get_func("bar2").expect("expected function export"); let e = bar2.call(&[]).err().expect("error calling function"); @@ -233,7 +233,10 @@ fn trap_start_function_import() -> Result<()> { let module = Module::new(&store, &binary)?; let sig = FuncType::new(Box::new([]), Box::new([])); let func = Func::new(&store, sig, |_, _, _| Err(Trap::new("user trap"))); - let err = Instance::new(&module, &[func.into()]).err().unwrap(); + let err = Instance::new(&module, &[func.into()]) + .and_then(|new_instance| new_instance.init_reactor(&[])) + .err() + .unwrap(); assert_eq!(err.downcast_ref::().unwrap().message(), "user trap"); Ok(()) } @@ -262,7 +265,8 @@ fn rust_panic_import() -> Result<()> { func.into(), Func::wrap(&store, || panic!("this is another panic")).into(), ], - )?; + )? + .init_reactor(&[])?; let func = instance.get_func("foo").unwrap(); let err = panic::catch_unwind(AssertUnwindSafe(|| { drop(func.call(&[])); @@ -299,14 +303,20 @@ fn rust_panic_start_function() -> Result<()> { let sig = FuncType::new(Box::new([]), Box::new([])); let func = Func::new(&store, sig, |_, _, _| panic!("this is a panic")); let err = panic::catch_unwind(AssertUnwindSafe(|| { - drop(Instance::new(&module, &[func.into()])); + drop( + Instance::new(&module, &[func.into()]) + .and_then(|new_instance| new_instance.init_reactor(&[])), + ); })) .unwrap_err(); assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic")); let func = Func::wrap(&store, || panic!("this is another panic")); let err = panic::catch_unwind(AssertUnwindSafe(|| { - drop(Instance::new(&module, &[func.into()])); + drop( + Instance::new(&module, &[func.into()]) + .and_then(|new_instance| new_instance.init_reactor(&[])), + ); })) .unwrap_err(); assert_eq!( @@ -329,7 +339,7 @@ fn mismatched_arguments() -> Result<()> { )?; let module = Module::new(&store, &binary)?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let func = instance.get_func("foo").unwrap(); assert_eq!( func.call(&[]).unwrap_err().to_string(), @@ -369,6 +379,7 @@ fn call_signature_mismatch() -> Result<()> { let module = Module::new(&store, &binary)?; let err = Instance::new(&module, &[]) + .and_then(|new_instance| new_instance.init_reactor(&[])) .err() .unwrap() .downcast::() @@ -392,10 +403,11 @@ fn start_trap_pretty() -> Result<()> { "#; let module = Module::new(&store, wat)?; - let e = match Instance::new(&module, &[]) { - Ok(_) => panic!("expected failure"), - Err(e) => e.downcast::()?, - }; + let e = + match Instance::new(&module, &[]).and_then(|new_instance| new_instance.init_reactor(&[])) { + Ok(_) => panic!("expected failure"), + Err(e) => e.downcast::()?, + }; assert_eq!( e.to_string(), @@ -415,7 +427,7 @@ wasm backtrace: fn present_after_module_drop() -> Result<()> { let store = Store::default(); let module = Module::new(&store, r#"(func (export "foo") unreachable)"#)?; - let instance = Instance::new(&module, &[])?; + let instance = Instance::new(&module, &[])?.init_reactor(&[])?; let func = instance.get_func("foo").unwrap(); println!("asserting before we drop modules"); diff --git a/tests/host_segfault.rs b/tests/host_segfault.rs index 18849672873a..d190bb2c50df 100644 --- a/tests/host_segfault.rs +++ b/tests/host_segfault.rs @@ -50,20 +50,29 @@ fn main() { ("make instance then segfault", || { let store = Store::default(); let module = Module::new(&store, "(module)").unwrap(); - let _instance = Instance::new(&module, &[]).unwrap(); + let _instance = Instance::new(&module, &[]) + .unwrap() + .init_reactor(&[]) + .unwrap(); segfault(); }), ("make instance then overrun the stack", || { let store = Store::default(); let module = Module::new(&store, "(module)").unwrap(); - let _instance = Instance::new(&module, &[]).unwrap(); + let _instance = Instance::new(&module, &[]) + .unwrap() + .init_reactor(&[]) + .unwrap(); println!("stack overrun: {}", overrun_the_stack()); }), ("segfault in a host function", || { let store = Store::default(); let module = Module::new(&store, r#"(import "" "" (func)) (start 0)"#).unwrap(); let segfault = Func::wrap(&store, || segfault()); - Instance::new(&module, &[segfault.into()]).unwrap(); + Instance::new(&module, &[segfault.into()]) + .unwrap() + .init_reactor(&[]) + .unwrap(); }), ]; match env::var(VAR_NAME) {