1b856261dSJoel Dice use crate::component::RuntimeInstance;
28fb9d189SAlex Crichton use crate::component::instance::Instance;
38fb9d189SAlex Crichton use crate::component::matching::InstanceType;
4d4242001SAdam Bratschi-Kaye use crate::component::storage::storage_as_slice;
592126c50SAlex Crichton use crate::component::types::ComponentFunc;
6d4242001SAdam Bratschi-Kaye use crate::component::values::Val;
781a89169SAlex Crichton use crate::prelude::*;
898499653SAlex Crichton use crate::runtime::vm::component::{ComponentInstance, InstanceFlags};
9b221fca7SJoel Dice use crate::runtime::vm::{Export, VMFuncRef};
10e33836c0SAlex Crichton use crate::store::StoreOpaque;
11d4242001SAdam Bratschi-Kaye use crate::{AsContext, AsContextMut, StoreContextMut, ValRaw};
1281a89169SAlex Crichton use core::mem::{self, MaybeUninit};
1381a89169SAlex Crichton use core::ptr::NonNull;
14d4242001SAdam Bratschi-Kaye use wasmtime_environ::component::{
15ec9b62abSAlex Crichton CanonicalOptions, ExportIndex, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, OptionsIndex,
16ec9b62abSAlex Crichton TypeFuncIndex, TypeTuple,
17d4242001SAdam Bratschi-Kaye };
18d4242001SAdam Bratschi-Kaye
19b221fca7SJoel Dice #[cfg(feature = "component-model-async")]
20c34eb3f7SAlex Crichton use crate::component::concurrent::{self, AsAccessor, PreparedCall};
21b221fca7SJoel Dice
22d4242001SAdam Bratschi-Kaye mod host;
23d4242001SAdam Bratschi-Kaye mod options;
24d4242001SAdam Bratschi-Kaye mod typed;
25d4242001SAdam Bratschi-Kaye pub use self::host::*;
26d4242001SAdam Bratschi-Kaye pub use self::options::*;
27d4242001SAdam Bratschi-Kaye pub use self::typed::*;
28d4242001SAdam Bratschi-Kaye
296d105f4dSAlex Crichton /// A WebAssembly component function which can be called.
306d105f4dSAlex Crichton ///
316d105f4dSAlex Crichton /// This type is the dual of [`wasmtime::Func`](crate::Func) for component
326d105f4dSAlex Crichton /// functions. An instance of [`Func`] represents a component function from a
336d105f4dSAlex Crichton /// component [`Instance`](crate::component::Instance). Like with
346d105f4dSAlex Crichton /// [`wasmtime::Func`](crate::Func) it's possible to call functions either
356d105f4dSAlex Crichton /// synchronously or asynchronously and either typed or untyped.
36d4242001SAdam Bratschi-Kaye #[derive(Copy, Clone, Debug)]
37e33836c0SAlex Crichton #[repr(C)] // here for the C API.
38e33836c0SAlex Crichton pub struct Func {
39d4242001SAdam Bratschi-Kaye instance: Instance,
40e33836c0SAlex Crichton index: ExportIndex,
41d4242001SAdam Bratschi-Kaye }
42d4242001SAdam Bratschi-Kaye
43e33836c0SAlex Crichton // Double-check that the C representation in `component/instance.h` matches our
44e33836c0SAlex Crichton // in-Rust representation here in terms of size/alignment/etc.
45e33836c0SAlex Crichton const _: () = {
46e33836c0SAlex Crichton #[repr(C)]
47e33836c0SAlex Crichton struct T(u64, u32);
48e33836c0SAlex Crichton #[repr(C)]
49e33836c0SAlex Crichton struct C(T, u32);
50e33836c0SAlex Crichton assert!(core::mem::size_of::<C>() == core::mem::size_of::<Func>());
51e33836c0SAlex Crichton assert!(core::mem::align_of::<C>() == core::mem::align_of::<Func>());
52e33836c0SAlex Crichton assert!(core::mem::offset_of!(Func, instance) == 0);
53d4242001SAdam Bratschi-Kaye };
54e33836c0SAlex Crichton
55e33836c0SAlex Crichton impl Func {
from_lifted_func(instance: Instance, index: ExportIndex) -> Func56e33836c0SAlex Crichton pub(crate) fn from_lifted_func(instance: Instance, index: ExportIndex) -> Func {
57e33836c0SAlex Crichton Func { instance, index }
58d4242001SAdam Bratschi-Kaye }
59d4242001SAdam Bratschi-Kaye
60d4242001SAdam Bratschi-Kaye /// Attempt to cast this [`Func`] to a statically typed [`TypedFunc`] with
61d4242001SAdam Bratschi-Kaye /// the provided `Params` and `Return`.
62d4242001SAdam Bratschi-Kaye ///
63d4242001SAdam Bratschi-Kaye /// This function will perform a type-check at runtime that the [`Func`]
64d4242001SAdam Bratschi-Kaye /// takes `Params` as parameters and returns `Return`. If the type-check
65d4242001SAdam Bratschi-Kaye /// passes then a [`TypedFunc`] will be returned which can be used to
66d4242001SAdam Bratschi-Kaye /// invoke the function in an efficient, statically-typed, and ergonomic
67d4242001SAdam Bratschi-Kaye /// manner.
68d4242001SAdam Bratschi-Kaye ///
69d4242001SAdam Bratschi-Kaye /// The `Params` type parameter here is a tuple of the parameters to the
70d4242001SAdam Bratschi-Kaye /// function. A function which takes no arguments should use `()`, a
71d4242001SAdam Bratschi-Kaye /// function with one argument should use `(T,)`, etc. Note that all
726d105f4dSAlex Crichton /// `Params` must also implement the [`Lower`] trait since they're going
736d105f4dSAlex Crichton /// into wasm.
74d4242001SAdam Bratschi-Kaye ///
75d4242001SAdam Bratschi-Kaye /// The `Return` type parameter is the return value of this function. A
76d4242001SAdam Bratschi-Kaye /// return value of `()` means that there's no return (similar to a Rust
77d4242001SAdam Bratschi-Kaye /// unit return) and otherwise a type `T` can be specified. Note that the
78d4242001SAdam Bratschi-Kaye /// `Return` must also implement the [`Lift`] trait since it's coming from
79d4242001SAdam Bratschi-Kaye /// wasm.
80d4242001SAdam Bratschi-Kaye ///
81d4242001SAdam Bratschi-Kaye /// Types specified here must implement the [`ComponentType`] trait. This
82d4242001SAdam Bratschi-Kaye /// trait is implemented for built-in types to Rust such as integer
83d4242001SAdam Bratschi-Kaye /// primitives, floats, `Option<T>`, `Result<T, E>`, strings, `Vec<T>`, and
84d4242001SAdam Bratschi-Kaye /// more. As parameters you'll be passing native Rust types.
85d4242001SAdam Bratschi-Kaye ///
866d105f4dSAlex Crichton /// See the documentation for [`ComponentType`] for more information about
876d105f4dSAlex Crichton /// supported types.
886d105f4dSAlex Crichton ///
89d4242001SAdam Bratschi-Kaye /// # Errors
90d4242001SAdam Bratschi-Kaye ///
91d4242001SAdam Bratschi-Kaye /// If the function does not actually take `Params` as its parameters or
92d4242001SAdam Bratschi-Kaye /// return `Return` then an error will be returned.
93d4242001SAdam Bratschi-Kaye ///
94d4242001SAdam Bratschi-Kaye /// # Panics
95d4242001SAdam Bratschi-Kaye ///
96d4242001SAdam Bratschi-Kaye /// This function will panic if `self` is not owned by the `store`
97d4242001SAdam Bratschi-Kaye /// specified.
98d4242001SAdam Bratschi-Kaye ///
99d4242001SAdam Bratschi-Kaye /// # Examples
100d4242001SAdam Bratschi-Kaye ///
101d4242001SAdam Bratschi-Kaye /// Calling a function which takes no parameters and has no return value:
102d4242001SAdam Bratschi-Kaye ///
103d4242001SAdam Bratschi-Kaye /// ```
104d4242001SAdam Bratschi-Kaye /// # use wasmtime::component::Func;
105d4242001SAdam Bratschi-Kaye /// # use wasmtime::Store;
10696e19700SNick Fitzgerald /// # fn foo(func: &Func, store: &mut Store<()>) -> wasmtime::Result<()> {
107d4242001SAdam Bratschi-Kaye /// let typed = func.typed::<(), ()>(&store)?;
108d4242001SAdam Bratschi-Kaye /// typed.call(store, ())?;
109d4242001SAdam Bratschi-Kaye /// # Ok(())
110d4242001SAdam Bratschi-Kaye /// # }
111d4242001SAdam Bratschi-Kaye /// ```
112d4242001SAdam Bratschi-Kaye ///
113d4242001SAdam Bratschi-Kaye /// Calling a function which takes one string parameter and returns a
114d4242001SAdam Bratschi-Kaye /// string:
115d4242001SAdam Bratschi-Kaye ///
116d4242001SAdam Bratschi-Kaye /// ```
117d4242001SAdam Bratschi-Kaye /// # use wasmtime::component::Func;
118d4242001SAdam Bratschi-Kaye /// # use wasmtime::Store;
11996e19700SNick Fitzgerald /// # fn foo(func: &Func, mut store: Store<()>) -> wasmtime::Result<()> {
120d4242001SAdam Bratschi-Kaye /// let typed = func.typed::<(&str,), (String,)>(&store)?;
121d4242001SAdam Bratschi-Kaye /// let ret = typed.call(&mut store, ("Hello, ",))?.0;
122d4242001SAdam Bratschi-Kaye /// println!("returned string was: {}", ret);
123d4242001SAdam Bratschi-Kaye /// # Ok(())
124d4242001SAdam Bratschi-Kaye /// # }
125d4242001SAdam Bratschi-Kaye /// ```
126d4242001SAdam Bratschi-Kaye ///
127d4242001SAdam Bratschi-Kaye /// Calling a function which takes multiple parameters and returns a boolean:
128d4242001SAdam Bratschi-Kaye ///
129d4242001SAdam Bratschi-Kaye /// ```
130d4242001SAdam Bratschi-Kaye /// # use wasmtime::component::Func;
131d4242001SAdam Bratschi-Kaye /// # use wasmtime::Store;
13296e19700SNick Fitzgerald /// # fn foo(func: &Func, mut store: Store<()>) -> wasmtime::Result<()> {
133d4242001SAdam Bratschi-Kaye /// let typed = func.typed::<(u32, Option<&str>, &[u8]), (bool,)>(&store)?;
134d4242001SAdam Bratschi-Kaye /// let ok: bool = typed.call(&mut store, (1, Some("hello"), b"bytes!"))?.0;
135d4242001SAdam Bratschi-Kaye /// println!("return value was: {ok}");
136d4242001SAdam Bratschi-Kaye /// # Ok(())
137d4242001SAdam Bratschi-Kaye /// # }
138d4242001SAdam Bratschi-Kaye /// ```
typed<Params, Return>(&self, store: impl AsContext) -> Result<TypedFunc<Params, Return>> where Params: ComponentNamedList + Lower, Return: ComponentNamedList + Lift,139d4242001SAdam Bratschi-Kaye pub fn typed<Params, Return>(&self, store: impl AsContext) -> Result<TypedFunc<Params, Return>>
140d4242001SAdam Bratschi-Kaye where
141d4242001SAdam Bratschi-Kaye Params: ComponentNamedList + Lower,
142d4242001SAdam Bratschi-Kaye Return: ComponentNamedList + Lift,
143d4242001SAdam Bratschi-Kaye {
144d4242001SAdam Bratschi-Kaye self._typed(store.as_context().0, None)
145d4242001SAdam Bratschi-Kaye }
146d4242001SAdam Bratschi-Kaye
_typed<Params, Return>( &self, store: &StoreOpaque, instance: Option<&ComponentInstance>, ) -> Result<TypedFunc<Params, Return>> where Params: ComponentNamedList + Lower, Return: ComponentNamedList + Lift,147d4242001SAdam Bratschi-Kaye pub(crate) fn _typed<Params, Return>(
148d4242001SAdam Bratschi-Kaye &self,
149d4242001SAdam Bratschi-Kaye store: &StoreOpaque,
1508fb9d189SAlex Crichton instance: Option<&ComponentInstance>,
151d4242001SAdam Bratschi-Kaye ) -> Result<TypedFunc<Params, Return>>
152d4242001SAdam Bratschi-Kaye where
153d4242001SAdam Bratschi-Kaye Params: ComponentNamedList + Lower,
154d4242001SAdam Bratschi-Kaye Return: ComponentNamedList + Lift,
155d4242001SAdam Bratschi-Kaye {
156d4242001SAdam Bratschi-Kaye self.typecheck::<Params, Return>(store, instance)?;
157d4242001SAdam Bratschi-Kaye unsafe { Ok(TypedFunc::new_unchecked(*self)) }
158d4242001SAdam Bratschi-Kaye }
159d4242001SAdam Bratschi-Kaye
typecheck<Params, Return>( &self, store: &StoreOpaque, instance: Option<&ComponentInstance>, ) -> Result<()> where Params: ComponentNamedList + Lower, Return: ComponentNamedList + Lift,160d4242001SAdam Bratschi-Kaye fn typecheck<Params, Return>(
161d4242001SAdam Bratschi-Kaye &self,
162d4242001SAdam Bratschi-Kaye store: &StoreOpaque,
1638fb9d189SAlex Crichton instance: Option<&ComponentInstance>,
164d4242001SAdam Bratschi-Kaye ) -> Result<()>
165d4242001SAdam Bratschi-Kaye where
166d4242001SAdam Bratschi-Kaye Params: ComponentNamedList + Lower,
167d4242001SAdam Bratschi-Kaye Return: ComponentNamedList + Lift,
168d4242001SAdam Bratschi-Kaye {
1697e28c254SAlex Crichton let cx = InstanceType::new(instance.unwrap_or_else(|| self.instance.id().get(store)));
17092126c50SAlex Crichton let ty = &cx.types[self.ty_index(store)];
171d4242001SAdam Bratschi-Kaye
172d4242001SAdam Bratschi-Kaye Params::typecheck(&InterfaceType::Tuple(ty.params), &cx)
173d4242001SAdam Bratschi-Kaye .context("type mismatch with parameters")?;
174d4242001SAdam Bratschi-Kaye Return::typecheck(&InterfaceType::Tuple(ty.results), &cx)
175d4242001SAdam Bratschi-Kaye .context("type mismatch with results")?;
176d4242001SAdam Bratschi-Kaye
177d4242001SAdam Bratschi-Kaye Ok(())
178d4242001SAdam Bratschi-Kaye }
179d4242001SAdam Bratschi-Kaye
18092126c50SAlex Crichton /// Get the type of this function.
ty(&self, store: impl AsContext) -> ComponentFunc18192126c50SAlex Crichton pub fn ty(&self, store: impl AsContext) -> ComponentFunc {
18292126c50SAlex Crichton self.ty_(store.as_context().0)
183d4242001SAdam Bratschi-Kaye }
184d4242001SAdam Bratschi-Kaye
ty_(&self, store: &StoreOpaque) -> ComponentFunc18592126c50SAlex Crichton fn ty_(&self, store: &StoreOpaque) -> ComponentFunc {
18692126c50SAlex Crichton let cx = InstanceType::new(self.instance.id().get(store));
18792126c50SAlex Crichton let ty = self.ty_index(store);
18892126c50SAlex Crichton ComponentFunc::from(ty, &cx)
189d4242001SAdam Bratschi-Kaye }
190d4242001SAdam Bratschi-Kaye
ty_index(&self, store: &StoreOpaque) -> TypeFuncIndex19192126c50SAlex Crichton fn ty_index(&self, store: &StoreOpaque) -> TypeFuncIndex {
1927e28c254SAlex Crichton let instance = self.instance.id().get(store);
193e33836c0SAlex Crichton let (ty, _, _) = instance.component().export_lifted_function(self.index);
194e33836c0SAlex Crichton ty
195e33836c0SAlex Crichton }
196e33836c0SAlex Crichton
197d4242001SAdam Bratschi-Kaye /// Invokes this function with the `params` given and returns the result.
198d4242001SAdam Bratschi-Kaye ///
1996d105f4dSAlex Crichton /// The `params` provided must match the parameters that this function takes
2006d105f4dSAlex Crichton /// in terms of their types and the number of parameters. Results will be
2016d105f4dSAlex Crichton /// written to the `results` slice provided if the call completes
2026d105f4dSAlex Crichton /// successfully. The initial types of the values in `results` are ignored
2036d105f4dSAlex Crichton /// and values are overwritten to write the result. It's required that the
2046d105f4dSAlex Crichton /// size of `results` exactly matches the number of results that this
2056d105f4dSAlex Crichton /// function produces.
2066d105f4dSAlex Crichton ///
207c09aa380SJoel Dice /// This will also call the corresponding `post-return` function, if any.
2086d105f4dSAlex Crichton ///
2096d105f4dSAlex Crichton /// For more detailed information see the documentation of
2106d105f4dSAlex Crichton /// [`TypedFunc::call`].
2116d105f4dSAlex Crichton ///
2126d105f4dSAlex Crichton /// # Errors
2136d105f4dSAlex Crichton ///
2146d105f4dSAlex Crichton /// Returns an error in situations including but not limited to:
2156d105f4dSAlex Crichton ///
2166d105f4dSAlex Crichton /// * `params` is not the right size or if the values have the wrong type
2176d105f4dSAlex Crichton /// * `results` is not the right size
2186d105f4dSAlex Crichton /// * A trap occurs while executing the function
2196d105f4dSAlex Crichton /// * The function calls a host function which returns an error
220cc8d04f4SAlex Crichton /// * The `store` used requires the use of [`Func::call_async`] instead. See
221cc8d04f4SAlex Crichton /// [store documentation](crate#async) for more information.
2226d105f4dSAlex Crichton ///
2236d105f4dSAlex Crichton /// See [`TypedFunc::call`] for more information in addition to
2246d105f4dSAlex Crichton /// [`wasmtime::Func::call`](crate::Func::call).
2256d105f4dSAlex Crichton ///
2266d105f4dSAlex Crichton /// # Panics
2276d105f4dSAlex Crichton ///
228cc8d04f4SAlex Crichton /// Panics if `store` does not own this function.
call( &self, mut store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()>229d4242001SAdam Bratschi-Kaye pub fn call(
230d4242001SAdam Bratschi-Kaye &self,
231d4242001SAdam Bratschi-Kaye mut store: impl AsContextMut,
232d4242001SAdam Bratschi-Kaye params: &[Val],
233d4242001SAdam Bratschi-Kaye results: &mut [Val],
234d4242001SAdam Bratschi-Kaye ) -> Result<()> {
235d4242001SAdam Bratschi-Kaye let mut store = store.as_context_mut();
236cc8d04f4SAlex Crichton store.0.validate_sync_call()?;
237c09aa380SJoel Dice self.call_impl(store.as_context_mut(), params, results)?;
238c09aa380SJoel Dice Ok(())
239d4242001SAdam Bratschi-Kaye }
240d4242001SAdam Bratschi-Kaye
241d4242001SAdam Bratschi-Kaye /// Exactly like [`Self::call`] except for use on async stores.
242d4242001SAdam Bratschi-Kaye ///
243d4242001SAdam Bratschi-Kaye /// # Panics
244d4242001SAdam Bratschi-Kaye ///
245cc8d04f4SAlex Crichton /// Panics if `store` does not own this function.
246d4242001SAdam Bratschi-Kaye #[cfg(feature = "async")]
call_async( &self, mut store: impl AsContextMut<Data: Send>, params: &[Val], results: &mut [Val], ) -> Result<()>247f81c0dc0SAlex Crichton pub async fn call_async(
248d4242001SAdam Bratschi-Kaye &self,
249f81c0dc0SAlex Crichton mut store: impl AsContextMut<Data: Send>,
250d4242001SAdam Bratschi-Kaye params: &[Val],
251d4242001SAdam Bratschi-Kaye results: &mut [Val],
252f81c0dc0SAlex Crichton ) -> Result<()> {
2537e39c25eSJoel Dice let store = store.as_context_mut();
2542200d82cSAlex Crichton
2552200d82cSAlex Crichton #[cfg(feature = "component-model-async")]
25621797bb5SAlex Crichton if store.0.concurrency_support() {
25763679896SNick Fitzgerald return store
2587e39c25eSJoel Dice .run_concurrent_trap_on_idle(async |store| {
259c09aa380SJoel Dice self.call_concurrent_dynamic(store, params, results)
2602200d82cSAlex Crichton .await
261f75ae788SJoel Dice .map(drop)
2622200d82cSAlex Crichton })
26363679896SNick Fitzgerald .await?;
2642200d82cSAlex Crichton }
26563679896SNick Fitzgerald
2667e39c25eSJoel Dice let mut store = store;
267d4242001SAdam Bratschi-Kaye store
268d4242001SAdam Bratschi-Kaye .on_fiber(|store| self.call_impl(store, params, results))
269d4242001SAdam Bratschi-Kaye .await?
270d4242001SAdam Bratschi-Kaye }
271d4242001SAdam Bratschi-Kaye
check_params_results<T>( &self, store: StoreContextMut<T>, params: &[Val], results: &mut [Val], ) -> Result<()>2722200d82cSAlex Crichton fn check_params_results<T>(
2732200d82cSAlex Crichton &self,
2742200d82cSAlex Crichton store: StoreContextMut<T>,
2752200d82cSAlex Crichton params: &[Val],
2762200d82cSAlex Crichton results: &mut [Val],
2772200d82cSAlex Crichton ) -> Result<()> {
27892126c50SAlex Crichton let ty = self.ty(&store);
27992126c50SAlex Crichton if ty.params().len() != params.len() {
2802200d82cSAlex Crichton bail!(
2812200d82cSAlex Crichton "expected {} argument(s), got {}",
28292126c50SAlex Crichton ty.params().len(),
2832200d82cSAlex Crichton params.len(),
2842200d82cSAlex Crichton );
2852200d82cSAlex Crichton }
2862200d82cSAlex Crichton
28792126c50SAlex Crichton if ty.results().len() != results.len() {
2882200d82cSAlex Crichton bail!(
2892200d82cSAlex Crichton "expected {} result(s), got {}",
29092126c50SAlex Crichton ty.results().len(),
2912200d82cSAlex Crichton results.len(),
2922200d82cSAlex Crichton );
293b221fca7SJoel Dice }
294b221fca7SJoel Dice
295b221fca7SJoel Dice Ok(())
296b221fca7SJoel Dice }
297b221fca7SJoel Dice
298b221fca7SJoel Dice /// Start a concurrent call to this function.
299b221fca7SJoel Dice ///
300b1c7887cSLorenzo Fontoura /// Concurrency is achieved by relying on the [`Accessor`] argument, which
301b1c7887cSLorenzo Fontoura /// can be obtained by calling [`StoreContextMut::run_concurrent`].
302b1c7887cSLorenzo Fontoura ///
303b221fca7SJoel Dice /// Unlike [`Self::call`] and [`Self::call_async`] (both of which require
304b221fca7SJoel Dice /// exclusive access to the store until the completion of the call), calls
305b221fca7SJoel Dice /// made using this method may run concurrently with other calls to the same
306fa70f025SJoel Dice /// instance. In addition, the runtime will call the `post-return` function
307c09aa380SJoel Dice /// (if any) automatically when the guest task completes.
308b221fca7SJoel Dice ///
309d6e7841fSAlex Crichton /// # Progress
310d6e7841fSAlex Crichton ///
311d6e7841fSAlex Crichton /// For the wasm task being created in `call_concurrent` to make progress it
312d6e7841fSAlex Crichton /// must be run within the scope of [`run_concurrent`]. If there are no
313d6e7841fSAlex Crichton /// active calls to [`run_concurrent`] then the wasm task will appear as
314d6e7841fSAlex Crichton /// stalled. This is typically not a concern as an [`Accessor`] is bound
315d6e7841fSAlex Crichton /// by default to a scope of [`run_concurrent`].
316d6e7841fSAlex Crichton ///
317d6e7841fSAlex Crichton /// One situation in which this can arise, for example, is that if a
318d6e7841fSAlex Crichton /// [`run_concurrent`] computation finishes its async closure before all
319d6e7841fSAlex Crichton /// wasm tasks have completed, then there will be no scope of
320d6e7841fSAlex Crichton /// [`run_concurrent`] anywhere. In this situation the wasm tasks that have
321d6e7841fSAlex Crichton /// not yet completed will not make progress until [`run_concurrent`] is
322d6e7841fSAlex Crichton /// called again.
323d6e7841fSAlex Crichton ///
324d6e7841fSAlex Crichton /// Embedders will need to ensure that this future is `await`'d within the
325d6e7841fSAlex Crichton /// scope of [`run_concurrent`] to ensure that the value can be produced
326d6e7841fSAlex Crichton /// during the `await` call.
327d6e7841fSAlex Crichton ///
328d6e7841fSAlex Crichton /// # Cancellation
329d6e7841fSAlex Crichton ///
330d6e7841fSAlex Crichton /// Cancelling an async task created via `call_concurrent`, at this time, is
331d6e7841fSAlex Crichton /// only possible by dropping the store that the computation runs within.
332d6e7841fSAlex Crichton /// With [#11833] implemented then it will be possible to request
333d6e7841fSAlex Crichton /// cancellation of a task, but that is not yet implemented. Hard-cancelling
334d6e7841fSAlex Crichton /// a task will only ever be possible by dropping the entire store and it is
335d6e7841fSAlex Crichton /// not possible to remove just one task from a store.
336d6e7841fSAlex Crichton ///
337d6e7841fSAlex Crichton /// This async function behaves more like a "spawn" than a normal Rust async
338d6e7841fSAlex Crichton /// function. When this function is invoked then metadata for the function
339d6e7841fSAlex Crichton /// call is recorded in the store connected to the `accessor` argument and
340d6e7841fSAlex Crichton /// the wasm invocation is from then on connected to the store. If the
341d6e7841fSAlex Crichton /// future created by this function is dropped it does not cancel the
342d6e7841fSAlex Crichton /// in-progress execution of the wasm task. Dropping the future
343d6e7841fSAlex Crichton /// relinquishes the host's ability to learn about the result of the task
344d6e7841fSAlex Crichton /// but the task will still progress and invoke callbacks and such until
345d6e7841fSAlex Crichton /// completion.
346d6e7841fSAlex Crichton ///
34721797bb5SAlex Crichton /// This function will return an error if [`Config::concurrency_support`] is
34821797bb5SAlex Crichton /// disabled.
34921797bb5SAlex Crichton ///
35021797bb5SAlex Crichton /// [`Config::concurrency_support`]: crate::Config::concurrency_support
351d6e7841fSAlex Crichton /// [`run_concurrent`]: crate::Store::run_concurrent
352d6e7841fSAlex Crichton /// [#11833]: https://github.com/bytecodealliance/wasmtime/issues/11833
353d6e7841fSAlex Crichton /// [`Accessor`]: crate::component::Accessor
354d6e7841fSAlex Crichton ///
355da265515SAlex Crichton /// # Panics
356da265515SAlex Crichton ///
357da265515SAlex Crichton /// Panics if the store that the [`Accessor`] is derived from does not own
358da265515SAlex Crichton /// this function.
359b1c7887cSLorenzo Fontoura ///
360b1c7887cSLorenzo Fontoura /// # Example
361b1c7887cSLorenzo Fontoura ///
362b1c7887cSLorenzo Fontoura /// Using [`StoreContextMut::run_concurrent`] to get an [`Accessor`]:
363b1c7887cSLorenzo Fontoura ///
364b1c7887cSLorenzo Fontoura /// ```
365b1c7887cSLorenzo Fontoura /// # use {
366b1c7887cSLorenzo Fontoura /// # wasmtime::{
367b1c7887cSLorenzo Fontoura /// # error::{Result},
368b1c7887cSLorenzo Fontoura /// # component::{Component, Linker, ResourceTable},
369b1c7887cSLorenzo Fontoura /// # Config, Engine, Store
370b1c7887cSLorenzo Fontoura /// # },
371b1c7887cSLorenzo Fontoura /// # };
372b1c7887cSLorenzo Fontoura /// #
373b1c7887cSLorenzo Fontoura /// # struct Ctx { table: ResourceTable }
374b1c7887cSLorenzo Fontoura /// #
375b1c7887cSLorenzo Fontoura /// # async fn foo() -> Result<()> {
376b1c7887cSLorenzo Fontoura /// # let mut config = Config::new();
377b1c7887cSLorenzo Fontoura /// # let engine = Engine::new(&config)?;
378b1c7887cSLorenzo Fontoura /// # let mut store = Store::new(&engine, Ctx { table: ResourceTable::new() });
379b1c7887cSLorenzo Fontoura /// # let mut linker = Linker::new(&engine);
380b1c7887cSLorenzo Fontoura /// # let component = Component::new(&engine, "")?;
381b1c7887cSLorenzo Fontoura /// # let instance = linker.instantiate_async(&mut store, &component).await?;
382b1c7887cSLorenzo Fontoura /// let my_func = instance.get_func(&mut store, "my_func").unwrap();
383b1c7887cSLorenzo Fontoura /// store.run_concurrent(async |accessor| -> wasmtime::Result<_> {
384b1c7887cSLorenzo Fontoura /// my_func.call_concurrent(accessor, &[], &mut Vec::new()).await?;
385b1c7887cSLorenzo Fontoura /// Ok(())
386b1c7887cSLorenzo Fontoura /// }).await??;
387b1c7887cSLorenzo Fontoura /// # Ok(())
388b1c7887cSLorenzo Fontoura /// # }
389b1c7887cSLorenzo Fontoura /// ```
390b221fca7SJoel Dice #[cfg(feature = "component-model-async")]
call_concurrent( self, accessor: impl AsAccessor<Data: Send>, params: &[Val], results: &mut [Val], ) -> Result<()>391c34eb3f7SAlex Crichton pub async fn call_concurrent(
392b221fca7SJoel Dice self,
393c34eb3f7SAlex Crichton accessor: impl AsAccessor<Data: Send>,
3942200d82cSAlex Crichton params: &[Val],
3952200d82cSAlex Crichton results: &mut [Val],
3961e0b0b46SAlex Crichton ) -> Result<()> {
397c09aa380SJoel Dice self.call_concurrent_dynamic(accessor, params, results)
3982200d82cSAlex Crichton .await
399fa70f025SJoel Dice }
400fa70f025SJoel Dice
401fa70f025SJoel Dice /// Internal helper function for `call_async` and `call_concurrent`.
402fa70f025SJoel Dice #[cfg(feature = "component-model-async")]
call_concurrent_dynamic( self, accessor: impl AsAccessor<Data: Send>, params: &[Val], results: &mut [Val], ) -> Result<()>4032200d82cSAlex Crichton async fn call_concurrent_dynamic(
404fa70f025SJoel Dice self,
405f75ae788SJoel Dice accessor: impl AsAccessor<Data: Send>,
4062200d82cSAlex Crichton params: &[Val],
4072200d82cSAlex Crichton results: &mut [Val],
4081e0b0b46SAlex Crichton ) -> Result<()> {
409f75ae788SJoel Dice let result = accessor.as_accessor().with(|mut store| {
4102200d82cSAlex Crichton self.check_params_results(store.as_context_mut(), params, results)?;
411c09aa380SJoel Dice let prepared = self.prepare_call_dynamic(store.as_context_mut(), params.to_vec())?;
4122200d82cSAlex Crichton concurrent::queue_call(store.as_context_mut(), prepared)
4132200d82cSAlex Crichton })?;
414b221fca7SJoel Dice
4151e0b0b46SAlex Crichton let run_results = result.await?;
4162200d82cSAlex Crichton assert_eq!(run_results.len(), results.len());
4172200d82cSAlex Crichton for (result, slot) in run_results.into_iter().zip(results) {
4182200d82cSAlex Crichton *slot = result;
4192200d82cSAlex Crichton }
4201e0b0b46SAlex Crichton Ok(())
421b221fca7SJoel Dice }
422b221fca7SJoel Dice
423b221fca7SJoel Dice /// Calls `concurrent::prepare_call` with monomorphized functions for
424b221fca7SJoel Dice /// lowering the parameters and lifting the result.
425b221fca7SJoel Dice #[cfg(feature = "component-model-async")]
prepare_call_dynamic<'a, T: Send + 'static>( self, mut store: StoreContextMut<'a, T>, params: Vec<Val>, ) -> Result<PreparedCall<Vec<Val>>>426b221fca7SJoel Dice fn prepare_call_dynamic<'a, T: Send + 'static>(
427b221fca7SJoel Dice self,
428b221fca7SJoel Dice mut store: StoreContextMut<'a, T>,
429b221fca7SJoel Dice params: Vec<Val>,
430b221fca7SJoel Dice ) -> Result<PreparedCall<Vec<Val>>> {
431b221fca7SJoel Dice let store = store.as_context_mut();
432b221fca7SJoel Dice
433b221fca7SJoel Dice concurrent::prepare_call(
434b221fca7SJoel Dice store,
435fa70f025SJoel Dice self,
436fa70f025SJoel Dice MAX_FLAT_PARAMS,
437e06fbf70SSy Brand false,
438b221fca7SJoel Dice move |func, store, params_out| {
439c09aa380SJoel Dice func.with_lower_context(store, |cx, ty| {
440b221fca7SJoel Dice Self::lower_args(cx, ¶ms, ty, params_out)
441b221fca7SJoel Dice })
442b221fca7SJoel Dice },
443b221fca7SJoel Dice move |func, store, results| {
444b221fca7SJoel Dice let max_flat = if func.abi_async(store) {
445b221fca7SJoel Dice MAX_FLAT_PARAMS
446b221fca7SJoel Dice } else {
447b221fca7SJoel Dice MAX_FLAT_RESULTS
448b221fca7SJoel Dice };
449b221fca7SJoel Dice let results = func.with_lift_context(store, |cx, ty| {
450b221fca7SJoel Dice Self::lift_results(cx, ty, results, max_flat)?.collect::<Result<Vec<_>>>()
451b221fca7SJoel Dice })?;
452b221fca7SJoel Dice Ok(Box::new(results))
453b221fca7SJoel Dice },
454b221fca7SJoel Dice )
455b221fca7SJoel Dice }
456b221fca7SJoel Dice
call_impl( &self, mut store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()>457d4242001SAdam Bratschi-Kaye fn call_impl(
458d4242001SAdam Bratschi-Kaye &self,
459d4242001SAdam Bratschi-Kaye mut store: impl AsContextMut,
460d4242001SAdam Bratschi-Kaye params: &[Val],
461d4242001SAdam Bratschi-Kaye results: &mut [Val],
462d4242001SAdam Bratschi-Kaye ) -> Result<()> {
463b221fca7SJoel Dice let mut store = store.as_context_mut();
464d4242001SAdam Bratschi-Kaye
4652200d82cSAlex Crichton self.check_params_results(store.as_context_mut(), params, results)?;
466d4242001SAdam Bratschi-Kaye
467b221fca7SJoel Dice if self.abi_async(store.0) {
468b221fca7SJoel Dice unreachable!(
469b221fca7SJoel Dice "async-lifted exports should have failed validation \
470b221fca7SJoel Dice when `component-model-async` feature disabled"
471b221fca7SJoel Dice );
472b221fca7SJoel Dice }
473b221fca7SJoel Dice
474b221fca7SJoel Dice // SAFETY: the chosen representations of type parameters to `call_raw`
475b221fca7SJoel Dice // here should be generally safe to work with:
476b221fca7SJoel Dice //
477b221fca7SJoel Dice // * parameters use `MaybeUninit<[MaybeUninit<ValRaw>; MAX_FLAT_PARAMS]>`
478b221fca7SJoel Dice // which represents the maximal possible number of parameters that can
479b221fca7SJoel Dice // be passed to lifted component functions. This is modeled with
480b221fca7SJoel Dice // `MaybeUninit` to represent how it all starts as uninitialized and
481b221fca7SJoel Dice // thus can't be safely read during lowering.
482b221fca7SJoel Dice //
483b221fca7SJoel Dice // * results are modeled as `[ValRaw; MAX_FLAT_RESULTS]` which
484b221fca7SJoel Dice // represents the maximal size of values that can be returned. Note
485b221fca7SJoel Dice // that if the function doesn't actually have a return value then the
486b221fca7SJoel Dice // `ValRaw` inside the array will have undefined contents. That is
487b221fca7SJoel Dice // safe in Rust, however, due to `ValRaw` being a `union`. The
488b221fca7SJoel Dice // contents should dynamically not be read due to the type of the
489b221fca7SJoel Dice // function used here matching the actual lift.
490c09aa380SJoel Dice let (_, post_return_arg) = unsafe {
491d4242001SAdam Bratschi-Kaye self.call_raw(
492c09aa380SJoel Dice store.as_context_mut(),
493b221fca7SJoel Dice |cx, ty, dst: &mut MaybeUninit<[MaybeUninit<ValRaw>; MAX_FLAT_PARAMS]>| {
494b221fca7SJoel Dice // SAFETY: it's safe to assume that
495b221fca7SJoel Dice // `MaybeUninit<array-of-maybe-uninit>` is initialized because
496b221fca7SJoel Dice // each individual element is still considered uninitialized.
497b221fca7SJoel Dice let dst: &mut [MaybeUninit<ValRaw>] = dst.assume_init_mut();
498b221fca7SJoel Dice Self::lower_args(cx, params, ty, dst)
499d4242001SAdam Bratschi-Kaye },
500d4242001SAdam Bratschi-Kaye |cx, results_ty, src: &[ValRaw; MAX_FLAT_RESULTS]| {
501b221fca7SJoel Dice let max_flat = MAX_FLAT_RESULTS;
502b221fca7SJoel Dice for (result, slot) in
503b221fca7SJoel Dice Self::lift_results(cx, results_ty, src, max_flat)?.zip(results)
504b221fca7SJoel Dice {
505b221fca7SJoel Dice *slot = result?;
506d4242001SAdam Bratschi-Kaye }
507d4242001SAdam Bratschi-Kaye Ok(())
508d4242001SAdam Bratschi-Kaye },
509c09aa380SJoel Dice )?
510c09aa380SJoel Dice };
511c09aa380SJoel Dice
512c09aa380SJoel Dice self.post_return_impl(store, post_return_arg)
513b221fca7SJoel Dice }
514b221fca7SJoel Dice
lifted_core_func(&self, store: &mut StoreOpaque) -> NonNull<VMFuncRef>515b221fca7SJoel Dice pub(crate) fn lifted_core_func(&self, store: &mut StoreOpaque) -> NonNull<VMFuncRef> {
516b221fca7SJoel Dice let def = {
517b221fca7SJoel Dice let instance = self.instance.id().get(store);
518b221fca7SJoel Dice let (_ty, def, _options) = instance.component().export_lifted_function(self.index);
519b221fca7SJoel Dice def.clone()
520b221fca7SJoel Dice };
521b221fca7SJoel Dice match self.instance.lookup_vmdef(store, &def) {
5222b832281SAlex Crichton Export::Function(f) => f.vm_func_ref(store),
523b221fca7SJoel Dice _ => unreachable!(),
524b221fca7SJoel Dice }
525b221fca7SJoel Dice }
526b221fca7SJoel Dice
post_return_core_func(&self, store: &StoreOpaque) -> Option<NonNull<VMFuncRef>>527b221fca7SJoel Dice pub(crate) fn post_return_core_func(&self, store: &StoreOpaque) -> Option<NonNull<VMFuncRef>> {
528b221fca7SJoel Dice let instance = self.instance.id().get(store);
529815c10deSAlex Crichton let component = instance.component();
530815c10deSAlex Crichton let (_ty, _def, options) = component.export_lifted_function(self.index);
531815c10deSAlex Crichton let post_return = component.env_component().options[options].post_return;
532815c10deSAlex Crichton post_return.map(|i| instance.runtime_post_return(i))
533b221fca7SJoel Dice }
534b221fca7SJoel Dice
abi_async(&self, store: &StoreOpaque) -> bool535b221fca7SJoel Dice pub(crate) fn abi_async(&self, store: &StoreOpaque) -> bool {
536b221fca7SJoel Dice let instance = self.instance.id().get(store);
537815c10deSAlex Crichton let component = instance.component();
538815c10deSAlex Crichton let (_ty, _def, options) = component.export_lifted_function(self.index);
539815c10deSAlex Crichton component.env_component().options[options].async_
540b221fca7SJoel Dice }
541b221fca7SJoel Dice
abi_info<'a>( &self, store: &'a StoreOpaque, ) -> ( OptionsIndex, InstanceFlags, TypeFuncIndex, &'a CanonicalOptions, )542b221fca7SJoel Dice pub(crate) fn abi_info<'a>(
543b221fca7SJoel Dice &self,
544b221fca7SJoel Dice store: &'a StoreOpaque,
545ec9b62abSAlex Crichton ) -> (
546ec9b62abSAlex Crichton OptionsIndex,
547ec9b62abSAlex Crichton InstanceFlags,
548ec9b62abSAlex Crichton TypeFuncIndex,
549ec9b62abSAlex Crichton &'a CanonicalOptions,
550ec9b62abSAlex Crichton ) {
551b221fca7SJoel Dice let vminstance = self.instance.id().get(store);
552815c10deSAlex Crichton let component = vminstance.component();
553815c10deSAlex Crichton let (ty, _def, options_index) = component.export_lifted_function(self.index);
554815c10deSAlex Crichton let raw_options = &component.env_component().options[options_index];
555815c10deSAlex Crichton (
556ec9b62abSAlex Crichton options_index,
557815c10deSAlex Crichton vminstance.instance_flags(raw_options.instance),
558815c10deSAlex Crichton ty,
559815c10deSAlex Crichton raw_options,
560b221fca7SJoel Dice )
561b221fca7SJoel Dice }
562d4242001SAdam Bratschi-Kaye
563d4242001SAdam Bratschi-Kaye /// Invokes the underlying wasm function, lowering arguments and lifting the
564d4242001SAdam Bratschi-Kaye /// result.
565d4242001SAdam Bratschi-Kaye ///
566d4242001SAdam Bratschi-Kaye /// The `lower` function and `lift` function provided here are what actually
567d4242001SAdam Bratschi-Kaye /// do the lowering and lifting. The `LowerParams` and `LowerReturn` types
568d4242001SAdam Bratschi-Kaye /// are what will be allocated on the stack for this function call. They
569d4242001SAdam Bratschi-Kaye /// should be appropriately sized for the lowering/lifting operation
570d4242001SAdam Bratschi-Kaye /// happening.
571b221fca7SJoel Dice ///
572b221fca7SJoel Dice /// # Safety
573b221fca7SJoel Dice ///
574b221fca7SJoel Dice /// The safety of this function relies on the correct definitions of the
575b221fca7SJoel Dice /// `LowerParams` and `LowerReturn` type. They must match the type of `self`
576b221fca7SJoel Dice /// for the params/results that are going to be produced. Additionally
577b221fca7SJoel Dice /// these types must be representable with a sequence of `ValRaw` values.
call_raw<T, Return, LowerParams, LowerReturn>( &self, mut store: StoreContextMut<'_, T>, lower: impl FnOnce( &mut LowerContext<'_, T>, InterfaceType, &mut MaybeUninit<LowerParams>, ) -> Result<()>, lift: impl FnOnce(&mut LiftContext<'_>, InterfaceType, &LowerReturn) -> Result<Return>, ) -> Result<(Return, ValRaw)> where LowerParams: Copy, LowerReturn: Copy,578b221fca7SJoel Dice unsafe fn call_raw<T, Return, LowerParams, LowerReturn>(
579d4242001SAdam Bratschi-Kaye &self,
580b221fca7SJoel Dice mut store: StoreContextMut<'_, T>,
581d4242001SAdam Bratschi-Kaye lower: impl FnOnce(
582d4242001SAdam Bratschi-Kaye &mut LowerContext<'_, T>,
583d4242001SAdam Bratschi-Kaye InterfaceType,
584d4242001SAdam Bratschi-Kaye &mut MaybeUninit<LowerParams>,
585d4242001SAdam Bratschi-Kaye ) -> Result<()>,
586d4242001SAdam Bratschi-Kaye lift: impl FnOnce(&mut LiftContext<'_>, InterfaceType, &LowerReturn) -> Result<Return>,
587c09aa380SJoel Dice ) -> Result<(Return, ValRaw)>
588d4242001SAdam Bratschi-Kaye where
589d4242001SAdam Bratschi-Kaye LowerParams: Copy,
590d4242001SAdam Bratschi-Kaye LowerReturn: Copy,
591d4242001SAdam Bratschi-Kaye {
592b221fca7SJoel Dice let export = self.lifted_core_func(store.0);
593b856261dSJoel Dice let (_options, _flags, _ty, raw_options) = self.abi_info(store.0);
594b856261dSJoel Dice let instance = RuntimeInstance {
595b856261dSJoel Dice instance: self.instance.id().instance(),
596b856261dSJoel Dice index: raw_options.instance,
597b856261dSJoel Dice };
598b856261dSJoel Dice
599da093747SAlex Crichton if !store.0.may_enter(instance)? {
600b856261dSJoel Dice bail!(crate::Trap::CannotEnterComponent);
601b856261dSJoel Dice }
6028801023bSNick Fitzgerald
603b271e452SJoel Dice let async_type = self.abi_async(store.0);
6043764e757SAlex Crichton store.0.enter_guest_sync_call(None, async_type, instance)?;
605b271e452SJoel Dice
606b221fca7SJoel Dice #[repr(C)]
607b221fca7SJoel Dice union Union<Params: Copy, Return: Copy> {
608b221fca7SJoel Dice params: Params,
609b221fca7SJoel Dice ret: Return,
610b221fca7SJoel Dice }
6118801023bSNick Fitzgerald
612b221fca7SJoel Dice let space = &mut MaybeUninit::<Union<LowerParams, LowerReturn>>::uninit();
613d4242001SAdam Bratschi-Kaye
6140e9121daSFrankReh // Double-check the size/alignment of `space`, just in case.
615d4242001SAdam Bratschi-Kaye //
616d4242001SAdam Bratschi-Kaye // Note that this alone is not enough to guarantee the validity of the
617d4242001SAdam Bratschi-Kaye // `unsafe` block below, but it's definitely required. In any case LLVM
618d4242001SAdam Bratschi-Kaye // should be able to trivially see through these assertions and remove
619d4242001SAdam Bratschi-Kaye // them in release mode.
620d4242001SAdam Bratschi-Kaye let val_size = mem::size_of::<ValRaw>();
621d4242001SAdam Bratschi-Kaye let val_align = mem::align_of::<ValRaw>();
622d4242001SAdam Bratschi-Kaye assert!(mem::size_of_val(space) % val_size == 0);
623d4242001SAdam Bratschi-Kaye assert!(mem::size_of_val(map_maybe_uninit!(space.params)) % val_size == 0);
624d4242001SAdam Bratschi-Kaye assert!(mem::size_of_val(map_maybe_uninit!(space.ret)) % val_size == 0);
625d4242001SAdam Bratschi-Kaye assert!(mem::align_of_val(space) == val_align);
626d4242001SAdam Bratschi-Kaye assert!(mem::align_of_val(map_maybe_uninit!(space.params)) == val_align);
627d4242001SAdam Bratschi-Kaye assert!(mem::align_of_val(map_maybe_uninit!(space.ret)) == val_align);
628d4242001SAdam Bratschi-Kaye
629c09aa380SJoel Dice self.with_lower_context(store.as_context_mut(), |cx, ty| {
630b221fca7SJoel Dice lower(cx, ty, map_maybe_uninit!(space.params))
631b221fca7SJoel Dice })?;
632d4242001SAdam Bratschi-Kaye
633b221fca7SJoel Dice // SAFETY: We are providing the guarantee that all the inputs are valid.
634b221fca7SJoel Dice // The various pointers passed in for the function are all valid since
635b221fca7SJoel Dice // they're coming from our store, and the `params_and_results` should
636b221fca7SJoel Dice // have the correct layout for the core wasm function we're calling.
637b221fca7SJoel Dice // Note that this latter point relies on the correctness of this module
638b221fca7SJoel Dice // and `ComponentType` implementations, hence `ComponentType` being an
639b221fca7SJoel Dice // `unsafe` trait.
640b221fca7SJoel Dice unsafe {
641d4242001SAdam Bratschi-Kaye crate::Func::call_unchecked_raw(
642b221fca7SJoel Dice &mut store,
643b221fca7SJoel Dice export,
644b86b9682SAlex Crichton NonNull::new(core::ptr::slice_from_raw_parts_mut(
645d4242001SAdam Bratschi-Kaye space.as_mut_ptr().cast(),
646d4242001SAdam Bratschi-Kaye mem::size_of_val(space) / mem::size_of::<ValRaw>(),
647b86b9682SAlex Crichton ))
648b86b9682SAlex Crichton .unwrap(),
649d4242001SAdam Bratschi-Kaye )?;
650b221fca7SJoel Dice }
651d4242001SAdam Bratschi-Kaye
652*58877f2fSAlex Crichton // Validate that the task, after returning, has no more active borrows
653*58877f2fSAlex Crichton // as they're required to have been dropped by this point.
654*58877f2fSAlex Crichton store
655*58877f2fSAlex Crichton .0
656*58877f2fSAlex Crichton .component_resource_tables(Some(self.instance))
657*58877f2fSAlex Crichton .validate_scope_exit()?;
658*58877f2fSAlex Crichton
659b221fca7SJoel Dice // SAFETY: We're relying on the correctness of the structure of
660b221fca7SJoel Dice // `LowerReturn` and the type-checking performed to acquire the
661b221fca7SJoel Dice // `TypedFunc` to make this safe. It should be the case that
662b221fca7SJoel Dice // `LowerReturn` is the exact representation of the return value when
663b221fca7SJoel Dice // interpreted as `[ValRaw]`, and additionally they should have the
664b221fca7SJoel Dice // correct types for the function we just called (which filled in the
665b221fca7SJoel Dice // return values).
666b221fca7SJoel Dice let ret: &LowerReturn = unsafe { map_maybe_uninit!(space.ret).assume_init_ref() };
667d4242001SAdam Bratschi-Kaye
668d4242001SAdam Bratschi-Kaye // Lift the result into the host while managing post-return state
669d4242001SAdam Bratschi-Kaye // here as well.
670d4242001SAdam Bratschi-Kaye //
671d4242001SAdam Bratschi-Kaye // After a successful lift the return value of the function, which
672d4242001SAdam Bratschi-Kaye // is currently required to be 0 or 1 values according to the
673d4242001SAdam Bratschi-Kaye // canonical ABI, is saved within the `Store`'s `FuncData`. This'll
674d4242001SAdam Bratschi-Kaye // later get used in post-return.
675b221fca7SJoel Dice let val = self.with_lift_context(store.0, |cx, ty| lift(cx, ty, ret))?;
676b221fca7SJoel Dice
677b221fca7SJoel Dice // SAFETY: it's a contract of this function that `LowerReturn` is an
678b221fca7SJoel Dice // appropriate representation of the result of this function.
679b221fca7SJoel Dice let ret_slice = unsafe { storage_as_slice(ret) };
680b221fca7SJoel Dice
681c09aa380SJoel Dice Ok((
682c09aa380SJoel Dice val,
683d4242001SAdam Bratschi-Kaye match ret_slice.len() {
684e33836c0SAlex Crichton 0 => ValRaw::i32(0),
685e33836c0SAlex Crichton 1 => ret_slice[0],
686d4242001SAdam Bratschi-Kaye _ => unreachable!(),
687e33836c0SAlex Crichton },
688c09aa380SJoel Dice ))
689d4242001SAdam Bratschi-Kaye }
690d4242001SAdam Bratschi-Kaye
691c09aa380SJoel Dice #[doc(hidden)]
692c09aa380SJoel Dice #[deprecated(note = "no longer needs to be called; this function has no effect")]
post_return(&self, _store: impl AsContextMut) -> Result<()>693c09aa380SJoel Dice pub fn post_return(&self, _store: impl AsContextMut) -> Result<()> {
694c09aa380SJoel Dice Ok(())
695d4242001SAdam Bratschi-Kaye }
696d4242001SAdam Bratschi-Kaye
697c09aa380SJoel Dice #[doc(hidden)]
698c09aa380SJoel Dice #[deprecated(note = "no longer needs to be called; this function has no effect")]
699d4242001SAdam Bratschi-Kaye #[cfg(feature = "async")]
post_return_async(&self, _store: impl AsContextMut<Data: Send>) -> Result<()>700c09aa380SJoel Dice pub async fn post_return_async(&self, _store: impl AsContextMut<Data: Send>) -> Result<()> {
701c09aa380SJoel Dice Ok(())
702d4242001SAdam Bratschi-Kaye }
703d4242001SAdam Bratschi-Kaye
post_return_impl(&self, mut store: impl AsContextMut, arg: ValRaw) -> Result<()>704c09aa380SJoel Dice pub(crate) fn post_return_impl(&self, mut store: impl AsContextMut, arg: ValRaw) -> Result<()> {
705d4242001SAdam Bratschi-Kaye let mut store = store.as_context_mut();
706b221fca7SJoel Dice
707e33836c0SAlex Crichton let index = self.index;
7087e28c254SAlex Crichton let vminstance = self.instance.id().get(store.0);
709815c10deSAlex Crichton let component = vminstance.component();
710815c10deSAlex Crichton let (_ty, _def, options) = component.export_lifted_function(index);
711b221fca7SJoel Dice let post_return = self.post_return_core_func(store.0);
712c09aa380SJoel Dice let flags = vminstance.instance_flags(component.env_component().options[options].instance);
713d4242001SAdam Bratschi-Kaye
714d4242001SAdam Bratschi-Kaye unsafe {
715c09aa380SJoel Dice call_post_return(&mut store, post_return, arg, flags)?;
716da093747SAlex Crichton store.0.exit_guest_sync_call()?;
717d4242001SAdam Bratschi-Kaye }
718d4242001SAdam Bratschi-Kaye Ok(())
719d4242001SAdam Bratschi-Kaye }
720d4242001SAdam Bratschi-Kaye
lower_args<T>( cx: &mut LowerContext<'_, T>, params: &[Val], params_ty: InterfaceType, dst: &mut [MaybeUninit<ValRaw>], ) -> Result<()>721b221fca7SJoel Dice fn lower_args<T>(
722b221fca7SJoel Dice cx: &mut LowerContext<'_, T>,
723b221fca7SJoel Dice params: &[Val],
724b221fca7SJoel Dice params_ty: InterfaceType,
725b221fca7SJoel Dice dst: &mut [MaybeUninit<ValRaw>],
726b221fca7SJoel Dice ) -> Result<()> {
727b221fca7SJoel Dice let params_ty = match params_ty {
728b221fca7SJoel Dice InterfaceType::Tuple(i) => &cx.types[i],
729b221fca7SJoel Dice _ => unreachable!(),
730b221fca7SJoel Dice };
731b221fca7SJoel Dice if params_ty.abi.flat_count(MAX_FLAT_PARAMS).is_some() {
732b221fca7SJoel Dice let dst = &mut dst.iter_mut();
733b221fca7SJoel Dice
734b221fca7SJoel Dice params
735b221fca7SJoel Dice .iter()
736b221fca7SJoel Dice .zip(params_ty.types.iter())
737b221fca7SJoel Dice .try_for_each(|(param, ty)| param.lower(cx, *ty, dst))
738b221fca7SJoel Dice } else {
739b221fca7SJoel Dice Self::store_args(cx, ¶ms_ty, params, dst)
740b221fca7SJoel Dice }
741b221fca7SJoel Dice }
742b221fca7SJoel Dice
store_args<T>( cx: &mut LowerContext<'_, T>, params_ty: &TypeTuple, args: &[Val], dst: &mut [MaybeUninit<ValRaw>], ) -> Result<()>743d4242001SAdam Bratschi-Kaye fn store_args<T>(
744d4242001SAdam Bratschi-Kaye cx: &mut LowerContext<'_, T>,
745d4242001SAdam Bratschi-Kaye params_ty: &TypeTuple,
746d4242001SAdam Bratschi-Kaye args: &[Val],
747b221fca7SJoel Dice dst: &mut [MaybeUninit<ValRaw>],
748d4242001SAdam Bratschi-Kaye ) -> Result<()> {
749d4242001SAdam Bratschi-Kaye let size = usize::try_from(params_ty.abi.size32).unwrap();
750d4242001SAdam Bratschi-Kaye let ptr = cx.realloc(0, 0, params_ty.abi.align32, size)?;
751d4242001SAdam Bratschi-Kaye let mut offset = ptr;
752d4242001SAdam Bratschi-Kaye for (ty, arg) in params_ty.types.iter().zip(args) {
753d4242001SAdam Bratschi-Kaye let abi = cx.types.canonical_abi(ty);
754d4242001SAdam Bratschi-Kaye arg.store(cx, *ty, abi.next_field32_size(&mut offset))?;
755d4242001SAdam Bratschi-Kaye }
756d4242001SAdam Bratschi-Kaye
757b221fca7SJoel Dice dst[0].write(ValRaw::i64(ptr as i64));
758d4242001SAdam Bratschi-Kaye
759d4242001SAdam Bratschi-Kaye Ok(())
760d4242001SAdam Bratschi-Kaye }
761d4242001SAdam Bratschi-Kaye
lift_results<'a, 'b>( cx: &'a mut LiftContext<'b>, results_ty: InterfaceType, src: &'a [ValRaw], max_flat: usize, ) -> Result<Box<dyn Iterator<Item = Result<Val>> + 'a>>762b221fca7SJoel Dice fn lift_results<'a, 'b>(
763b221fca7SJoel Dice cx: &'a mut LiftContext<'b>,
764b221fca7SJoel Dice results_ty: InterfaceType,
765b221fca7SJoel Dice src: &'a [ValRaw],
766b221fca7SJoel Dice max_flat: usize,
767b221fca7SJoel Dice ) -> Result<Box<dyn Iterator<Item = Result<Val>> + 'a>> {
768b221fca7SJoel Dice let results_ty = match results_ty {
769b221fca7SJoel Dice InterfaceType::Tuple(i) => &cx.types[i],
770b221fca7SJoel Dice _ => unreachable!(),
771b221fca7SJoel Dice };
772b221fca7SJoel Dice if results_ty.abi.flat_count(max_flat).is_some() {
773b221fca7SJoel Dice let mut flat = src.iter();
774b221fca7SJoel Dice Ok(Box::new(
775b221fca7SJoel Dice results_ty
776b221fca7SJoel Dice .types
777b221fca7SJoel Dice .iter()
778b221fca7SJoel Dice .map(move |ty| Val::lift(cx, *ty, &mut flat)),
779b221fca7SJoel Dice ))
780b221fca7SJoel Dice } else {
781b221fca7SJoel Dice let iter = Self::load_results(cx, results_ty, &mut src.iter())?;
782b221fca7SJoel Dice Ok(Box::new(iter))
783b221fca7SJoel Dice }
784b221fca7SJoel Dice }
785b221fca7SJoel Dice
load_results<'a, 'b>( cx: &'a mut LiftContext<'b>, results_ty: &'a TypeTuple, src: &mut core::slice::Iter<'_, ValRaw>, ) -> Result<impl Iterator<Item = Result<Val>> + use<'a, 'b>>786b221fca7SJoel Dice fn load_results<'a, 'b>(
787b221fca7SJoel Dice cx: &'a mut LiftContext<'b>,
788b221fca7SJoel Dice results_ty: &'a TypeTuple,
78981a89169SAlex Crichton src: &mut core::slice::Iter<'_, ValRaw>,
790b221fca7SJoel Dice ) -> Result<impl Iterator<Item = Result<Val>> + use<'a, 'b>> {
791ef1ec37eSAlex Crichton // FIXME(#4311): needs to read an i64 for memory64
7929034e101SAlex Crichton let ptr = usize::try_from(src.next().unwrap().get_u32())?;
7939034e101SAlex Crichton if ptr % usize::try_from(results_ty.abi.align32)? != 0 {
794d4242001SAdam Bratschi-Kaye bail!("return pointer not aligned");
795d4242001SAdam Bratschi-Kaye }
796d4242001SAdam Bratschi-Kaye
797d4242001SAdam Bratschi-Kaye let bytes = cx
798d4242001SAdam Bratschi-Kaye .memory()
799d4242001SAdam Bratschi-Kaye .get(ptr..)
800d4242001SAdam Bratschi-Kaye .and_then(|b| b.get(..usize::try_from(results_ty.abi.size32).unwrap()))
80196e19700SNick Fitzgerald .ok_or_else(|| crate::format_err!("pointer out of bounds of memory"))?;
802d4242001SAdam Bratschi-Kaye
803d4242001SAdam Bratschi-Kaye let mut offset = 0;
804b221fca7SJoel Dice Ok(results_ty.types.iter().map(move |ty| {
805d4242001SAdam Bratschi-Kaye let abi = cx.types.canonical_abi(ty);
806d4242001SAdam Bratschi-Kaye let offset = abi.next_field32_size(&mut offset);
807b221fca7SJoel Dice Val::load(cx, *ty, &bytes[offset..][..abi.size32 as usize])
808b221fca7SJoel Dice }))
809d4242001SAdam Bratschi-Kaye }
810b221fca7SJoel Dice
811fa70f025SJoel Dice #[cfg(feature = "component-model-async")]
instance(self) -> Instance812fa70f025SJoel Dice pub(crate) fn instance(self) -> Instance {
813fa70f025SJoel Dice self.instance
814fa70f025SJoel Dice }
815fa70f025SJoel Dice
816b221fca7SJoel Dice /// Creates a `LowerContext` using the configuration values of this lifted
817b221fca7SJoel Dice /// function.
818b221fca7SJoel Dice ///
819b221fca7SJoel Dice /// The `lower` closure provided should perform the actual lowering and
820b221fca7SJoel Dice /// return the result of the lowering operation which is then returned from
821b221fca7SJoel Dice /// this function as well.
with_lower_context<T>( self, mut store: StoreContextMut<T>, lower: impl FnOnce(&mut LowerContext<T>, InterfaceType) -> Result<()>, ) -> Result<()>822b221fca7SJoel Dice fn with_lower_context<T>(
823b221fca7SJoel Dice self,
824b221fca7SJoel Dice mut store: StoreContextMut<T>,
825b221fca7SJoel Dice lower: impl FnOnce(&mut LowerContext<T>, InterfaceType) -> Result<()>,
826b221fca7SJoel Dice ) -> Result<()> {
827c09aa380SJoel Dice let (options_idx, mut flags, ty, _) = self.abi_info(store.0);
828b221fca7SJoel Dice
829b221fca7SJoel Dice // Perform the actual lowering, where while this is running the
830b221fca7SJoel Dice // component is forbidden from calling imports.
831b221fca7SJoel Dice unsafe {
832b221fca7SJoel Dice debug_assert!(flags.may_leave());
833b221fca7SJoel Dice flags.set_may_leave(false);
834b221fca7SJoel Dice }
835ec9b62abSAlex Crichton let mut cx = LowerContext::new(store.as_context_mut(), options_idx, self.instance);
836ec9b62abSAlex Crichton let param_ty = InterfaceType::Tuple(cx.types[ty].params);
837ec9b62abSAlex Crichton let result = lower(&mut cx, param_ty);
838b221fca7SJoel Dice unsafe { flags.set_may_leave(true) };
839c09aa380SJoel Dice result
840d4242001SAdam Bratschi-Kaye }
841b221fca7SJoel Dice
842b221fca7SJoel Dice /// Creates a `LiftContext` using the configuration values with this lifted
843b221fca7SJoel Dice /// function.
844b221fca7SJoel Dice ///
845b221fca7SJoel Dice /// The closure `lift` provided should actually perform the lift itself and
846b221fca7SJoel Dice /// the result of that closure is returned from this function call as well.
with_lift_context<R>( self, store: &mut StoreOpaque, lift: impl FnOnce(&mut LiftContext, InterfaceType) -> Result<R>, ) -> Result<R>847b221fca7SJoel Dice fn with_lift_context<R>(
848b221fca7SJoel Dice self,
849b221fca7SJoel Dice store: &mut StoreOpaque,
850b221fca7SJoel Dice lift: impl FnOnce(&mut LiftContext, InterfaceType) -> Result<R>,
851b221fca7SJoel Dice ) -> Result<R> {
852b221fca7SJoel Dice let (options, _flags, ty, _) = self.abi_info(store);
853ec9b62abSAlex Crichton let mut cx = LiftContext::new(store, options, self.instance);
8542b776b00SAlex Crichton let ty = InterfaceType::Tuple(cx.types[ty].results);
8552b776b00SAlex Crichton lift(&mut cx, ty)
856b221fca7SJoel Dice }
857d4242001SAdam Bratschi-Kaye }
858f75ae788SJoel Dice
call_post_return( mut store: impl AsContextMut, func: Option<NonNull<VMFuncRef>>, arg: ValRaw, mut flags: InstanceFlags, ) -> Result<()>859c09aa380SJoel Dice pub(crate) unsafe fn call_post_return(
860c09aa380SJoel Dice mut store: impl AsContextMut,
861c09aa380SJoel Dice func: Option<NonNull<VMFuncRef>>,
862c09aa380SJoel Dice arg: ValRaw,
863c09aa380SJoel Dice mut flags: InstanceFlags,
864c09aa380SJoel Dice ) -> Result<()> {
865c09aa380SJoel Dice unsafe {
866c09aa380SJoel Dice // Post return functions are forbidden from calling imports or
867c09aa380SJoel Dice // intrinsics.
868c09aa380SJoel Dice flags.set_may_leave(false);
869c09aa380SJoel Dice
870c09aa380SJoel Dice // If the function actually had a `post-return` configured in its
871c09aa380SJoel Dice // canonical options that's executed here.
872c09aa380SJoel Dice if let Some(func) = func {
873c09aa380SJoel Dice crate::Func::call_unchecked_raw(
874c09aa380SJoel Dice &mut store.as_context_mut(),
875c09aa380SJoel Dice func,
876c09aa380SJoel Dice core::slice::from_ref(&arg).into(),
877c09aa380SJoel Dice )?;
878c09aa380SJoel Dice }
879c09aa380SJoel Dice
880c09aa380SJoel Dice // And finally if everything completed successfully then the "may
881c09aa380SJoel Dice // leave" flags is set to `true` again here which enables further
882c09aa380SJoel Dice // use of the component.
883c09aa380SJoel Dice flags.set_may_leave(true);
884c09aa380SJoel Dice }
885c09aa380SJoel Dice
886c09aa380SJoel Dice Ok(())
887c09aa380SJoel Dice }
888