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

@@ -138,11 +138,8 @@ use anyhow::{anyhow, Context, Result};
use std::os::raw::{c_int, c_void};
use std::slice;
use std::{env, path::PathBuf};
use wasmtime::{Config, Engine, FuncType, Instance, Linker, Module, Store};
use wasmtime_wasi::{
sync::{Wasi, WasiCtxBuilder},
WasiCtx,
};
use wasmtime::{Config, Engine, Instance, Linker, Module, Store};
use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx};
pub type ExitCode = c_int;
pub const OK: ExitCode = 0;
@@ -372,7 +369,7 @@ fn to_exit_code<T>(result: impl Into<Result<T>>) -> ExitCode {
/// This structure contains the actual Rust implementation of the state required
/// to manage the Wasmtime engine between calls.
struct BenchState {
engine: Engine,
linker: Linker<HostState>,
compilation_timer: *mut u8,
compilation_start: extern "C" fn(*mut u8),
compilation_end: extern "C" fn(*mut u8),
@@ -381,7 +378,16 @@ struct BenchState {
instantiation_end: extern "C" fn(*mut u8),
make_wasi_cx: Box<dyn FnMut() -> Result<WasiCtx>>,
module: Option<Module>,
instance: Option<Instance>,
store_and_instance: Option<(Store<HostState>, Instance)>,
}
struct HostState {
wasi: WasiCtx,
#[cfg(feature = "wasi-nn")]
wasi_nn: wasmtime_wasi_nn::WasiNnCtx,
#[cfg(feature = "wasi-crypto")]
wasi_crypto: wasmtime_wasi_crypto::WasiCryptoCtx,
}
impl BenchState {
@@ -400,7 +406,8 @@ impl BenchState {
// NB: do not configure a code cache.
let mut config = Config::new();
config.wasm_simd(true);
Wasi::add_to_config(&mut config);
let engine = Engine::new(&config)?;
let mut linker = Linker::<HostState>::new(&engine);
// Define the benchmarking start/end functions.
let execution_timer = unsafe {
@@ -408,29 +415,25 @@ impl BenchState {
// are only ever called from a single thread.
UnsafeSendSync::new(execution_timer)
};
config.define_host_func(
"bench",
"start",
FuncType::new(vec![], vec![]),
move |_, _, _| {
execution_start(*execution_timer.get());
Ok(())
},
);
config.define_host_func(
"bench",
"end",
FuncType::new(vec![], vec![]),
move |_, _, _| {
execution_end(*execution_timer.get());
Ok(())
},
);
linker.func_wrap("bench", "start", move || {
execution_start(*execution_timer.get());
Ok(())
})?;
linker.func_wrap("bench", "end", move || {
execution_end(*execution_timer.get());
Ok(())
})?;
let engine = Engine::new(&config)?;
wasmtime_wasi::add_to_linker(&mut linker, |cx| &mut cx.wasi)?;
#[cfg(feature = "wasi-nn")]
wasmtime_wasi_nn::add_to_linker(&mut linker, |cx| &mut cx.wasi_nn)?;
#[cfg(feature = "wasi-crypto")]
wasmtime_wasi_crypto::add_to_linker(&mut linker, |cx| &mut cx.wasi_crypto)?;
Ok(Self {
engine,
linker,
compilation_timer,
compilation_start,
compilation_end,
@@ -439,7 +442,7 @@ impl BenchState {
instantiation_end,
make_wasi_cx: Box::new(make_wasi_cx) as _,
module: None,
instance: None,
store_and_instance: None,
})
}
@@ -450,7 +453,7 @@ impl BenchState {
);
(self.compilation_start)(self.compilation_timer);
let module = Module::from_binary(&self.engine, bytes)?;
let module = Module::from_binary(self.linker.engine(), bytes)?;
(self.compilation_end)(self.compilation_timer);
self.module = Some(module);
@@ -463,60 +466,34 @@ impl BenchState {
.as_ref()
.expect("compile the module before instantiating it");
let wasi_cx = (self.make_wasi_cx)().context("failed to create a WASI context")?;
let host = HostState {
wasi: (self.make_wasi_cx)().context("failed to create a WASI context")?,
#[cfg(feature = "wasi-nn")]
wasi_nn: wasmtime_wasi_nn::WasiNnCtx::new()?,
#[cfg(feature = "wasi-crypto")]
wasi_crypto: wasmtime_wasi_nn::WasiCryptoCtx::new(),
};
// NB: Start measuring instantiation time *after* we've created the WASI
// context, since that needs to do file I/O to setup
// stdin/stdout/stderr.
(self.instantiation_start)(self.instantiation_timer);
let store = Store::new(&self.engine);
assert!(Wasi::set_context(&store, wasi_cx).is_ok());
let linker = Linker::new(&store);
#[cfg(feature = "wasi-nn")]
{
use std::cell::RefCell;
use std::rc::Rc;
use wasmtime_wasi_nn::{WasiNn, WasiNnCtx};
let wasi_nn = WasiNn::new(linker.store(), Rc::new(RefCell::new(WasiNnCtx::new()?)));
wasi_nn.add_to_linker(&mut linker)?;
}
#[cfg(feature = "wasi-crypto")]
{
use std::cell::RefCell;
use std::rc::Rc;
use wasmtime_wasi_crypto::{
WasiCryptoAsymmetricCommon, WasiCryptoCommon, WasiCryptoCtx, WasiCryptoSignatures,
WasiCryptoSymmetric,
};
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)?;
}
let instance = linker.instantiate(&module)?;
let mut store = Store::new(self.linker.engine(), host);
let instance = self.linker.instantiate(&mut store, &module)?;
(self.instantiation_end)(self.instantiation_timer);
self.instance = Some(instance);
self.store_and_instance = Some((store, instance));
Ok(())
}
fn execute(&mut self) -> Result<()> {
let instance = self
.instance
let (mut store, instance) = self
.store_and_instance
.take()
.expect("instantiate the module before executing it");
let start_func = instance.get_typed_func::<(), ()>("_start")?;
match start_func.call(()) {
let start_func = instance.get_typed_func::<(), (), _>(&mut store, "_start")?;
match start_func.call(&mut store, ()) {
Ok(_) => Ok(()),
Err(trap) => {
// Since _start will likely return by using the system `exit` call, we must