Path: blob/main/crates/wizer/src/component/wasmtime.rs
2459 views
use crate::Wizer;1use crate::component::ComponentInstanceState;2use anyhow::{Context, anyhow};3use wasmtime::component::{4Component, ComponentExportIndex, Instance, Lift, WasmList, types::ComponentItem,5};6use wasmtime::{Result, Store};78impl Wizer {9/// Same as [`Wizer::run`], except for components.10pub async fn run_component<T: Send>(11&self,12store: &mut Store<T>,13wasm: &[u8],14instantiate: impl AsyncFnOnce(&mut Store<T>, &Component) -> Result<Instance>,15) -> anyhow::Result<Vec<u8>> {16let (cx, instrumented_wasm) = self.instrument_component(wasm)?;1718#[cfg(feature = "wasmprinter")]19log::debug!(20"instrumented wasm: {}",21wasmprinter::print_bytes(&instrumented_wasm)?,22);2324let engine = store.engine();25let component = Component::new(engine, &instrumented_wasm)26.context("failed to compile the Wasm component")?;27let index = self.validate_component_init_func(&component)?;2829let instance = instantiate(store, &component).await?;30self.initialize_component(store, &instance, index).await?;31self.snapshot_component(cx, &mut WasmtimeWizerComponent { store, instance })32.await33}3435fn validate_component_init_func(36&self,37component: &Component,38) -> anyhow::Result<ComponentExportIndex> {39let init_func = self.get_init_func();40let (ty, index) = component41.get_export(None, init_func)42.ok_or_else(|| anyhow!("the component does export the function `{init_func}`"))?;4344let ty = match ty {45ComponentItem::ComponentFunc(ty) => ty,46_ => anyhow::bail!("the component's `{init_func}` export is not a function",),47};4849if ty.params().len() != 0 || ty.results().len() != 0 {50anyhow::bail!(51"the component's `{init_func}` function export does not have type `[] -> []`",52);53}54Ok(index)55}5657async fn initialize_component<T: Send>(58&self,59store: &mut Store<T>,60instance: &Instance,61index: ComponentExportIndex,62) -> anyhow::Result<()> {63let init_func = instance64.get_typed_func::<(), ()>(&mut *store, index)65.expect("checked by `validate_init_func`");66init_func67.call_async(&mut *store, ())68.await69.with_context(|| format!("the initialization function trapped"))?;70init_func71.post_return_async(&mut *store)72.await73.context("failed to call post-return")?;7475Ok(())76}77}7879/// Impementation of [`InstanceState`] backed by Wasmtime.80pub struct WasmtimeWizerComponent<'a, T: 'static> {81/// The Wasmtime-based store that owns the `instance` field.82pub store: &'a mut Store<T>,83/// The instance that this will load state from.84pub instance: Instance,85}8687impl<T: Send> WasmtimeWizerComponent<'_, T> {88async fn call_func<R, R2>(89&mut self,90instance: &str,91func: &str,92use_ret: impl FnOnce(&mut Store<T>, R) -> R2,93) -> R294where95R: Lift + 'static,96{97log::debug!("invoking {instance}#{func}");98let (_, instance_export) = self99.instance100.get_export(&mut *self.store, None, instance)101.unwrap();102let (_, func_export) = self103.instance104.get_export(&mut *self.store, Some(&instance_export), func)105.unwrap();106let func = self107.instance108.get_typed_func::<(), (R,)>(&mut *self.store, func_export)109.unwrap();110let ret = func.call_async(&mut *self.store, ()).await.unwrap().0;111let ret = use_ret(&mut *self.store, ret);112func.post_return_async(&mut *self.store).await.unwrap();113ret114}115}116117impl<T: Send> ComponentInstanceState for WasmtimeWizerComponent<'_, T> {118async fn call_func_ret_list_u8(119&mut self,120instance: &str,121func: &str,122contents: impl FnOnce(&[u8]) + Send,123) {124self.call_func(instance, func, |store, list: WasmList<u8>| {125contents(list.as_le_slice(&store));126})127.await128}129130async fn call_func_ret_s32(&mut self, instance: &str, func: &str) -> i32 {131self.call_func(instance, func, |_, r| r).await132}133134async fn call_func_ret_s64(&mut self, instance: &str, func: &str) -> i64 {135self.call_func(instance, func, |_, r| r).await136}137138async fn call_func_ret_f32(&mut self, instance: &str, func: &str) -> u32 {139self.call_func(instance, func, |_, r: f32| r.to_bits())140.await141}142143async fn call_func_ret_f64(&mut self, instance: &str, func: &str) -> u64 {144self.call_func(instance, func, |_, r: f64| r.to_bits())145.await146}147}148149150