wasmtime/runtime/component/func.rs
1use crate::component::instance::Instance;
2use crate::component::matching::InstanceType;
3use crate::component::storage::storage_as_slice;
4use crate::component::types::ComponentFunc;
5use crate::component::values::Val;
6use crate::prelude::*;
7use crate::runtime::vm::component::{ComponentInstance, InstanceFlags, ResourceTables};
8use crate::runtime::vm::{Export, VMFuncRef};
9use crate::store::StoreOpaque;
10use crate::{AsContext, AsContextMut, StoreContextMut, ValRaw};
11use core::mem::{self, MaybeUninit};
12use core::ptr::NonNull;
13use wasmtime_environ::component::{
14 CanonicalOptions, ExportIndex, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, OptionsIndex,
15 TypeFuncIndex, TypeTuple,
16};
17
18#[cfg(feature = "component-model-async")]
19use crate::component::concurrent::{self, AsAccessor, PreparedCall};
20
21mod host;
22mod options;
23mod typed;
24pub use self::host::*;
25pub use self::options::*;
26pub use self::typed::*;
27
28/// A WebAssembly component function which can be called.
29///
30/// This type is the dual of [`wasmtime::Func`](crate::Func) for component
31/// functions. An instance of [`Func`] represents a component function from a
32/// component [`Instance`](crate::component::Instance). Like with
33/// [`wasmtime::Func`](crate::Func) it's possible to call functions either
34/// synchronously or asynchronously and either typed or untyped.
35#[derive(Copy, Clone, Debug)]
36#[repr(C)] // here for the C API.
37pub struct Func {
38 instance: Instance,
39 index: ExportIndex,
40}
41
42// Double-check that the C representation in `component/instance.h` matches our
43// in-Rust representation here in terms of size/alignment/etc.
44const _: () = {
45 #[repr(C)]
46 struct T(u64, u32);
47 #[repr(C)]
48 struct C(T, u32);
49 assert!(core::mem::size_of::<C>() == core::mem::size_of::<Func>());
50 assert!(core::mem::align_of::<C>() == core::mem::align_of::<Func>());
51 assert!(core::mem::offset_of!(Func, instance) == 0);
52};
53
54impl Func {
55 pub(crate) fn from_lifted_func(instance: Instance, index: ExportIndex) -> Func {
56 Func { instance, index }
57 }
58
59 /// Attempt to cast this [`Func`] to a statically typed [`TypedFunc`] with
60 /// the provided `Params` and `Return`.
61 ///
62 /// This function will perform a type-check at runtime that the [`Func`]
63 /// takes `Params` as parameters and returns `Return`. If the type-check
64 /// passes then a [`TypedFunc`] will be returned which can be used to
65 /// invoke the function in an efficient, statically-typed, and ergonomic
66 /// manner.
67 ///
68 /// The `Params` type parameter here is a tuple of the parameters to the
69 /// function. A function which takes no arguments should use `()`, a
70 /// function with one argument should use `(T,)`, etc. Note that all
71 /// `Params` must also implement the [`Lower`] trait since they're going
72 /// into wasm.
73 ///
74 /// The `Return` type parameter is the return value of this function. A
75 /// return value of `()` means that there's no return (similar to a Rust
76 /// unit return) and otherwise a type `T` can be specified. Note that the
77 /// `Return` must also implement the [`Lift`] trait since it's coming from
78 /// wasm.
79 ///
80 /// Types specified here must implement the [`ComponentType`] trait. This
81 /// trait is implemented for built-in types to Rust such as integer
82 /// primitives, floats, `Option<T>`, `Result<T, E>`, strings, `Vec<T>`, and
83 /// more. As parameters you'll be passing native Rust types.
84 ///
85 /// See the documentation for [`ComponentType`] for more information about
86 /// supported types.
87 ///
88 /// # Errors
89 ///
90 /// If the function does not actually take `Params` as its parameters or
91 /// return `Return` then an error will be returned.
92 ///
93 /// # Panics
94 ///
95 /// This function will panic if `self` is not owned by the `store`
96 /// specified.
97 ///
98 /// # Examples
99 ///
100 /// Calling a function which takes no parameters and has no return value:
101 ///
102 /// ```
103 /// # use wasmtime::component::Func;
104 /// # use wasmtime::Store;
105 /// # fn foo(func: &Func, store: &mut Store<()>) -> wasmtime::Result<()> {
106 /// let typed = func.typed::<(), ()>(&store)?;
107 /// typed.call(store, ())?;
108 /// # Ok(())
109 /// # }
110 /// ```
111 ///
112 /// Calling a function which takes one string parameter and returns a
113 /// string:
114 ///
115 /// ```
116 /// # use wasmtime::component::Func;
117 /// # use wasmtime::Store;
118 /// # fn foo(func: &Func, mut store: Store<()>) -> wasmtime::Result<()> {
119 /// let typed = func.typed::<(&str,), (String,)>(&store)?;
120 /// let ret = typed.call(&mut store, ("Hello, ",))?.0;
121 /// println!("returned string was: {}", ret);
122 /// # Ok(())
123 /// # }
124 /// ```
125 ///
126 /// Calling a function which takes multiple parameters and returns a boolean:
127 ///
128 /// ```
129 /// # use wasmtime::component::Func;
130 /// # use wasmtime::Store;
131 /// # fn foo(func: &Func, mut store: Store<()>) -> wasmtime::Result<()> {
132 /// let typed = func.typed::<(u32, Option<&str>, &[u8]), (bool,)>(&store)?;
133 /// let ok: bool = typed.call(&mut store, (1, Some("hello"), b"bytes!"))?.0;
134 /// println!("return value was: {ok}");
135 /// # Ok(())
136 /// # }
137 /// ```
138 pub fn typed<Params, Return>(&self, store: impl AsContext) -> Result<TypedFunc<Params, Return>>
139 where
140 Params: ComponentNamedList + Lower,
141 Return: ComponentNamedList + Lift,
142 {
143 self._typed(store.as_context().0, None)
144 }
145
146 pub(crate) fn _typed<Params, Return>(
147 &self,
148 store: &StoreOpaque,
149 instance: Option<&ComponentInstance>,
150 ) -> Result<TypedFunc<Params, Return>>
151 where
152 Params: ComponentNamedList + Lower,
153 Return: ComponentNamedList + Lift,
154 {
155 self.typecheck::<Params, Return>(store, instance)?;
156 unsafe { Ok(TypedFunc::new_unchecked(*self)) }
157 }
158
159 fn typecheck<Params, Return>(
160 &self,
161 store: &StoreOpaque,
162 instance: Option<&ComponentInstance>,
163 ) -> Result<()>
164 where
165 Params: ComponentNamedList + Lower,
166 Return: ComponentNamedList + Lift,
167 {
168 let cx = InstanceType::new(instance.unwrap_or_else(|| self.instance.id().get(store)));
169 let ty = &cx.types[self.ty_index(store)];
170
171 Params::typecheck(&InterfaceType::Tuple(ty.params), &cx)
172 .context("type mismatch with parameters")?;
173 Return::typecheck(&InterfaceType::Tuple(ty.results), &cx)
174 .context("type mismatch with results")?;
175
176 Ok(())
177 }
178
179 /// Get the type of this function.
180 pub fn ty(&self, store: impl AsContext) -> ComponentFunc {
181 self.ty_(store.as_context().0)
182 }
183
184 fn ty_(&self, store: &StoreOpaque) -> ComponentFunc {
185 let cx = InstanceType::new(self.instance.id().get(store));
186 let ty = self.ty_index(store);
187 ComponentFunc::from(ty, &cx)
188 }
189
190 fn ty_index(&self, store: &StoreOpaque) -> TypeFuncIndex {
191 let instance = self.instance.id().get(store);
192 let (ty, _, _) = instance.component().export_lifted_function(self.index);
193 ty
194 }
195
196 /// Invokes this function with the `params` given and returns the result.
197 ///
198 /// The `params` provided must match the parameters that this function takes
199 /// in terms of their types and the number of parameters. Results will be
200 /// written to the `results` slice provided if the call completes
201 /// successfully. The initial types of the values in `results` are ignored
202 /// and values are overwritten to write the result. It's required that the
203 /// size of `results` exactly matches the number of results that this
204 /// function produces.
205 ///
206 /// Note that after a function is invoked the embedder needs to invoke
207 /// [`Func::post_return`] to execute any final cleanup required by the
208 /// guest. This function call is required to either call the function again
209 /// or to call another function.
210 ///
211 /// For more detailed information see the documentation of
212 /// [`TypedFunc::call`].
213 ///
214 /// # Errors
215 ///
216 /// Returns an error in situations including but not limited to:
217 ///
218 /// * `params` is not the right size or if the values have the wrong type
219 /// * `results` is not the right size
220 /// * A trap occurs while executing the function
221 /// * The function calls a host function which returns an error
222 ///
223 /// See [`TypedFunc::call`] for more information in addition to
224 /// [`wasmtime::Func::call`](crate::Func::call).
225 ///
226 /// # Panics
227 ///
228 /// Panics if this is called on a function in an asynchronous store. This
229 /// only works with functions defined within a synchronous store. Also
230 /// panics if `store` does not own this function.
231 pub fn call(
232 &self,
233 mut store: impl AsContextMut,
234 params: &[Val],
235 results: &mut [Val],
236 ) -> Result<()> {
237 let mut store = store.as_context_mut();
238 assert!(
239 !store.0.async_support(),
240 "must use `call_async` when async support is enabled on the config"
241 );
242 self.call_impl(&mut store.as_context_mut(), params, results)
243 }
244
245 /// Exactly like [`Self::call`] except for use on async stores.
246 ///
247 /// Note that after this [`Func::post_return_async`] will be used instead of
248 /// the synchronous version at [`Func::post_return`].
249 ///
250 /// # Panics
251 ///
252 /// Panics if this is called on a function in a synchronous store. This
253 /// only works with functions defined within an asynchronous store. Also
254 /// panics if `store` does not own this function.
255 #[cfg(feature = "async")]
256 pub async fn call_async(
257 &self,
258 mut store: impl AsContextMut<Data: Send>,
259 params: &[Val],
260 results: &mut [Val],
261 ) -> Result<()> {
262 let store = store.as_context_mut();
263
264 #[cfg(feature = "component-model-async")]
265 {
266 store
267 .run_concurrent_trap_on_idle(async |store| {
268 self.call_concurrent_dynamic(store, params, results, false)
269 .await
270 .map(drop)
271 })
272 .await?
273 }
274 #[cfg(not(feature = "component-model-async"))]
275 {
276 assert!(
277 store.0.async_support(),
278 "cannot use `call_async` without enabling async support in the config"
279 );
280 let mut store = store;
281 store
282 .on_fiber(|store| self.call_impl(store, params, results))
283 .await?
284 }
285 }
286
287 fn check_params_results<T>(
288 &self,
289 store: StoreContextMut<T>,
290 params: &[Val],
291 results: &mut [Val],
292 ) -> Result<()> {
293 let ty = self.ty(&store);
294 if ty.params().len() != params.len() {
295 bail!(
296 "expected {} argument(s), got {}",
297 ty.params().len(),
298 params.len(),
299 );
300 }
301
302 if ty.results().len() != results.len() {
303 bail!(
304 "expected {} result(s), got {}",
305 ty.results().len(),
306 results.len(),
307 );
308 }
309
310 Ok(())
311 }
312
313 /// Start a concurrent call to this function.
314 ///
315 /// Unlike [`Self::call`] and [`Self::call_async`] (both of which require
316 /// exclusive access to the store until the completion of the call), calls
317 /// made using this method may run concurrently with other calls to the same
318 /// instance. In addition, the runtime will call the `post-return` function
319 /// (if any) automatically when the guest task completes -- no need to
320 /// explicitly call `Func::post_return` afterward.
321 ///
322 /// This returns a [`TaskExit`] representing the completion of the guest
323 /// task and any transitive subtasks it might create.
324 ///
325 /// # Progress
326 ///
327 /// For the wasm task being created in `call_concurrent` to make progress it
328 /// must be run within the scope of [`run_concurrent`]. If there are no
329 /// active calls to [`run_concurrent`] then the wasm task will appear as
330 /// stalled. This is typically not a concern as an [`Accessor`] is bound
331 /// by default to a scope of [`run_concurrent`].
332 ///
333 /// One situation in which this can arise, for example, is that if a
334 /// [`run_concurrent`] computation finishes its async closure before all
335 /// wasm tasks have completed, then there will be no scope of
336 /// [`run_concurrent`] anywhere. In this situation the wasm tasks that have
337 /// not yet completed will not make progress until [`run_concurrent`] is
338 /// called again.
339 ///
340 /// Embedders will need to ensure that this future is `await`'d within the
341 /// scope of [`run_concurrent`] to ensure that the value can be produced
342 /// during the `await` call.
343 ///
344 /// # Cancellation
345 ///
346 /// Cancelling an async task created via `call_concurrent`, at this time, is
347 /// only possible by dropping the store that the computation runs within.
348 /// With [#11833] implemented then it will be possible to request
349 /// cancellation of a task, but that is not yet implemented. Hard-cancelling
350 /// a task will only ever be possible by dropping the entire store and it is
351 /// not possible to remove just one task from a store.
352 ///
353 /// This async function behaves more like a "spawn" than a normal Rust async
354 /// function. When this function is invoked then metadata for the function
355 /// call is recorded in the store connected to the `accessor` argument and
356 /// the wasm invocation is from then on connected to the store. If the
357 /// future created by this function is dropped it does not cancel the
358 /// in-progress execution of the wasm task. Dropping the future
359 /// relinquishes the host's ability to learn about the result of the task
360 /// but the task will still progress and invoke callbacks and such until
361 /// completion.
362 ///
363 /// [`run_concurrent`]: crate::Store::run_concurrent
364 /// [#11833]: https://github.com/bytecodealliance/wasmtime/issues/11833
365 /// [`Accessor`]: crate::component::Accessor
366 ///
367 /// # Panics
368 ///
369 /// Panics if the store that the [`Accessor`] is derived from does not own
370 /// this function.
371 #[cfg(feature = "component-model-async")]
372 pub async fn call_concurrent(
373 self,
374 accessor: impl AsAccessor<Data: Send>,
375 params: &[Val],
376 results: &mut [Val],
377 ) -> Result<TaskExit> {
378 self.call_concurrent_dynamic(accessor, params, results, true)
379 .await
380 }
381
382 /// Internal helper function for `call_async` and `call_concurrent`.
383 #[cfg(feature = "component-model-async")]
384 async fn call_concurrent_dynamic(
385 self,
386 accessor: impl AsAccessor<Data: Send>,
387 params: &[Val],
388 results: &mut [Val],
389 call_post_return_automatically: bool,
390 ) -> Result<TaskExit> {
391 let result = accessor.as_accessor().with(|mut store| {
392 assert!(
393 store.as_context_mut().0.async_support(),
394 "cannot use `call_concurrent` when async support is not enabled on the config"
395 );
396 self.check_params_results(store.as_context_mut(), params, results)?;
397 let prepared = self.prepare_call_dynamic(
398 store.as_context_mut(),
399 params.to_vec(),
400 call_post_return_automatically,
401 )?;
402 concurrent::queue_call(store.as_context_mut(), prepared)
403 })?;
404
405 let (run_results, rx) = result.await?;
406 assert_eq!(run_results.len(), results.len());
407 for (result, slot) in run_results.into_iter().zip(results) {
408 *slot = result;
409 }
410 Ok(TaskExit(rx))
411 }
412
413 /// Calls `concurrent::prepare_call` with monomorphized functions for
414 /// lowering the parameters and lifting the result.
415 #[cfg(feature = "component-model-async")]
416 fn prepare_call_dynamic<'a, T: Send + 'static>(
417 self,
418 mut store: StoreContextMut<'a, T>,
419 params: Vec<Val>,
420 call_post_return_automatically: bool,
421 ) -> Result<PreparedCall<Vec<Val>>> {
422 let store = store.as_context_mut();
423
424 concurrent::prepare_call(
425 store,
426 self,
427 MAX_FLAT_PARAMS,
428 false,
429 call_post_return_automatically,
430 move |func, store, params_out| {
431 func.with_lower_context(store, call_post_return_automatically, |cx, ty| {
432 Self::lower_args(cx, ¶ms, ty, params_out)
433 })
434 },
435 move |func, store, results| {
436 let max_flat = if func.abi_async(store) {
437 MAX_FLAT_PARAMS
438 } else {
439 MAX_FLAT_RESULTS
440 };
441 let results = func.with_lift_context(store, |cx, ty| {
442 Self::lift_results(cx, ty, results, max_flat)?.collect::<Result<Vec<_>>>()
443 })?;
444 Ok(Box::new(results))
445 },
446 )
447 }
448
449 fn call_impl(
450 &self,
451 mut store: impl AsContextMut,
452 params: &[Val],
453 results: &mut [Val],
454 ) -> Result<()> {
455 let mut store = store.as_context_mut();
456
457 self.check_params_results(store.as_context_mut(), params, results)?;
458
459 if self.abi_async(store.0) {
460 unreachable!(
461 "async-lifted exports should have failed validation \
462 when `component-model-async` feature disabled"
463 );
464 }
465
466 // SAFETY: the chosen representations of type parameters to `call_raw`
467 // here should be generally safe to work with:
468 //
469 // * parameters use `MaybeUninit<[MaybeUninit<ValRaw>; MAX_FLAT_PARAMS]>`
470 // which represents the maximal possible number of parameters that can
471 // be passed to lifted component functions. This is modeled with
472 // `MaybeUninit` to represent how it all starts as uninitialized and
473 // thus can't be safely read during lowering.
474 //
475 // * results are modeled as `[ValRaw; MAX_FLAT_RESULTS]` which
476 // represents the maximal size of values that can be returned. Note
477 // that if the function doesn't actually have a return value then the
478 // `ValRaw` inside the array will have undefined contents. That is
479 // safe in Rust, however, due to `ValRaw` being a `union`. The
480 // contents should dynamically not be read due to the type of the
481 // function used here matching the actual lift.
482 unsafe {
483 self.call_raw(
484 store,
485 |cx, ty, dst: &mut MaybeUninit<[MaybeUninit<ValRaw>; MAX_FLAT_PARAMS]>| {
486 // SAFETY: it's safe to assume that
487 // `MaybeUninit<array-of-maybe-uninit>` is initialized because
488 // each individual element is still considered uninitialized.
489 let dst: &mut [MaybeUninit<ValRaw>] = dst.assume_init_mut();
490 Self::lower_args(cx, params, ty, dst)
491 },
492 |cx, results_ty, src: &[ValRaw; MAX_FLAT_RESULTS]| {
493 let max_flat = MAX_FLAT_RESULTS;
494 for (result, slot) in
495 Self::lift_results(cx, results_ty, src, max_flat)?.zip(results)
496 {
497 *slot = result?;
498 }
499 Ok(())
500 },
501 )
502 }
503 }
504
505 pub(crate) fn lifted_core_func(&self, store: &mut StoreOpaque) -> NonNull<VMFuncRef> {
506 let def = {
507 let instance = self.instance.id().get(store);
508 let (_ty, def, _options) = instance.component().export_lifted_function(self.index);
509 def.clone()
510 };
511 match self.instance.lookup_vmdef(store, &def) {
512 Export::Function(f) => f.vm_func_ref(store),
513 _ => unreachable!(),
514 }
515 }
516
517 pub(crate) fn post_return_core_func(&self, store: &StoreOpaque) -> Option<NonNull<VMFuncRef>> {
518 let instance = self.instance.id().get(store);
519 let component = instance.component();
520 let (_ty, _def, options) = component.export_lifted_function(self.index);
521 let post_return = component.env_component().options[options].post_return;
522 post_return.map(|i| instance.runtime_post_return(i))
523 }
524
525 pub(crate) fn abi_async(&self, store: &StoreOpaque) -> bool {
526 let instance = self.instance.id().get(store);
527 let component = instance.component();
528 let (_ty, _def, options) = component.export_lifted_function(self.index);
529 component.env_component().options[options].async_
530 }
531
532 pub(crate) fn abi_info<'a>(
533 &self,
534 store: &'a StoreOpaque,
535 ) -> (
536 OptionsIndex,
537 InstanceFlags,
538 TypeFuncIndex,
539 &'a CanonicalOptions,
540 ) {
541 let vminstance = self.instance.id().get(store);
542 let component = vminstance.component();
543 let (ty, _def, options_index) = component.export_lifted_function(self.index);
544 let raw_options = &component.env_component().options[options_index];
545 (
546 options_index,
547 vminstance.instance_flags(raw_options.instance),
548 ty,
549 raw_options,
550 )
551 }
552
553 /// Invokes the underlying wasm function, lowering arguments and lifting the
554 /// result.
555 ///
556 /// The `lower` function and `lift` function provided here are what actually
557 /// do the lowering and lifting. The `LowerParams` and `LowerReturn` types
558 /// are what will be allocated on the stack for this function call. They
559 /// should be appropriately sized for the lowering/lifting operation
560 /// happening.
561 ///
562 /// # Safety
563 ///
564 /// The safety of this function relies on the correct definitions of the
565 /// `LowerParams` and `LowerReturn` type. They must match the type of `self`
566 /// for the params/results that are going to be produced. Additionally
567 /// these types must be representable with a sequence of `ValRaw` values.
568 unsafe fn call_raw<T, Return, LowerParams, LowerReturn>(
569 &self,
570 mut store: StoreContextMut<'_, T>,
571 lower: impl FnOnce(
572 &mut LowerContext<'_, T>,
573 InterfaceType,
574 &mut MaybeUninit<LowerParams>,
575 ) -> Result<()>,
576 lift: impl FnOnce(&mut LiftContext<'_>, InterfaceType, &LowerReturn) -> Result<Return>,
577 ) -> Result<Return>
578 where
579 LowerParams: Copy,
580 LowerReturn: Copy,
581 {
582 let export = self.lifted_core_func(store.0);
583
584 #[repr(C)]
585 union Union<Params: Copy, Return: Copy> {
586 params: Params,
587 ret: Return,
588 }
589
590 let space = &mut MaybeUninit::<Union<LowerParams, LowerReturn>>::uninit();
591
592 // Double-check the size/alignment of `space`, just in case.
593 //
594 // Note that this alone is not enough to guarantee the validity of the
595 // `unsafe` block below, but it's definitely required. In any case LLVM
596 // should be able to trivially see through these assertions and remove
597 // them in release mode.
598 let val_size = mem::size_of::<ValRaw>();
599 let val_align = mem::align_of::<ValRaw>();
600 assert!(mem::size_of_val(space) % val_size == 0);
601 assert!(mem::size_of_val(map_maybe_uninit!(space.params)) % val_size == 0);
602 assert!(mem::size_of_val(map_maybe_uninit!(space.ret)) % val_size == 0);
603 assert!(mem::align_of_val(space) == val_align);
604 assert!(mem::align_of_val(map_maybe_uninit!(space.params)) == val_align);
605 assert!(mem::align_of_val(map_maybe_uninit!(space.ret)) == val_align);
606
607 self.with_lower_context(store.as_context_mut(), false, |cx, ty| {
608 cx.enter_call();
609 lower(cx, ty, map_maybe_uninit!(space.params))
610 })?;
611
612 // SAFETY: We are providing the guarantee that all the inputs are valid.
613 // The various pointers passed in for the function are all valid since
614 // they're coming from our store, and the `params_and_results` should
615 // have the correct layout for the core wasm function we're calling.
616 // Note that this latter point relies on the correctness of this module
617 // and `ComponentType` implementations, hence `ComponentType` being an
618 // `unsafe` trait.
619 unsafe {
620 crate::Func::call_unchecked_raw(
621 &mut store,
622 export,
623 NonNull::new(core::ptr::slice_from_raw_parts_mut(
624 space.as_mut_ptr().cast(),
625 mem::size_of_val(space) / mem::size_of::<ValRaw>(),
626 ))
627 .unwrap(),
628 )?;
629 }
630
631 // SAFETY: We're relying on the correctness of the structure of
632 // `LowerReturn` and the type-checking performed to acquire the
633 // `TypedFunc` to make this safe. It should be the case that
634 // `LowerReturn` is the exact representation of the return value when
635 // interpreted as `[ValRaw]`, and additionally they should have the
636 // correct types for the function we just called (which filled in the
637 // return values).
638 let ret: &LowerReturn = unsafe { map_maybe_uninit!(space.ret).assume_init_ref() };
639
640 // Lift the result into the host while managing post-return state
641 // here as well.
642 //
643 // After a successful lift the return value of the function, which
644 // is currently required to be 0 or 1 values according to the
645 // canonical ABI, is saved within the `Store`'s `FuncData`. This'll
646 // later get used in post-return.
647 // flags.set_needs_post_return(true);
648 let val = self.with_lift_context(store.0, |cx, ty| lift(cx, ty, ret))?;
649
650 // SAFETY: it's a contract of this function that `LowerReturn` is an
651 // appropriate representation of the result of this function.
652 let ret_slice = unsafe { storage_as_slice(ret) };
653
654 self.instance.id().get_mut(store.0).post_return_arg_set(
655 self.index,
656 match ret_slice.len() {
657 0 => ValRaw::i32(0),
658 1 => ret_slice[0],
659 _ => unreachable!(),
660 },
661 );
662 return Ok(val);
663 }
664
665 /// Invokes the `post-return` canonical ABI option, if specified, after a
666 /// [`Func::call`] has finished.
667 ///
668 /// This function is a required method call after a [`Func::call`] completes
669 /// successfully. After the embedder has finished processing the return
670 /// value then this function must be invoked.
671 ///
672 /// # Errors
673 ///
674 /// This function will return an error in the case of a WebAssembly trap
675 /// happening during the execution of the `post-return` function, if
676 /// specified.
677 ///
678 /// # Panics
679 ///
680 /// This function will panic if it's not called under the correct
681 /// conditions. This can only be called after a previous invocation of
682 /// [`Func::call`] completes successfully, and this function can only
683 /// be called for the same [`Func`] that was `call`'d.
684 ///
685 /// If this function is called when [`Func::call`] was not previously
686 /// called, then it will panic. If a different [`Func`] for the same
687 /// component instance was invoked then this function will also panic
688 /// because the `post-return` needs to happen for the other function.
689 ///
690 /// Panics if this is called on a function in an asynchronous store.
691 /// This only works with functions defined within a synchronous store.
692 #[inline]
693 pub fn post_return(&self, mut store: impl AsContextMut) -> Result<()> {
694 let store = store.as_context_mut();
695 assert!(
696 !store.0.async_support(),
697 "must use `post_return_async` when async support is enabled on the config"
698 );
699 self.post_return_impl(store)
700 }
701
702 /// Exactly like [`Self::post_return`] except for use on async stores.
703 ///
704 /// # Panics
705 ///
706 /// Panics if this is called on a function in a synchronous store. This
707 /// only works with functions defined within an asynchronous store.
708 #[cfg(feature = "async")]
709 pub async fn post_return_async(&self, mut store: impl AsContextMut<Data: Send>) -> Result<()> {
710 let mut store = store.as_context_mut();
711 assert!(
712 store.0.async_support(),
713 "cannot use `post_return_async` without enabling async support in the config"
714 );
715 // Future optimization opportunity: conditionally use a fiber here since
716 // some func's post_return will not need the async context (i.e. end up
717 // calling async host functionality)
718 store.on_fiber(|store| self.post_return_impl(store)).await?
719 }
720
721 fn post_return_impl(&self, mut store: impl AsContextMut) -> Result<()> {
722 let mut store = store.as_context_mut();
723
724 let index = self.index;
725 let vminstance = self.instance.id().get(store.0);
726 let component = vminstance.component();
727 let (_ty, _def, options) = component.export_lifted_function(index);
728 let post_return = self.post_return_core_func(store.0);
729 let mut flags =
730 vminstance.instance_flags(component.env_component().options[options].instance);
731 let mut instance = self.instance.id().get_mut(store.0);
732 let post_return_arg = instance.as_mut().post_return_arg_take(index);
733
734 unsafe {
735 // First assert that the instance is in a "needs post return" state.
736 // This will ensure that the previous action on the instance was a
737 // function call above. This flag is only set after a component
738 // function returns so this also can't be called (as expected)
739 // during a host import for example.
740 //
741 // Note, though, that this assert is not sufficient because it just
742 // means some function on this instance needs its post-return
743 // called. We need a precise post-return for a particular function
744 // which is the second assert here (the `.expect`). That will assert
745 // that this function itself needs to have its post-return called.
746 //
747 // The theory at least is that these two asserts ensure component
748 // model semantics are upheld where the host properly calls
749 // `post_return` on the right function despite the call being a
750 // separate step in the API.
751 assert!(
752 flags.needs_post_return(),
753 "post_return can only be called after a function has previously been called",
754 );
755 let post_return_arg = post_return_arg.expect("calling post_return on wrong function");
756
757 // This is a sanity-check assert which shouldn't ever trip.
758 assert!(!flags.may_enter());
759
760 // Unset the "needs post return" flag now that post-return is being
761 // processed. This will cause future invocations of this method to
762 // panic, even if the function call below traps.
763 flags.set_needs_post_return(false);
764
765 // Post return functions are forbidden from calling imports or
766 // intrinsics.
767 flags.set_may_leave(false);
768
769 // If the function actually had a `post-return` configured in its
770 // canonical options that's executed here.
771 //
772 // Note that if this traps (returns an error) this function
773 // intentionally leaves the instance in a "poisoned" state where it
774 // can no longer be entered because `may_enter` is `false`.
775 if let Some(func) = post_return {
776 crate::Func::call_unchecked_raw(
777 &mut store,
778 func,
779 NonNull::new(core::ptr::slice_from_raw_parts(&post_return_arg, 1).cast_mut())
780 .unwrap(),
781 )?;
782 }
783
784 // And finally if everything completed successfully then the "may
785 // enter" and "may leave" flags are set to `true` again here which
786 // enables further use of the component.
787 flags.set_may_enter(true);
788 flags.set_may_leave(true);
789
790 let (calls, host_table, _, instance) = store
791 .0
792 .component_resource_state_with_instance(self.instance);
793 ResourceTables {
794 host_table: Some(host_table),
795 calls,
796 guest: Some(instance.instance_states()),
797 }
798 .exit_call()?;
799 }
800 Ok(())
801 }
802
803 fn lower_args<T>(
804 cx: &mut LowerContext<'_, T>,
805 params: &[Val],
806 params_ty: InterfaceType,
807 dst: &mut [MaybeUninit<ValRaw>],
808 ) -> Result<()> {
809 let params_ty = match params_ty {
810 InterfaceType::Tuple(i) => &cx.types[i],
811 _ => unreachable!(),
812 };
813 if params_ty.abi.flat_count(MAX_FLAT_PARAMS).is_some() {
814 let dst = &mut dst.iter_mut();
815
816 params
817 .iter()
818 .zip(params_ty.types.iter())
819 .try_for_each(|(param, ty)| param.lower(cx, *ty, dst))
820 } else {
821 Self::store_args(cx, ¶ms_ty, params, dst)
822 }
823 }
824
825 fn store_args<T>(
826 cx: &mut LowerContext<'_, T>,
827 params_ty: &TypeTuple,
828 args: &[Val],
829 dst: &mut [MaybeUninit<ValRaw>],
830 ) -> Result<()> {
831 let size = usize::try_from(params_ty.abi.size32).unwrap();
832 let ptr = cx.realloc(0, 0, params_ty.abi.align32, size)?;
833 let mut offset = ptr;
834 for (ty, arg) in params_ty.types.iter().zip(args) {
835 let abi = cx.types.canonical_abi(ty);
836 arg.store(cx, *ty, abi.next_field32_size(&mut offset))?;
837 }
838
839 dst[0].write(ValRaw::i64(ptr as i64));
840
841 Ok(())
842 }
843
844 fn lift_results<'a, 'b>(
845 cx: &'a mut LiftContext<'b>,
846 results_ty: InterfaceType,
847 src: &'a [ValRaw],
848 max_flat: usize,
849 ) -> Result<Box<dyn Iterator<Item = Result<Val>> + 'a>> {
850 let results_ty = match results_ty {
851 InterfaceType::Tuple(i) => &cx.types[i],
852 _ => unreachable!(),
853 };
854 if results_ty.abi.flat_count(max_flat).is_some() {
855 let mut flat = src.iter();
856 Ok(Box::new(
857 results_ty
858 .types
859 .iter()
860 .map(move |ty| Val::lift(cx, *ty, &mut flat)),
861 ))
862 } else {
863 let iter = Self::load_results(cx, results_ty, &mut src.iter())?;
864 Ok(Box::new(iter))
865 }
866 }
867
868 fn load_results<'a, 'b>(
869 cx: &'a mut LiftContext<'b>,
870 results_ty: &'a TypeTuple,
871 src: &mut core::slice::Iter<'_, ValRaw>,
872 ) -> Result<impl Iterator<Item = Result<Val>> + use<'a, 'b>> {
873 // FIXME(#4311): needs to read an i64 for memory64
874 let ptr = usize::try_from(src.next().unwrap().get_u32())?;
875 if ptr % usize::try_from(results_ty.abi.align32)? != 0 {
876 bail!("return pointer not aligned");
877 }
878
879 let bytes = cx
880 .memory()
881 .get(ptr..)
882 .and_then(|b| b.get(..usize::try_from(results_ty.abi.size32).unwrap()))
883 .ok_or_else(|| crate::format_err!("pointer out of bounds of memory"))?;
884
885 let mut offset = 0;
886 Ok(results_ty.types.iter().map(move |ty| {
887 let abi = cx.types.canonical_abi(ty);
888 let offset = abi.next_field32_size(&mut offset);
889 Val::load(cx, *ty, &bytes[offset..][..abi.size32 as usize])
890 }))
891 }
892
893 #[cfg(feature = "component-model-async")]
894 pub(crate) fn instance(self) -> Instance {
895 self.instance
896 }
897
898 #[cfg(feature = "component-model-async")]
899 pub(crate) fn index(self) -> ExportIndex {
900 self.index
901 }
902
903 /// Creates a `LowerContext` using the configuration values of this lifted
904 /// function.
905 ///
906 /// The `lower` closure provided should perform the actual lowering and
907 /// return the result of the lowering operation which is then returned from
908 /// this function as well.
909 fn with_lower_context<T>(
910 self,
911 mut store: StoreContextMut<T>,
912 may_enter: bool,
913 lower: impl FnOnce(&mut LowerContext<T>, InterfaceType) -> Result<()>,
914 ) -> Result<()> {
915 let (options_idx, mut flags, ty, options) = self.abi_info(store.0);
916 let async_ = options.async_;
917
918 // Test the "may enter" flag which is a "lock" on this instance.
919 // This is immediately set to `false` afterwards and note that
920 // there's no on-cleanup setting this flag back to true. That's an
921 // intentional design aspect where if anything goes wrong internally
922 // from this point on the instance is considered "poisoned" and can
923 // never be entered again. The only time this flag is set to `true`
924 // again is after post-return logic has completed successfully.
925 unsafe {
926 if !flags.may_enter() {
927 bail!(crate::Trap::CannotEnterComponent);
928 }
929 flags.set_may_enter(false);
930 }
931
932 // Perform the actual lowering, where while this is running the
933 // component is forbidden from calling imports.
934 unsafe {
935 debug_assert!(flags.may_leave());
936 flags.set_may_leave(false);
937 }
938 let mut cx = LowerContext::new(store.as_context_mut(), options_idx, self.instance);
939 let param_ty = InterfaceType::Tuple(cx.types[ty].params);
940 let result = lower(&mut cx, param_ty);
941 unsafe { flags.set_may_leave(true) };
942 result?;
943
944 // If this is an async function and `may_enter == true` then we're
945 // allowed to reenter the component at this point, and otherwise flag a
946 // post-return call being required as we're about to enter wasm and
947 // afterwards need a post-return.
948 unsafe {
949 if may_enter && async_ {
950 flags.set_may_enter(true);
951 } else {
952 flags.set_needs_post_return(true);
953 }
954 }
955
956 Ok(())
957 }
958
959 /// Creates a `LiftContext` using the configuration values with this lifted
960 /// function.
961 ///
962 /// The closure `lift` provided should actually perform the lift itself and
963 /// the result of that closure is returned from this function call as well.
964 fn with_lift_context<R>(
965 self,
966 store: &mut StoreOpaque,
967 lift: impl FnOnce(&mut LiftContext, InterfaceType) -> Result<R>,
968 ) -> Result<R> {
969 let (options, _flags, ty, _) = self.abi_info(store);
970 let mut cx = LiftContext::new(store, options, self.instance);
971 let ty = InterfaceType::Tuple(cx.types[ty].results);
972 lift(&mut cx, ty)
973 }
974}
975
976/// Represents the completion of a task created using
977/// `[Typed]Func::call_concurrent`.
978///
979/// In general, a guest task may continue running after returning a value.
980/// Moreover, any given guest task may create its own subtasks before or after
981/// returning and may exit before some or all of those subtasks have finished
982/// running. In that case, the still-running subtasks will be "reparented" to
983/// the nearest surviving caller, which may be the original host call. The
984/// future returned by `TaskExit::block` will resolve once all transitive
985/// subtasks created directly or indirectly by the original call to
986/// `Instance::call_concurrent` have exited.
987#[cfg(feature = "component-model-async")]
988pub struct TaskExit(futures::channel::oneshot::Receiver<()>);
989
990#[cfg(feature = "component-model-async")]
991impl TaskExit {
992 /// Returns a future which will resolve once all transitive subtasks created
993 /// directly or indirectly by the original call to
994 /// `Instance::call_concurrent` have exited.
995 pub async fn block(self, accessor: impl AsAccessor<Data: Send>) {
996 // The current implementation makes no use of `accessor`, but future
997 // implementations might (e.g. by using a more efficient mechanism than
998 // a oneshot channel).
999 _ = accessor;
1000
1001 // We don't care whether the sender sent us a value or was dropped
1002 // first; either one counts as a notification, so we ignore the result
1003 // once the future resolves:
1004 _ = self.0.await;
1005 }
1006}