Implement RFC 11: Redesigning Wasmtime's APIs (#2897)

Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
This commit is contained in:
Alex Crichton
2021-06-03 09:10:53 -05:00
committed by GitHub
parent a5a28b1c5b
commit 7a1b7cdf92
233 changed files with 13349 additions and 11997 deletions

View File

@@ -128,10 +128,10 @@ mod test {
let engine = Engine::default();
let contents = std::fs::read(output_path)?;
let module = unsafe { Module::deserialize(&engine, contents)? };
let store = Store::new(&engine);
let instance = Instance::new(&store, &module, &[])?;
let f = instance.get_typed_func::<i32, i32>("f")?;
assert_eq!(f.call(1234).unwrap(), 1234);
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let f = instance.get_typed_func::<i32, i32, _>(&mut store, "f")?;
assert_eq!(f.call(&mut store, 1234).unwrap(), 1234);
Ok(())
}

View File

@@ -1,7 +1,7 @@
//! The module that implements the `wasmtime run` command.
use crate::{CommonOptions, WasiModules};
use anyhow::{bail, Context as _, Result};
use anyhow::{anyhow, bail, Context as _, Result};
use std::thread;
use std::time::Duration;
use std::{
@@ -11,16 +11,13 @@ use std::{
};
use structopt::{clap::AppSettings, StructOpt};
use wasmtime::{Engine, Func, Linker, Module, Store, Trap, Val, ValType};
use wasmtime_wasi::sync::{Dir, Wasi, WasiCtxBuilder};
use wasmtime_wasi::sync::{Dir, WasiCtxBuilder};
#[cfg(feature = "wasi-nn")]
use wasmtime_wasi_nn::{WasiNn, WasiNnCtx};
use wasmtime_wasi_nn::WasiNnCtx;
#[cfg(feature = "wasi-crypto")]
use wasmtime_wasi_crypto::{
WasiCryptoAsymmetricCommon, WasiCryptoCommon, WasiCryptoCtx, WasiCryptoSignatures,
WasiCryptoSymmetric,
};
use wasmtime_wasi_crypto::WasiCryptoCtx;
fn parse_module(s: &OsStr) -> Result<PathBuf, OsString> {
// Do not accept wasmtime subcommand names as the module name
@@ -140,16 +137,17 @@ impl RunCommand {
config.interruptable(true);
}
let engine = Engine::new(&config)?;
let store = Store::new(&engine);
let mut store = Store::new(&engine, Host::default());
// Make wasi available by default.
let preopen_dirs = self.compute_preopen_dirs()?;
let argv = self.compute_argv();
let mut linker = Linker::new(&store);
let mut linker = Linker::new(&engine);
linker.allow_unknown_exports(self.allow_unknown_exports);
populate_with_wasi(
&mut store,
&mut linker,
preopen_dirs,
&argv,
@@ -163,7 +161,7 @@ impl RunCommand {
let module = Module::from_file(&engine, path)?;
// Add the module's functions to the linker.
linker.module(name, &module).context(format!(
linker.module(&mut store, name, &module).context(format!(
"failed to process preload `{}` at `{}`",
name,
path.display()
@@ -172,7 +170,7 @@ impl RunCommand {
// Load the main wasm module.
match self
.load_main_module(&mut linker)
.load_main_module(&mut store, &mut linker)
.with_context(|| format!("failed to run main module `{}`", self.module.display()))
{
Ok(()) => (),
@@ -256,9 +254,9 @@ impl RunCommand {
result
}
fn load_main_module(&self, linker: &mut Linker) -> Result<()> {
fn load_main_module(&self, store: &mut Store<Host>, linker: &mut Linker<Host>) -> Result<()> {
if let Some(timeout) = self.wasm_timeout {
let handle = linker.store().interrupt_handle()?;
let handle = store.interrupt_handle()?;
thread::spawn(move || {
thread::sleep(timeout);
handle.interrupt();
@@ -267,30 +265,39 @@ impl RunCommand {
// Read the wasm module binary either as `*.wat` or a raw binary.
// Use "" as a default module name.
let module = Module::from_file(linker.store().engine(), &self.module)?;
let module = Module::from_file(linker.engine(), &self.module)?;
linker
.module("", &module)
.module(&mut *store, "", &module)
.context(format!("failed to instantiate {:?}", self.module))?;
// If a function to invoke was given, invoke it.
if let Some(name) = self.invoke.as_ref() {
self.invoke_export(linker, name)
self.invoke_export(store, linker, name)
} else {
let func = linker.get_default("")?;
self.invoke_func(func, None)
let func = linker.get_default(&mut *store, "")?;
self.invoke_func(store, func, None)
}
}
fn invoke_export(&self, linker: &Linker, name: &str) -> Result<()> {
let func = match linker.get_one_by_name("", Some(name))?.into_func() {
fn invoke_export(
&self,
store: &mut Store<Host>,
linker: &Linker<Host>,
name: &str,
) -> Result<()> {
let func = match linker
.get(&mut *store, "", Some(name))
.ok_or_else(|| anyhow!("no export named `{}` found", name))?
.into_func()
{
Some(func) => func,
None => bail!("export of `{}` wasn't a function", name),
};
self.invoke_func(func, Some(name))
self.invoke_func(store, func, Some(name))
}
fn invoke_func(&self, func: Func, name: Option<&str>) -> Result<()> {
let ty = func.ty();
fn invoke_func(&self, store: &mut Store<Host>, func: Func, name: Option<&str>) -> Result<()> {
let ty = func.ty(&store);
if ty.params().len() > 0 {
eprintln!(
"warning: using `--invoke` with a function that takes arguments \
@@ -324,7 +331,7 @@ impl RunCommand {
// Invoke the function and then afterwards print all the results that came
// out, if there are any.
let results = func.call(&values).with_context(|| {
let results = func.call(store, &values).with_context(|| {
if let Some(name) = name {
format!("failed to invoke `{}`", name)
} else {
@@ -354,24 +361,34 @@ impl RunCommand {
}
}
#[derive(Default)]
struct Host {
wasi: Option<wasmtime_wasi::WasiCtx>,
#[cfg(feature = "wasi-nn")]
wasi_nn: Option<WasiNnCtx>,
#[cfg(feature = "wasi-crypto")]
wasi_crypto: Option<WasiCryptoCtx>,
}
/// Populates the given `Linker` with WASI APIs.
fn populate_with_wasi(
linker: &mut Linker,
store: &mut Store<Host>,
linker: &mut Linker<Host>,
preopen_dirs: Vec<(String, Dir)>,
argv: &[String],
vars: &[(String, String)],
wasi_modules: &WasiModules,
) -> Result<()> {
// Add the current snapshot to the linker.
let mut builder = WasiCtxBuilder::new();
builder = builder.inherit_stdio().args(argv)?.envs(vars)?;
for (name, dir) in preopen_dirs.into_iter() {
builder = builder.preopened_dir(dir, name)?;
}
if wasi_modules.wasi_common {
Wasi::new(linker.store(), builder.build()).add_to_linker(linker)?;
wasmtime_wasi::add_to_linker(linker, |host| host.wasi.as_mut().unwrap())?;
let mut builder = WasiCtxBuilder::new();
builder = builder.inherit_stdio().args(argv)?.envs(vars)?;
for (name, dir) in preopen_dirs.into_iter() {
builder = builder.preopened_dir(dir, name)?;
}
store.data_mut().wasi = Some(builder.build());
}
if wasi_modules.wasi_nn {
@@ -381,10 +398,8 @@ fn populate_with_wasi(
}
#[cfg(feature = "wasi-nn")]
{
use std::cell::RefCell;
use std::rc::Rc;
let wasi_nn = WasiNn::new(linker.store(), Rc::new(RefCell::new(WasiNnCtx::new()?)));
wasi_nn.add_to_linker(linker)?;
wasmtime_wasi_nn::add_to_linker(linker, |host| host.wasi_nn.as_mut().unwrap())?;
store.data_mut().wasi_nn = Some(WasiNnCtx::new()?);
}
}
@@ -395,14 +410,8 @@ fn populate_with_wasi(
}
#[cfg(feature = "wasi-crypto")]
{
use std::cell::RefCell;
use std::rc::Rc;
let cx_crypto = Rc::new(RefCell::new(WasiCryptoCtx::new()));
WasiCryptoCommon::new(linker.store(), cx_crypto.clone()).add_to_linker(linker)?;
WasiCryptoAsymmetricCommon::new(linker.store(), cx_crypto.clone())
.add_to_linker(linker)?;
WasiCryptoSignatures::new(linker.store(), cx_crypto.clone()).add_to_linker(linker)?;
WasiCryptoSymmetric::new(linker.store(), cx_crypto).add_to_linker(linker)?;
wasmtime_wasi_crypto::add_to_linker(linker, |host| host.wasi_crypto.as_mut().unwrap())?;
store.data_mut().wasi_crypto = Some(WasiCryptoCtx::new());
}
}

View File

@@ -36,7 +36,7 @@ impl WastCommand {
self.common.init_logging();
let config = self.common.config(None)?;
let store = Store::new(&Engine::new(&config)?);
let store = Store::new(&Engine::new(&config)?, ());
let mut wast_context = WastContext::new(store);
wast_context