Path: blob/main/crates/wizer/src/component/wasmtime.rs
3068 views
use crate::Wizer;1use crate::component::ComponentInstanceState;2use wasmtime::component::{3Component, ComponentExportIndex, Instance, Lift, WasmList, types::ComponentItem,4};5use wasmtime::{Result, Store, error::Context as _, format_err};67#[cfg(feature = "wasmprinter")]8use wasmtime::ToWasmtimeResult as _;910impl Wizer {11/// Same as [`Wizer::run`], except for components.12pub async fn run_component<T: Send>(13&self,14store: &mut Store<T>,15wasm: &[u8],16instantiate: impl AsyncFnOnce(&mut Store<T>, &Component) -> Result<Instance>,17) -> wasmtime::Result<Vec<u8>> {18let (cx, instrumented_wasm) = self.instrument_component(wasm)?;1920#[cfg(feature = "wasmprinter")]21log::debug!(22"instrumented wasm: {}",23wasmprinter::print_bytes(&instrumented_wasm).to_wasmtime_result()?,24);2526let engine = store.engine();27let component = Component::new(engine, &instrumented_wasm)28.context("failed to compile the Wasm component")?;29let index = self.validate_component_init_func(&component)?;3031let instance = instantiate(store, &component).await?;32self.initialize_component(store, &instance, index).await?;33self.snapshot_component(cx, &mut WasmtimeWizerComponent { store, instance })34.await35}3637fn validate_component_init_func(38&self,39component: &Component,40) -> wasmtime::Result<ComponentExportIndex> {41let init_func = self.get_init_func();42let (ty, index) = component43.get_export(None, init_func)44.ok_or_else(|| format_err!("the component does export the function `{init_func}`"))?;4546let ty = match ty {47ComponentItem::ComponentFunc(ty) => ty,48_ => wasmtime::bail!("the component's `{init_func}` export is not a function",),49};5051if ty.params().len() != 0 || ty.results().len() != 0 {52wasmtime::bail!(53"the component's `{init_func}` function export does not have type `[] -> []`",54);55}56Ok(index)57}5859async fn initialize_component<T: Send>(60&self,61store: &mut Store<T>,62instance: &Instance,63index: ComponentExportIndex,64) -> wasmtime::Result<()> {65let init_func = instance66.get_typed_func::<(), ()>(&mut *store, index)67.expect("checked by `validate_init_func`");68init_func69.call_async(&mut *store, ())70.await71.with_context(|| format!("the initialization function trapped"))?;7273Ok(())74}75}7677/// Impementation of [`ComponentInstanceState`] backed by Wasmtime.78pub struct WasmtimeWizerComponent<'a, T: 'static> {79/// The Wasmtime-based store that owns the `instance` field.80pub store: &'a mut Store<T>,81/// The instance that this will load state from.82pub instance: Instance,83}8485impl<T: Send> WasmtimeWizerComponent<'_, T> {86async fn call_func<R, R2>(87&mut self,88instance: &str,89func: &str,90use_ret: impl FnOnce(&mut Store<T>, R) -> R2,91) -> R292where93R: Lift + 'static,94{95log::debug!("invoking {instance}#{func}");96let (_, instance_export) = self97.instance98.get_export(&mut *self.store, None, instance)99.unwrap();100let (_, func_export) = self101.instance102.get_export(&mut *self.store, Some(&instance_export), func)103.unwrap();104let func = self105.instance106.get_typed_func::<(), (R,)>(&mut *self.store, func_export)107.unwrap();108let ret = func.call_async(&mut *self.store, ()).await.unwrap().0;109use_ret(&mut *self.store, ret)110}111}112113impl<T: Send> ComponentInstanceState for WasmtimeWizerComponent<'_, T> {114async fn call_func_ret_list_u8(115&mut self,116instance: &str,117func: &str,118contents: impl FnOnce(&[u8]) + Send,119) {120self.call_func(instance, func, |store, list: WasmList<u8>| {121contents(list.as_le_slice(&store));122})123.await124}125126async fn call_func_ret_s32(&mut self, instance: &str, func: &str) -> i32 {127self.call_func(instance, func, |_, r| r).await128}129130async fn call_func_ret_s64(&mut self, instance: &str, func: &str) -> i64 {131self.call_func(instance, func, |_, r| r).await132}133134async fn call_func_ret_f32(&mut self, instance: &str, func: &str) -> u32 {135self.call_func(instance, func, |_, r: f32| r.to_bits())136.await137}138139async fn call_func_ret_f64(&mut self, instance: &str, func: &str) -> u64 {140self.call_func(instance, func, |_, r: f64| r.to_bits())141.await142}143}144145146