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