wasmtime/runtime/component/func/
typed.rs

1use crate::component::Instance;
2use crate::component::func::{Func, LiftContext, LowerContext, Options};
3use crate::component::matching::InstanceType;
4use crate::component::storage::{storage_as_slice, storage_as_slice_mut};
5use crate::prelude::*;
6use crate::{AsContextMut, StoreContext, StoreContextMut, ValRaw};
7use alloc::borrow::Cow;
8use alloc::sync::Arc;
9use core::fmt;
10use core::iter;
11use core::marker;
12use core::mem::{self, MaybeUninit};
13use core::str;
14use wasmtime_environ::component::{
15    CanonicalAbiInfo, ComponentTypes, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS,
16    StringEncoding, VariantInfo,
17};
18
19#[cfg(feature = "component-model-async")]
20use crate::component::concurrent::{self, PreparedCall};
21#[cfg(feature = "component-model-async")]
22use core::future::Future;
23#[cfg(feature = "component-model-async")]
24use core::pin::Pin;
25
26/// A statically-typed version of [`Func`] which takes `Params` as input and
27/// returns `Return`.
28///
29/// This is an efficient way to invoke a WebAssembly component where if the
30/// inputs and output are statically known this can eschew the vast majority of
31/// machinery and checks when calling WebAssembly. This is the most optimized
32/// way to call a WebAssembly component.
33///
34/// Note that like [`Func`] this is a pointer within a [`Store`](crate::Store)
35/// and usage will panic if used with the wrong store.
36///
37/// This type is primarily created with the [`Func::typed`] API.
38///
39/// See [`ComponentType`] for more information about supported types.
40pub struct TypedFunc<Params, Return> {
41    func: Func,
42
43    // The definition of this field is somewhat subtle and may be surprising.
44    // Naively one might expect something like
45    //
46    //      _marker: marker::PhantomData<fn(Params) -> Return>,
47    //
48    // Since this is a function pointer after all. The problem with this
49    // definition though is that it imposes the wrong variance on `Params` from
50    // what we want. Abstractly a `fn(Params)` is able to store `Params` within
51    // it meaning you can only give it `Params` that live longer than the
52    // function pointer.
53    //
54    // With a component model function, however, we're always copying data from
55    // the host into the guest, so we are never storing pointers to `Params`
56    // into the guest outside the duration of a `call`, meaning we can actually
57    // accept values in `TypedFunc::call` which live for a shorter duration
58    // than the `Params` argument on the struct.
59    //
60    // This all means that we don't use a phantom function pointer, but instead
61    // feign phantom storage here to get the variance desired.
62    _marker: marker::PhantomData<(Params, Return)>,
63}
64
65impl<Params, Return> Copy for TypedFunc<Params, Return> {}
66
67impl<Params, Return> Clone for TypedFunc<Params, Return> {
68    fn clone(&self) -> TypedFunc<Params, Return> {
69        *self
70    }
71}
72
73impl<Params, Return> TypedFunc<Params, Return>
74where
75    Params: ComponentNamedList + Lower,
76    Return: ComponentNamedList + Lift,
77{
78    /// Creates a new [`TypedFunc`] from the provided component [`Func`],
79    /// unsafely asserting that the underlying function takes `Params` as
80    /// input and returns `Return`.
81    ///
82    /// # Unsafety
83    ///
84    /// This is an unsafe function because it does not verify that the [`Func`]
85    /// provided actually implements this signature. It's up to the caller to
86    /// have performed some other sort of check to ensure that the signature is
87    /// correct.
88    pub unsafe fn new_unchecked(func: Func) -> TypedFunc<Params, Return> {
89        TypedFunc {
90            _marker: marker::PhantomData,
91            func,
92        }
93    }
94
95    /// Returns the underlying un-typed [`Func`] that this [`TypedFunc`]
96    /// references.
97    pub fn func(&self) -> &Func {
98        &self.func
99    }
100
101    /// Calls the underlying WebAssembly component function using the provided
102    /// `params` as input.
103    ///
104    /// This method is used to enter into a component. Execution happens within
105    /// the `store` provided. The `params` are copied into WebAssembly memory
106    /// as appropriate and a core wasm function is invoked.
107    ///
108    /// # Post-return
109    ///
110    /// In the component model each function can have a "post return" specified
111    /// which allows cleaning up the arguments returned to the host. For example
112    /// if WebAssembly returns a string to the host then it might be a uniquely
113    /// allocated string which, after the host finishes processing it, needs to
114    /// be deallocated in the wasm instance's own linear memory to prevent
115    /// memory leaks in wasm itself. The `post-return` canonical abi option is
116    /// used to configured this.
117    ///
118    /// To accommodate this feature of the component model after invoking a
119    /// function via [`TypedFunc::call`] you must next invoke
120    /// [`TypedFunc::post_return`]. Note that the return value of the function
121    /// should be processed between these two function calls. The return value
122    /// continues to be usable from an embedder's perspective after
123    /// `post_return` is called, but after `post_return` is invoked it may no
124    /// longer retain the same value that the wasm module originally returned.
125    ///
126    /// Also note that [`TypedFunc::post_return`] must be invoked irrespective
127    /// of whether the canonical ABI option `post-return` was configured or not.
128    /// This means that embedders must unconditionally call
129    /// [`TypedFunc::post_return`] when a function returns. If this function
130    /// call returns an error, however, then [`TypedFunc::post_return`] is not
131    /// required.
132    ///
133    /// # Errors
134    ///
135    /// This function can return an error for a number of reasons:
136    ///
137    /// * If the wasm itself traps during execution.
138    /// * If the wasm traps while copying arguments into memory.
139    /// * If the wasm provides bad allocation pointers when copying arguments
140    ///   into memory.
141    /// * If the wasm returns a value which violates the canonical ABI.
142    /// * If this function's instances cannot be entered, for example if the
143    ///   instance is currently calling a host function.
144    /// * If a previous function call occurred and the corresponding
145    ///   `post_return` hasn't been invoked yet.
146    ///
147    /// In general there are many ways that things could go wrong when copying
148    /// types in and out of a wasm module with the canonical ABI, and certain
149    /// error conditions are specific to certain types. For example a
150    /// WebAssembly module can't return an invalid `char`. When allocating space
151    /// for this host to copy a string into the returned pointer must be
152    /// in-bounds in memory.
153    ///
154    /// If an error happens then the error should contain detailed enough
155    /// information to understand which part of the canonical ABI went wrong
156    /// and what to inspect.
157    ///
158    /// # Panics
159    ///
160    /// Panics if this is called on a function in an asynchronous store. This
161    /// only works with functions defined within a synchronous store. Also
162    /// panics if `store` does not own this function.
163    pub fn call(&self, store: impl AsContextMut, params: Params) -> Result<Return> {
164        assert!(
165            !store.as_context().async_support(),
166            "must use `call_async` when async support is enabled on the config"
167        );
168        self.call_impl(store, params)
169    }
170
171    /// Exactly like [`Self::call`], except for use on asynchronous stores.
172    ///
173    /// # Panics
174    ///
175    /// Panics if this is called on a function in a synchronous store. This
176    /// only works with functions defined within an asynchronous store. Also
177    /// panics if `store` does not own this function.
178    #[cfg(feature = "async")]
179    pub async fn call_async(
180        &self,
181        mut store: impl AsContextMut<Data: Send>,
182        params: Params,
183    ) -> Result<Return>
184    where
185        Return: 'static,
186    {
187        let mut store = store.as_context_mut();
188        assert!(
189            store.0.async_support(),
190            "cannot use `call_async` when async support is not enabled on the config"
191        );
192        #[cfg(feature = "component-model-async")]
193        {
194            use crate::component::concurrent::TaskId;
195            use crate::runtime::vm::SendSyncPtr;
196            use core::ptr::NonNull;
197
198            let ptr = SendSyncPtr::from(NonNull::from(&params).cast::<u8>());
199            let prepared =
200                self.prepare_call(store.as_context_mut(), false, false, move |cx, ty, dst| {
201                    // SAFETY: The goal here is to get `Params`, a non-`'static`
202                    // value, to live long enough to the lowering of the
203                    // parameters. We're guaranteed that `Params` lives in the
204                    // future of the outer function (we're in an `async fn`) so it'll
205                    // stay alive as long as the future itself. That is distinct,
206                    // for example, from the signature of `call_concurrent` below.
207                    //
208                    // Here a pointer to `Params` is smuggled to this location
209                    // through a `SendSyncPtr<u8>` to thwart the `'static` check
210                    // of rustc and the signature of `prepare_call`.
211                    //
212                    // Note the use of `RemoveOnDrop` in the code that follows
213                    // this closure, which ensures that the task will be removed
214                    // from the concurrent state to which it belongs when the
215                    // containing `Future` is dropped, thereby ensuring that
216                    // this closure will never be called if it hasn't already,
217                    // meaning it will never see a dangling pointer.
218                    let params = unsafe { ptr.cast::<Params>().as_ref() };
219                    Self::lower_args(cx, ty, dst, params)
220                })?;
221
222            struct RemoveOnDrop<'a, T: 'static> {
223                store: StoreContextMut<'a, T>,
224                task: TaskId,
225            }
226
227            impl<'a, T> Drop for RemoveOnDrop<'a, T> {
228                fn drop(&mut self) {
229                    self.task.remove(self.store.as_context_mut()).unwrap();
230                }
231            }
232
233            let mut wrapper = RemoveOnDrop {
234                store,
235                task: prepared.task_id(),
236            };
237
238            let result = concurrent::queue_call(wrapper.store.as_context_mut(), prepared)?;
239            self.func
240                .instance
241                .run(wrapper.store.as_context_mut(), result)
242                .await?
243        }
244        #[cfg(not(feature = "component-model-async"))]
245        {
246            store
247                .on_fiber(|store| self.call_impl(store, params))
248                .await?
249        }
250    }
251
252    /// Start a concurrent call to this function.
253    ///
254    /// Unlike [`Self::call`] and [`Self::call_async`] (both of which require
255    /// exclusive access to the store until the completion of the call), calls
256    /// made using this method may run concurrently with other calls to the same
257    /// instance.  In addition, the runtime will call the `post-return` function
258    /// (if any) automatically when the guest task completes -- no need to
259    /// explicitly call `Func::post_return` afterward.
260    ///
261    /// Note that the `Future` returned by this method will panic if polled or
262    /// `.await`ed outside of the event loop of the component instance this
263    /// function belongs to; use `Instance::run`, `Instance::run_with`, or
264    /// `Instance::spawn` to poll it from within the event loop.  See
265    /// [`Instance::run`] for examples.
266    //
267    // FIXME: this function should return `impl Future` but that forces
268    // capturing all type parameters in scope at this time. The future
269    // intentionally does not close over `store` but returning `impl Future`
270    // implicitly does so. In a future version of Rust maybe this limitation
271    // will be lifted? Maybe rust-lang/rust#130043. Unsure.
272    #[cfg(feature = "component-model-async")]
273    pub fn call_concurrent(
274        self,
275        mut store: impl AsContextMut<Data: Send>,
276        params: Params,
277    ) -> Pin<Box<dyn Future<Output = Result<Return>> + Send>>
278    where
279        Params: 'static,
280        Return: 'static,
281    {
282        let mut store = store.as_context_mut();
283        assert!(
284            store.0.async_support(),
285            "cannot use `call_concurrent` when async support is not enabled on the config"
286        );
287
288        let result = (|| {
289            let prepared =
290                self.prepare_call(store.as_context_mut(), true, true, move |cx, ty, dst| {
291                    Self::lower_args(cx, ty, dst, &params)
292                })?;
293            concurrent::queue_call(store, prepared)
294        })();
295
296        Box::pin(async move { result?.await })
297    }
298
299    fn lower_args<T>(
300        cx: &mut LowerContext<T>,
301        ty: InterfaceType,
302        dst: &mut [MaybeUninit<ValRaw>],
303        params: &Params,
304    ) -> Result<()> {
305        use crate::component::storage::slice_to_storage_mut;
306
307        if Params::flatten_count() <= MAX_FLAT_PARAMS {
308            // SAFETY: the safety of `slice_to_storage_mut` relies on
309            // `Params::Lower` being represented by a sequence of
310            // `ValRaw`, and that's a guarantee upheld by the `Lower`
311            // trait itself.
312            let dst: &mut MaybeUninit<Params::Lower> = unsafe { slice_to_storage_mut(dst) };
313            Self::lower_stack_args(cx, &params, ty, dst)
314        } else {
315            Self::lower_heap_args(cx, &params, ty, &mut dst[0])
316        }
317    }
318
319    /// Calls `concurrent::prepare_call` with monomorphized functions for
320    /// lowering the parameters and lifting the result according to the number
321    /// of core Wasm parameters and results in the signature of the function to
322    /// be called.
323    #[cfg(feature = "component-model-async")]
324    fn prepare_call<T>(
325        self,
326        store: StoreContextMut<'_, T>,
327        remove_task_automatically: bool,
328        call_post_return_automatically: bool,
329        lower: impl FnOnce(
330            &mut LowerContext<T>,
331            InterfaceType,
332            &mut [MaybeUninit<ValRaw>],
333        ) -> Result<()>
334        + Send
335        + Sync
336        + 'static,
337    ) -> Result<PreparedCall<Return>>
338    where
339        Return: 'static,
340    {
341        use crate::component::storage::slice_to_storage;
342
343        let param_count = if Params::flatten_count() <= MAX_FLAT_PARAMS {
344            Params::flatten_count()
345        } else {
346            1
347        };
348        let max_results = if self.func.abi_async(store.0) {
349            MAX_FLAT_PARAMS
350        } else {
351            MAX_FLAT_RESULTS
352        };
353        concurrent::prepare_call(
354            store,
355            self.func,
356            param_count,
357            remove_task_automatically,
358            call_post_return_automatically,
359            move |func, store, params_out| {
360                func.with_lower_context(store, call_post_return_automatically, |cx, ty| {
361                    lower(cx, ty, params_out)
362                })
363            },
364            move |func, store, results| {
365                let result = if Return::flatten_count() <= max_results {
366                    func.with_lift_context(store, |cx, ty| {
367                        // SAFETY: Per the safety requiments documented for the
368                        // `ComponentType` trait, `Return::Lower` must be
369                        // compatible at the binary level with a `[ValRaw; N]`,
370                        // where `N` is `mem::size_of::<Return::Lower>() /
371                        // mem::size_of::<ValRaw>()`.  And since this function
372                        // is only used when `Return::flatten_count() <=
373                        // MAX_FLAT_RESULTS` and `MAX_FLAT_RESULTS == 1`, `N`
374                        // can only either be 0 or 1.
375                        //
376                        // See `ComponentInstance::exit_call` for where we use
377                        // the result count passed from
378                        // `wasmtime_environ::fact::trampoline`-generated code
379                        // to ensure the slice has the correct length, and also
380                        // `concurrent::start_call` for where we conservatively
381                        // use a slice length of 1 unconditionally.  Also note
382                        // that, as of this writing `slice_to_storage`
383                        // double-checks the slice length is sufficient.
384                        let results: &Return::Lower = unsafe { slice_to_storage(results) };
385                        Self::lift_stack_result(cx, ty, results)
386                    })?
387                } else {
388                    func.with_lift_context(store, |cx, ty| {
389                        Self::lift_heap_result(cx, ty, &results[0])
390                    })?
391                };
392                Ok(Box::new(result))
393            },
394        )
395    }
396
397    fn call_impl(&self, mut store: impl AsContextMut, params: Params) -> Result<Return> {
398        let store = store.as_context_mut();
399
400        if self.func.abi_async(store.0) {
401            bail!("must enable the `component-model-async` feature to call async-lifted exports")
402        }
403
404        // Note that this is in theory simpler than it might read at this time.
405        // Here we're doing a runtime dispatch on the `flatten_count` for the
406        // params/results to see whether they're inbounds. This creates 4 cases
407        // to handle. In reality this is a highly optimizable branch where LLVM
408        // will easily figure out that only one branch here is taken.
409        //
410        // Otherwise this current construction is done to ensure that the stack
411        // space reserved for the params/results is always of the appropriate
412        // size (as the params/results needed differ depending on the "flatten"
413        // count)
414        //
415        // SAFETY: the safety of these invocations of `call_raw` depends on the
416        // correctness of the ascription of the `LowerParams` and `LowerReturn`
417        // types on the `call_raw` function. That's upheld here through the
418        // safety requirements of `Lift` and `Lower` on `Params` and `Return` in
419        // combination with checking the various possible branches here and
420        // dispatching to appropriately typed functions.
421        unsafe {
422            // This type is used as `LowerParams` for `call_raw` which is either
423            // `Params::Lower` or `ValRaw` representing it's either on the stack
424            // or it's on the heap. This allocates 1 extra `ValRaw` on the stack
425            // if `Params` is empty and `Return` is also empty, but that's a
426            // reasonable enough price to pay for now given the current code
427            // organization.
428            #[derive(Copy, Clone)]
429            union Union<T: Copy, U: Copy> {
430                _a: T,
431                _b: U,
432            }
433
434            if Return::flatten_count() <= MAX_FLAT_RESULTS {
435                self.func.call_raw(
436                    store,
437                    |cx, ty, dst: &mut MaybeUninit<Union<Params::Lower, ValRaw>>| {
438                        let dst = storage_as_slice_mut(dst);
439                        Self::lower_args(cx, ty, dst, &params)
440                    },
441                    Self::lift_stack_result,
442                )
443            } else {
444                self.func.call_raw(
445                    store,
446                    |cx, ty, dst: &mut MaybeUninit<Union<Params::Lower, ValRaw>>| {
447                        let dst = storage_as_slice_mut(dst);
448                        Self::lower_args(cx, ty, dst, &params)
449                    },
450                    Self::lift_heap_result,
451                )
452            }
453        }
454    }
455
456    /// Lower parameters directly onto the stack specified by the `dst`
457    /// location.
458    ///
459    /// This is only valid to call when the "flatten count" is small enough, or
460    /// when the canonical ABI says arguments go through the stack rather than
461    /// the heap.
462    fn lower_stack_args<T>(
463        cx: &mut LowerContext<'_, T>,
464        params: &Params,
465        ty: InterfaceType,
466        dst: &mut MaybeUninit<Params::Lower>,
467    ) -> Result<()> {
468        assert!(Params::flatten_count() <= MAX_FLAT_PARAMS);
469        params.linear_lower_to_flat(cx, ty, dst)?;
470        Ok(())
471    }
472
473    /// Lower parameters onto a heap-allocated location.
474    ///
475    /// This is used when the stack space to be used for the arguments is above
476    /// the `MAX_FLAT_PARAMS` threshold. Here the wasm's `realloc` function is
477    /// invoked to allocate space and then parameters are stored at that heap
478    /// pointer location.
479    fn lower_heap_args<T>(
480        cx: &mut LowerContext<'_, T>,
481        params: &Params,
482        ty: InterfaceType,
483        dst: &mut MaybeUninit<ValRaw>,
484    ) -> Result<()> {
485        // Memory must exist via validation if the arguments are stored on the
486        // heap, so we can create a `MemoryMut` at this point. Afterwards
487        // `realloc` is used to allocate space for all the arguments and then
488        // they're all stored in linear memory.
489        //
490        // Note that `realloc` will bake in a check that the returned pointer is
491        // in-bounds.
492        let ptr = cx.realloc(0, 0, Params::ALIGN32, Params::SIZE32)?;
493        params.linear_lower_to_memory(cx, ty, ptr)?;
494
495        // Note that the pointer here is stored as a 64-bit integer. This allows
496        // this to work with either 32 or 64-bit memories. For a 32-bit memory
497        // it'll just ignore the upper 32 zero bits, and for 64-bit memories
498        // this'll have the full 64-bits. Note that for 32-bit memories the call
499        // to `realloc` above guarantees that the `ptr` is in-bounds meaning
500        // that we will know that the zero-extended upper bits of `ptr` are
501        // guaranteed to be zero.
502        //
503        // This comment about 64-bit integers is also referred to below with
504        // "WRITEPTR64".
505        dst.write(ValRaw::i64(ptr as i64));
506
507        Ok(())
508    }
509
510    /// Lift the result of a function directly from the stack result.
511    ///
512    /// This is only used when the result fits in the maximum number of stack
513    /// slots.
514    fn lift_stack_result(
515        cx: &mut LiftContext<'_>,
516        ty: InterfaceType,
517        dst: &Return::Lower,
518    ) -> Result<Return> {
519        Return::linear_lift_from_flat(cx, ty, dst)
520    }
521
522    /// Lift the result of a function where the result is stored indirectly on
523    /// the heap.
524    fn lift_heap_result(
525        cx: &mut LiftContext<'_>,
526        ty: InterfaceType,
527        dst: &ValRaw,
528    ) -> Result<Return> {
529        assert!(Return::flatten_count() > MAX_FLAT_RESULTS);
530        // FIXME(#4311): needs to read an i64 for memory64
531        let ptr = usize::try_from(dst.get_u32())?;
532        if ptr % usize::try_from(Return::ALIGN32)? != 0 {
533            bail!("return pointer not aligned");
534        }
535
536        let bytes = cx
537            .memory()
538            .get(ptr..)
539            .and_then(|b| b.get(..Return::SIZE32))
540            .ok_or_else(|| anyhow::anyhow!("pointer out of bounds of memory"))?;
541        Return::linear_lift_from_memory(cx, ty, bytes)
542    }
543
544    /// See [`Func::post_return`]
545    pub fn post_return(&self, store: impl AsContextMut) -> Result<()> {
546        self.func.post_return(store)
547    }
548
549    /// See [`Func::post_return_async`]
550    #[cfg(feature = "async")]
551    pub async fn post_return_async<T: Send>(
552        &self,
553        store: impl AsContextMut<Data = T>,
554    ) -> Result<()> {
555        self.func.post_return_async(store).await
556    }
557}
558
559/// A trait representing a static list of named types that can be passed to or
560/// returned from a [`TypedFunc`].
561///
562/// This trait is implemented for a number of tuple types and is not expected
563/// to be implemented externally. The contents of this trait are hidden as it's
564/// intended to be an implementation detail of Wasmtime. The contents of this
565/// trait are not covered by Wasmtime's stability guarantees.
566///
567/// For more information about this trait see [`Func::typed`] and
568/// [`TypedFunc`].
569//
570// Note that this is an `unsafe` trait, and the unsafety means that
571// implementations of this trait must be correct or otherwise [`TypedFunc`]
572// would not be memory safe. The main reason this is `unsafe` is the
573// `typecheck` function which must operate correctly relative to the `AsTuple`
574// interpretation of the implementor.
575pub unsafe trait ComponentNamedList: ComponentType {}
576
577/// A trait representing types which can be passed to and read from components
578/// with the canonical ABI.
579///
580/// This trait is implemented for Rust types which can be communicated to
581/// components. The [`Func::typed`] and [`TypedFunc`] Rust items are the main
582/// consumers of this trait.
583///
584/// Supported Rust types include:
585///
586/// | Component Model Type              | Rust Type                            |
587/// |-----------------------------------|--------------------------------------|
588/// | `{s,u}{8,16,32,64}`               | `{i,u}{8,16,32,64}`                  |
589/// | `f{32,64}`                        | `f{32,64}`                           |
590/// | `bool`                            | `bool`                               |
591/// | `char`                            | `char`                               |
592/// | `tuple<A, B>`                     | `(A, B)`                             |
593/// | `option<T>`                       | `Option<T>`                          |
594/// | `result`                          | `Result<(), ()>`                     |
595/// | `result<T>`                       | `Result<T, ()>`                      |
596/// | `result<_, E>`                    | `Result<(), E>`                      |
597/// | `result<T, E>`                    | `Result<T, E>`                       |
598/// | `string`                          | `String`, `&str`, or [`WasmStr`]     |
599/// | `list<T>`                         | `Vec<T>`, `&[T]`, or [`WasmList`]    |
600/// | `own<T>`, `borrow<T>`             | [`Resource<T>`] or [`ResourceAny`]   |
601/// | `record`                          | [`#[derive(ComponentType)]`][d-cm]   |
602/// | `variant`                         | [`#[derive(ComponentType)]`][d-cm]   |
603/// | `enum`                            | [`#[derive(ComponentType)]`][d-cm]   |
604/// | `flags`                           | [`flags!`][f-m]                      |
605///
606/// [`Resource<T>`]: crate::component::Resource
607/// [`ResourceAny`]: crate::component::ResourceAny
608/// [d-cm]: macro@crate::component::ComponentType
609/// [f-m]: crate::component::flags
610///
611/// Rust standard library pointers such as `&T`, `Box<T>`, and `Arc<T>`
612/// additionally represent whatever type `T` represents in the component model.
613/// Note that types such as `record`, `variant`, `enum`, and `flags` are
614/// generated by the embedder at compile time. These macros derive
615/// implementation of this trait for custom types to map to custom types in the
616/// component model. Note that for `record`, `variant`, `enum`, and `flags`
617/// those types are often generated by the
618/// [`bindgen!`](crate::component::bindgen) macro from WIT definitions.
619///
620/// Types that implement [`ComponentType`] are used for `Params` and `Return`
621/// in [`TypedFunc`] and [`Func::typed`].
622///
623/// The contents of this trait are hidden as it's intended to be an
624/// implementation detail of Wasmtime. The contents of this trait are not
625/// covered by Wasmtime's stability guarantees.
626///
627/// # Safety
628///
629/// Note that this is an `unsafe` trait as `TypedFunc`'s safety heavily relies on
630/// the correctness of the implementations of this trait. Some ways in which this
631/// trait must be correct to be safe are:
632///
633/// * The `Lower` associated type must be a `ValRaw` sequence. It doesn't have to
634///   literally be `[ValRaw; N]` but when laid out in memory it must be adjacent
635///   `ValRaw` values and have a multiple of the size of `ValRaw` and the same
636///   alignment.
637///
638/// * The `lower` function must initialize the bits within `Lower` that are going
639///   to be read by the trampoline that's used to enter core wasm. A trampoline
640///   is passed `*mut Lower` and will read the canonical abi arguments in
641///   sequence, so all of the bits must be correctly initialized.
642///
643/// * The `size` and `align` functions must be correct for this value stored in
644///   the canonical ABI. The `Cursor<T>` iteration of these bytes rely on this
645///   for correctness as they otherwise eschew bounds-checking.
646///
647/// There are likely some other correctness issues which aren't documented as
648/// well, this isn't currently an exhaustive list. It suffices to say, though,
649/// that correctness bugs in this trait implementation are highly likely to
650/// lead to security bugs, which again leads to the `unsafe` in the trait.
651///
652/// Note that this trait specifically is not sealed because `bindgen!`-generated
653/// types must be able to implement this trait using a `#[derive]` macro. For
654/// users it's recommended to not implement this trait manually given the
655/// non-exhaustive list of safety requirements that must be upheld. This trait
656/// is implemented at your own risk if you do so.
657///
658/// # Send and Sync
659///
660/// While on the topic of safety it's worth discussing the `Send` and `Sync`
661/// bounds here as well. These bounds might naively seem like they shouldn't be
662/// required for all component types as they're host-level types not guest-level
663/// types persisted anywhere. Various subtleties lead to these bounds, however:
664///
665/// * Fibers require that all stack-local variables are `Send` and `Sync` for
666///   fibers themselves to be send/sync. Unfortunately we have no help from the
667///   compiler on this one so it's up to Wasmtime's discipline to maintain this.
668///   One instance of this is that return values are placed on the stack as
669///   they're lowered into guest memory. This lowering operation can involve
670///   malloc and context switches, so return values must be Send/Sync.
671///
672/// * In the implementation of component model async it's not uncommon for types
673///   to be "buffered" in the store temporarily. For example parameters might
674///   reside in a store temporarily while wasm has backpressure turned on.
675///
676/// Overall it's generally easiest to require `Send` and `Sync` for all
677/// component types. There additionally aren't known use case for non-`Send` or
678/// non-`Sync` types at this time.
679pub unsafe trait ComponentType: Send + Sync {
680    /// Representation of the "lowered" form of this component value.
681    ///
682    /// Lowerings lower into core wasm values which are represented by `ValRaw`.
683    /// This `Lower` type must be a list of `ValRaw` as either a literal array
684    /// or a struct where every field is a `ValRaw`. This must be `Copy` (as
685    /// `ValRaw` is `Copy`) and support all byte patterns. This being correct is
686    /// one reason why the trait is unsafe.
687    #[doc(hidden)]
688    type Lower: Copy;
689
690    /// The information about this type's canonical ABI (size/align/etc).
691    #[doc(hidden)]
692    const ABI: CanonicalAbiInfo;
693
694    #[doc(hidden)]
695    const SIZE32: usize = Self::ABI.size32 as usize;
696    #[doc(hidden)]
697    const ALIGN32: u32 = Self::ABI.align32;
698
699    #[doc(hidden)]
700    const IS_RUST_UNIT_TYPE: bool = false;
701
702    /// Returns the number of core wasm abi values will be used to represent
703    /// this type in its lowered form.
704    ///
705    /// This divides the size of `Self::Lower` by the size of `ValRaw`.
706    #[doc(hidden)]
707    fn flatten_count() -> usize {
708        assert!(mem::size_of::<Self::Lower>() % mem::size_of::<ValRaw>() == 0);
709        assert!(mem::align_of::<Self::Lower>() == mem::align_of::<ValRaw>());
710        mem::size_of::<Self::Lower>() / mem::size_of::<ValRaw>()
711    }
712
713    /// Performs a type-check to see whether this component value type matches
714    /// the interface type `ty` provided.
715    #[doc(hidden)]
716    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()>;
717}
718
719#[doc(hidden)]
720pub unsafe trait ComponentVariant: ComponentType {
721    const CASES: &'static [Option<CanonicalAbiInfo>];
722    const INFO: VariantInfo = VariantInfo::new_static(Self::CASES);
723    const PAYLOAD_OFFSET32: usize = Self::INFO.payload_offset32 as usize;
724}
725
726/// Host types which can be passed to WebAssembly components.
727///
728/// This trait is implemented for all types that can be passed to components
729/// either as parameters of component exports or returns of component imports.
730/// This trait represents the ability to convert from the native host
731/// representation to the canonical ABI.
732///
733/// Built-in types to Rust such as `Option<T>` implement this trait as
734/// appropriate. For a mapping of component model to Rust types see
735/// [`ComponentType`].
736///
737/// For user-defined types, for example `record` types mapped to Rust `struct`s,
738/// this crate additionally has
739/// [`#[derive(Lower)]`](macro@crate::component::Lower).
740///
741/// Note that like [`ComponentType`] the definition of this trait is intended to
742/// be an internal implementation detail of Wasmtime at this time. It's
743/// recommended to use the `#[derive(Lower)]` implementation instead.
744pub unsafe trait Lower: ComponentType {
745    /// Performs the "lower" function in the linear memory version of the
746    /// canonical ABI.
747    ///
748    /// This method will lower the current value into a component. The `lower`
749    /// function performs a "flat" lowering into the `dst` specified which is
750    /// allowed to be uninitialized entering this method but is guaranteed to be
751    /// fully initialized if the method returns `Ok(())`.
752    ///
753    /// The `cx` context provided is the context within which this lowering is
754    /// happening. This contains information such as canonical options specified
755    /// (e.g. string encodings, memories, etc), the store itself, along with
756    /// type information.
757    ///
758    /// The `ty` parameter is the destination type that is being lowered into.
759    /// For example this is the component's "view" of the type that is being
760    /// lowered. This is guaranteed to have passed a `typecheck` earlier.
761    ///
762    /// This will only be called if `typecheck` passes for `Op::Lower`.
763    #[doc(hidden)]
764    fn linear_lower_to_flat<T>(
765        &self,
766        cx: &mut LowerContext<'_, T>,
767        ty: InterfaceType,
768        dst: &mut MaybeUninit<Self::Lower>,
769    ) -> Result<()>;
770
771    /// Performs the "store" operation in the linear memory version of the
772    /// canonical ABI.
773    ///
774    /// This function will store `self` into the linear memory described by
775    /// `cx` at the `offset` provided.
776    ///
777    /// It is expected that `offset` is a valid offset in memory for
778    /// `Self::SIZE32` bytes. At this time that's not an unsafe contract as it's
779    /// always re-checked on all stores, but this is something that will need to
780    /// be improved in the future to remove extra bounds checks. For now this
781    /// function will panic if there's a bug and `offset` isn't valid within
782    /// memory.
783    ///
784    /// The `ty` type information passed here is the same as the type
785    /// information passed to `lower` above, and is the component's own view of
786    /// what the resulting type should be.
787    ///
788    /// This will only be called if `typecheck` passes for `Op::Lower`.
789    #[doc(hidden)]
790    fn linear_lower_to_memory<T>(
791        &self,
792        cx: &mut LowerContext<'_, T>,
793        ty: InterfaceType,
794        offset: usize,
795    ) -> Result<()>;
796
797    /// Provided method to lower a list of `Self` into memory.
798    ///
799    /// Requires that `offset` has already been checked for alignment and
800    /// validity in terms of being in-bounds, otherwise this may panic.
801    ///
802    /// This is primarily here to get overridden for implementations of integers
803    /// which can avoid some extra fluff and use a pattern that's more easily
804    /// optimizable by LLVM.
805    #[doc(hidden)]
806    fn linear_store_list_to_memory<T>(
807        cx: &mut LowerContext<'_, T>,
808        ty: InterfaceType,
809        mut offset: usize,
810        items: &[Self],
811    ) -> Result<()>
812    where
813        Self: Sized,
814    {
815        for item in items {
816            item.linear_lower_to_memory(cx, ty, offset)?;
817            offset += Self::SIZE32;
818        }
819        Ok(())
820    }
821}
822
823/// Host types which can be created from the canonical ABI.
824///
825/// This is the mirror of the [`Lower`] trait where it represents the capability
826/// of acquiring items from WebAssembly and passing them to the host.
827///
828/// Built-in types to Rust such as `Option<T>` implement this trait as
829/// appropriate. For a mapping of component model to Rust types see
830/// [`ComponentType`].
831///
832/// For user-defined types, for example `record` types mapped to Rust `struct`s,
833/// this crate additionally has
834/// [`#[derive(Lift)]`](macro@crate::component::Lift).
835///
836/// Note that like [`ComponentType`] the definition of this trait is intended to
837/// be an internal implementation detail of Wasmtime at this time. It's
838/// recommended to use the `#[derive(Lift)]` implementation instead.
839pub unsafe trait Lift: Sized + ComponentType {
840    /// Performs the "lift" operation in the linear memory version of the
841    /// canonical ABI.
842    ///
843    /// This function performs a "flat" lift operation from the `src` specified
844    /// which is a sequence of core wasm values. The lifting operation will
845    /// validate core wasm values and produce a `Self` on success.
846    ///
847    /// The `cx` provided contains contextual information such as the store
848    /// that's being loaded from, canonical options, and type information.
849    ///
850    /// The `ty` parameter is the origin component's specification for what the
851    /// type that is being lifted is. For example this is the record type or the
852    /// resource type that is being lifted.
853    ///
854    /// Note that this has a default implementation but if `typecheck` passes
855    /// for `Op::Lift` this needs to be overridden.
856    #[doc(hidden)]
857    fn linear_lift_from_flat(
858        cx: &mut LiftContext<'_>,
859        ty: InterfaceType,
860        src: &Self::Lower,
861    ) -> Result<Self>;
862
863    /// Performs the "load" operation in the linear memory version of the
864    /// canonical ABI.
865    ///
866    /// This will read the `bytes` provided, which are a sub-slice into the
867    /// linear memory described by `cx`. The `bytes` array provided is
868    /// guaranteed to be `Self::SIZE32` bytes large. All of memory is then also
869    /// available through `cx` for bounds-checks and such as necessary for
870    /// strings/lists.
871    ///
872    /// The `ty` argument is the type that's being loaded, as described by the
873    /// original component.
874    ///
875    /// Note that this has a default implementation but if `typecheck` passes
876    /// for `Op::Lift` this needs to be overridden.
877    #[doc(hidden)]
878    fn linear_lift_from_memory(
879        cx: &mut LiftContext<'_>,
880        ty: InterfaceType,
881        bytes: &[u8],
882    ) -> Result<Self>;
883
884    /// Converts `list` into a `Vec<T>`, used in `Lift for Vec<T>`.
885    #[doc(hidden)]
886    fn linear_lift_list_from_memory(
887        cx: &mut LiftContext<'_>,
888        list: &WasmList<Self>,
889    ) -> Result<Vec<Self>>
890    where
891        Self: Sized,
892    {
893        let mut dst = Vec::with_capacity(list.len);
894        Self::linear_lift_into_from_memory(cx, list, &mut dst)?;
895        Ok(dst)
896    }
897
898    /// Load no more than `max_count` items from `list` into `dst`.
899    ///
900    /// This is primarily here to get overridden for implementations of integers
901    /// which can avoid some extra fluff and use a pattern that's more easily
902    /// optimizable by LLVM.
903    #[doc(hidden)]
904    fn linear_lift_into_from_memory(
905        cx: &mut LiftContext<'_>,
906        list: &WasmList<Self>,
907        dst: &mut impl Extend<Self>,
908    ) -> Result<()>
909    where
910        Self: Sized,
911    {
912        for i in 0..list.len {
913            dst.extend(Some(list.get_from_store(cx, i).unwrap()?));
914        }
915        Ok(())
916    }
917}
918
919// Macro to help generate "forwarding implementations" of `ComponentType` to
920// another type, used for wrappers in Rust like `&T`, `Box<T>`, etc. Note that
921// these wrappers only implement lowering because lifting native Rust types
922// cannot be done.
923macro_rules! forward_type_impls {
924    ($(($($generics:tt)*) $a:ty => $b:ty,)*) => ($(
925        unsafe impl <$($generics)*> ComponentType for $a {
926            type Lower = <$b as ComponentType>::Lower;
927
928            const ABI: CanonicalAbiInfo = <$b as ComponentType>::ABI;
929
930            #[inline]
931            fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
932                <$b as ComponentType>::typecheck(ty, types)
933            }
934        }
935    )*)
936}
937
938forward_type_impls! {
939    (T: ComponentType + ?Sized) &'_ T => T,
940    (T: ComponentType + ?Sized) Box<T> => T,
941    (T: ComponentType + ?Sized) alloc::sync::Arc<T> => T,
942    () String => str,
943    (T: ComponentType) Vec<T> => [T],
944}
945
946macro_rules! forward_lowers {
947    ($(($($generics:tt)*) $a:ty => $b:ty,)*) => ($(
948        unsafe impl <$($generics)*> Lower for $a {
949            fn linear_lower_to_flat<U>(
950                &self,
951                cx: &mut LowerContext<'_, U>,
952                ty: InterfaceType,
953                dst: &mut MaybeUninit<Self::Lower>,
954            ) -> Result<()> {
955                <$b as Lower>::linear_lower_to_flat(self, cx, ty, dst)
956            }
957
958            fn linear_lower_to_memory<U>(
959                &self,
960                cx: &mut LowerContext<'_, U>,
961                ty: InterfaceType,
962                offset: usize,
963            ) -> Result<()> {
964                <$b as Lower>::linear_lower_to_memory(self, cx, ty, offset)
965            }
966        }
967    )*)
968}
969
970forward_lowers! {
971    (T: Lower + ?Sized) &'_ T => T,
972    (T: Lower + ?Sized) Box<T> => T,
973    (T: Lower + ?Sized) alloc::sync::Arc<T> => T,
974    () String => str,
975    (T: Lower) Vec<T> => [T],
976}
977
978macro_rules! forward_string_lifts {
979    ($($a:ty,)*) => ($(
980        unsafe impl Lift for $a {
981            #[inline]
982            fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
983                Ok(<WasmStr as Lift>::linear_lift_from_flat(cx, ty, src)?.to_str_from_memory(cx.memory())?.into())
984            }
985
986            #[inline]
987            fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
988                Ok(<WasmStr as Lift>::linear_lift_from_memory(cx, ty, bytes)?.to_str_from_memory(cx.memory())?.into())
989            }
990        }
991    )*)
992}
993
994forward_string_lifts! {
995    Box<str>,
996    alloc::sync::Arc<str>,
997    String,
998}
999
1000macro_rules! forward_list_lifts {
1001    ($($a:ty,)*) => ($(
1002        unsafe impl <T: Lift> Lift for $a {
1003            fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
1004                let list = <WasmList::<T> as Lift>::linear_lift_from_flat(cx, ty, src)?;
1005                Ok(T::linear_lift_list_from_memory(cx, &list)?.into())
1006            }
1007
1008            fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
1009                let list = <WasmList::<T> as Lift>::linear_lift_from_memory(cx, ty, bytes)?;
1010                Ok(T::linear_lift_list_from_memory(cx, &list)?.into())
1011            }
1012        }
1013    )*)
1014}
1015
1016forward_list_lifts! {
1017    Box<[T]>,
1018    alloc::sync::Arc<[T]>,
1019    Vec<T>,
1020}
1021
1022// Macro to help generate `ComponentType` implementations for primitive types
1023// such as integers, char, bool, etc.
1024macro_rules! integers {
1025    ($($primitive:ident = $ty:ident in $field:ident/$get:ident with abi:$abi:ident,)*) => ($(
1026        unsafe impl ComponentType for $primitive {
1027            type Lower = ValRaw;
1028
1029            const ABI: CanonicalAbiInfo = CanonicalAbiInfo::$abi;
1030
1031            fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1032                match ty {
1033                    InterfaceType::$ty => Ok(()),
1034                    other => bail!("expected `{}` found `{}`", desc(&InterfaceType::$ty), desc(other))
1035                }
1036            }
1037        }
1038
1039        unsafe impl Lower for $primitive {
1040            #[inline]
1041            #[allow(trivial_numeric_casts, reason = "macro-generated code")]
1042            fn linear_lower_to_flat<T>(
1043                &self,
1044                _cx: &mut LowerContext<'_, T>,
1045                ty: InterfaceType,
1046                dst: &mut MaybeUninit<Self::Lower>,
1047            ) -> Result<()> {
1048                debug_assert!(matches!(ty, InterfaceType::$ty));
1049                dst.write(ValRaw::$field(*self as $field));
1050                Ok(())
1051            }
1052
1053            #[inline]
1054            fn linear_lower_to_memory<T>(
1055                &self,
1056                cx: &mut LowerContext<'_, T>,
1057                ty: InterfaceType,
1058                offset: usize,
1059            ) -> Result<()> {
1060                debug_assert!(matches!(ty, InterfaceType::$ty));
1061                debug_assert!(offset % Self::SIZE32 == 0);
1062                *cx.get(offset) = self.to_le_bytes();
1063                Ok(())
1064            }
1065
1066            fn linear_store_list_to_memory<T>(
1067                cx: &mut LowerContext<'_, T>,
1068                ty: InterfaceType,
1069                offset: usize,
1070                items: &[Self],
1071            ) -> Result<()> {
1072                debug_assert!(matches!(ty, InterfaceType::$ty));
1073
1074                // Double-check that the CM alignment is at least the host's
1075                // alignment for this type which should be true for all
1076                // platforms.
1077                assert!((Self::ALIGN32 as usize) >= mem::align_of::<Self>());
1078
1079                // Slice `cx`'s memory to the window that we'll be modifying.
1080                // This should all have already been verified in terms of
1081                // alignment and sizing meaning that these assertions here are
1082                // not truly necessary but are instead double-checks.
1083                //
1084                // Note that we're casting a `[u8]` slice to `[Self]` with
1085                // `align_to_mut` which is not safe in general but is safe in
1086                // our specific case as all `u8` patterns are valid `Self`
1087                // patterns since `Self` is an integral type.
1088                let dst = &mut cx.as_slice_mut()[offset..][..items.len() * Self::SIZE32];
1089                let (before, middle, end) = unsafe { dst.align_to_mut::<Self>() };
1090                assert!(before.is_empty() && end.is_empty());
1091                assert_eq!(middle.len(), items.len());
1092
1093                // And with all that out of the way perform the copying loop.
1094                // This is not a `copy_from_slice` because endianness needs to
1095                // be handled here, but LLVM should pretty easily transform this
1096                // into a memcpy on little-endian platforms.
1097                for (dst, src) in middle.iter_mut().zip(items) {
1098                    *dst = src.to_le();
1099                }
1100                Ok(())
1101            }
1102        }
1103
1104        unsafe impl Lift for $primitive {
1105            #[inline]
1106            #[allow(
1107                trivial_numeric_casts,
1108                clippy::cast_possible_truncation,
1109                reason = "macro-generated code"
1110            )]
1111            fn linear_lift_from_flat(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
1112                debug_assert!(matches!(ty, InterfaceType::$ty));
1113                Ok(src.$get() as $primitive)
1114            }
1115
1116            #[inline]
1117            fn linear_lift_from_memory(_cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
1118                debug_assert!(matches!(ty, InterfaceType::$ty));
1119                debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1120                Ok($primitive::from_le_bytes(bytes.try_into().unwrap()))
1121            }
1122
1123            fn linear_lift_into_from_memory(
1124                cx: &mut LiftContext<'_>,
1125                list: &WasmList<Self>,
1126                dst: &mut impl Extend<Self>,
1127            ) -> Result<()>
1128            where
1129                Self: Sized,
1130            {
1131                dst.extend(list._as_le_slice(cx.memory())
1132                           .iter()
1133                           .map(|i| Self::from_le(*i)));
1134                Ok(())
1135            }
1136        }
1137    )*)
1138}
1139
1140integers! {
1141    i8 = S8 in i32/get_i32 with abi:SCALAR1,
1142    u8 = U8 in u32/get_u32 with abi:SCALAR1,
1143    i16 = S16 in i32/get_i32 with abi:SCALAR2,
1144    u16 = U16 in u32/get_u32 with abi:SCALAR2,
1145    i32 = S32 in i32/get_i32 with abi:SCALAR4,
1146    u32 = U32 in u32/get_u32 with abi:SCALAR4,
1147    i64 = S64 in i64/get_i64 with abi:SCALAR8,
1148    u64 = U64 in u64/get_u64 with abi:SCALAR8,
1149}
1150
1151macro_rules! floats {
1152    ($($float:ident/$get_float:ident = $ty:ident with abi:$abi:ident)*) => ($(const _: () = {
1153        unsafe impl ComponentType for $float {
1154            type Lower = ValRaw;
1155
1156            const ABI: CanonicalAbiInfo = CanonicalAbiInfo::$abi;
1157
1158            fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1159                match ty {
1160                    InterfaceType::$ty => Ok(()),
1161                    other => bail!("expected `{}` found `{}`", desc(&InterfaceType::$ty), desc(other))
1162                }
1163            }
1164        }
1165
1166        unsafe impl Lower for $float {
1167            #[inline]
1168            fn linear_lower_to_flat<T>(
1169                &self,
1170                _cx: &mut LowerContext<'_, T>,
1171                ty: InterfaceType,
1172                dst: &mut MaybeUninit<Self::Lower>,
1173            ) -> Result<()> {
1174                debug_assert!(matches!(ty, InterfaceType::$ty));
1175                dst.write(ValRaw::$float(self.to_bits()));
1176                Ok(())
1177            }
1178
1179            #[inline]
1180            fn linear_lower_to_memory<T>(
1181                &self,
1182                cx: &mut LowerContext<'_, T>,
1183                ty: InterfaceType,
1184                offset: usize,
1185            ) -> Result<()> {
1186                debug_assert!(matches!(ty, InterfaceType::$ty));
1187                debug_assert!(offset % Self::SIZE32 == 0);
1188                let ptr = cx.get(offset);
1189                *ptr = self.to_bits().to_le_bytes();
1190                Ok(())
1191            }
1192
1193            fn linear_store_list_to_memory<T>(
1194                cx: &mut LowerContext<'_, T>,
1195                ty: InterfaceType,
1196                offset: usize,
1197                items: &[Self],
1198            ) -> Result<()> {
1199                debug_assert!(matches!(ty, InterfaceType::$ty));
1200
1201                // Double-check that the CM alignment is at least the host's
1202                // alignment for this type which should be true for all
1203                // platforms.
1204                assert!((Self::ALIGN32 as usize) >= mem::align_of::<Self>());
1205
1206                // Slice `cx`'s memory to the window that we'll be modifying.
1207                // This should all have already been verified in terms of
1208                // alignment and sizing meaning that these assertions here are
1209                // not truly necessary but are instead double-checks.
1210                let dst = &mut cx.as_slice_mut()[offset..][..items.len() * Self::SIZE32];
1211                assert!(dst.as_ptr().cast::<Self>().is_aligned());
1212
1213                // And with all that out of the way perform the copying loop.
1214                // This is not a `copy_from_slice` because endianness needs to
1215                // be handled here, but LLVM should pretty easily transform this
1216                // into a memcpy on little-endian platforms.
1217                // TODO use `as_chunks` when https://github.com/rust-lang/rust/issues/74985
1218                // is stabilized
1219                for (dst, src) in iter::zip(dst.chunks_exact_mut(Self::SIZE32), items) {
1220                    let dst: &mut [u8; Self::SIZE32] = dst.try_into().unwrap();
1221                    *dst = src.to_le_bytes();
1222                }
1223                Ok(())
1224            }
1225        }
1226
1227        unsafe impl Lift for $float {
1228            #[inline]
1229            fn linear_lift_from_flat(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
1230                debug_assert!(matches!(ty, InterfaceType::$ty));
1231                Ok($float::from_bits(src.$get_float()))
1232            }
1233
1234            #[inline]
1235            fn linear_lift_from_memory(_cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
1236                debug_assert!(matches!(ty, InterfaceType::$ty));
1237                debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1238                Ok($float::from_le_bytes(bytes.try_into().unwrap()))
1239            }
1240
1241            fn linear_lift_list_from_memory(cx: &mut LiftContext<'_>, list: &WasmList<Self>) -> Result<Vec<Self>> where Self: Sized {
1242                // See comments in `WasmList::get` for the panicking indexing
1243                let byte_size = list.len * mem::size_of::<Self>();
1244                let bytes = &cx.memory()[list.ptr..][..byte_size];
1245
1246                // The canonical ABI requires that everything is aligned to its
1247                // own size, so this should be an aligned array.
1248                assert!(bytes.as_ptr().cast::<Self>().is_aligned());
1249
1250                // Copy the resulting slice to a new Vec, handling endianness
1251                // in the process
1252                // TODO use `as_chunks` when https://github.com/rust-lang/rust/issues/74985
1253                // is stabilized
1254                Ok(
1255                    bytes
1256                        .chunks_exact(Self::SIZE32)
1257                        .map(|i| $float::from_le_bytes(i.try_into().unwrap()))
1258                        .collect()
1259                )
1260            }
1261        }
1262    };)*)
1263}
1264
1265floats! {
1266    f32/get_f32 = Float32 with abi:SCALAR4
1267    f64/get_f64 = Float64 with abi:SCALAR8
1268}
1269
1270unsafe impl ComponentType for bool {
1271    type Lower = ValRaw;
1272
1273    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR1;
1274
1275    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1276        match ty {
1277            InterfaceType::Bool => Ok(()),
1278            other => bail!("expected `bool` found `{}`", desc(other)),
1279        }
1280    }
1281}
1282
1283unsafe impl Lower for bool {
1284    fn linear_lower_to_flat<T>(
1285        &self,
1286        _cx: &mut LowerContext<'_, T>,
1287        ty: InterfaceType,
1288        dst: &mut MaybeUninit<Self::Lower>,
1289    ) -> Result<()> {
1290        debug_assert!(matches!(ty, InterfaceType::Bool));
1291        dst.write(ValRaw::i32(*self as i32));
1292        Ok(())
1293    }
1294
1295    fn linear_lower_to_memory<T>(
1296        &self,
1297        cx: &mut LowerContext<'_, T>,
1298        ty: InterfaceType,
1299        offset: usize,
1300    ) -> Result<()> {
1301        debug_assert!(matches!(ty, InterfaceType::Bool));
1302        debug_assert!(offset % Self::SIZE32 == 0);
1303        cx.get::<1>(offset)[0] = *self as u8;
1304        Ok(())
1305    }
1306}
1307
1308unsafe impl Lift for bool {
1309    #[inline]
1310    fn linear_lift_from_flat(
1311        _cx: &mut LiftContext<'_>,
1312        ty: InterfaceType,
1313        src: &Self::Lower,
1314    ) -> Result<Self> {
1315        debug_assert!(matches!(ty, InterfaceType::Bool));
1316        match src.get_i32() {
1317            0 => Ok(false),
1318            _ => Ok(true),
1319        }
1320    }
1321
1322    #[inline]
1323    fn linear_lift_from_memory(
1324        _cx: &mut LiftContext<'_>,
1325        ty: InterfaceType,
1326        bytes: &[u8],
1327    ) -> Result<Self> {
1328        debug_assert!(matches!(ty, InterfaceType::Bool));
1329        match bytes[0] {
1330            0 => Ok(false),
1331            _ => Ok(true),
1332        }
1333    }
1334}
1335
1336unsafe impl ComponentType for char {
1337    type Lower = ValRaw;
1338
1339    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
1340
1341    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1342        match ty {
1343            InterfaceType::Char => Ok(()),
1344            other => bail!("expected `char` found `{}`", desc(other)),
1345        }
1346    }
1347}
1348
1349unsafe impl Lower for char {
1350    #[inline]
1351    fn linear_lower_to_flat<T>(
1352        &self,
1353        _cx: &mut LowerContext<'_, T>,
1354        ty: InterfaceType,
1355        dst: &mut MaybeUninit<Self::Lower>,
1356    ) -> Result<()> {
1357        debug_assert!(matches!(ty, InterfaceType::Char));
1358        dst.write(ValRaw::u32(u32::from(*self)));
1359        Ok(())
1360    }
1361
1362    #[inline]
1363    fn linear_lower_to_memory<T>(
1364        &self,
1365        cx: &mut LowerContext<'_, T>,
1366        ty: InterfaceType,
1367        offset: usize,
1368    ) -> Result<()> {
1369        debug_assert!(matches!(ty, InterfaceType::Char));
1370        debug_assert!(offset % Self::SIZE32 == 0);
1371        *cx.get::<4>(offset) = u32::from(*self).to_le_bytes();
1372        Ok(())
1373    }
1374}
1375
1376unsafe impl Lift for char {
1377    #[inline]
1378    fn linear_lift_from_flat(
1379        _cx: &mut LiftContext<'_>,
1380        ty: InterfaceType,
1381        src: &Self::Lower,
1382    ) -> Result<Self> {
1383        debug_assert!(matches!(ty, InterfaceType::Char));
1384        Ok(char::try_from(src.get_u32())?)
1385    }
1386
1387    #[inline]
1388    fn linear_lift_from_memory(
1389        _cx: &mut LiftContext<'_>,
1390        ty: InterfaceType,
1391        bytes: &[u8],
1392    ) -> Result<Self> {
1393        debug_assert!(matches!(ty, InterfaceType::Char));
1394        debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1395        let bits = u32::from_le_bytes(bytes.try_into().unwrap());
1396        Ok(char::try_from(bits)?)
1397    }
1398}
1399
1400// FIXME(#4311): these probably need different constants for memory64
1401const UTF16_TAG: usize = 1 << 31;
1402const MAX_STRING_BYTE_LENGTH: usize = (1 << 31) - 1;
1403
1404// Note that this is similar to `ComponentType for WasmStr` except it can only
1405// be used for lowering, not lifting.
1406unsafe impl ComponentType for str {
1407    type Lower = [ValRaw; 2];
1408
1409    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1410
1411    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1412        match ty {
1413            InterfaceType::String => Ok(()),
1414            other => bail!("expected `string` found `{}`", desc(other)),
1415        }
1416    }
1417}
1418
1419unsafe impl Lower for str {
1420    fn linear_lower_to_flat<T>(
1421        &self,
1422        cx: &mut LowerContext<'_, T>,
1423        ty: InterfaceType,
1424        dst: &mut MaybeUninit<[ValRaw; 2]>,
1425    ) -> Result<()> {
1426        debug_assert!(matches!(ty, InterfaceType::String));
1427        let (ptr, len) = lower_string(cx, self)?;
1428        // See "WRITEPTR64" above for why this is always storing a 64-bit
1429        // integer.
1430        map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64));
1431        map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64));
1432        Ok(())
1433    }
1434
1435    fn linear_lower_to_memory<T>(
1436        &self,
1437        cx: &mut LowerContext<'_, T>,
1438        ty: InterfaceType,
1439        offset: usize,
1440    ) -> Result<()> {
1441        debug_assert!(matches!(ty, InterfaceType::String));
1442        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1443        let (ptr, len) = lower_string(cx, self)?;
1444        // FIXME(#4311): needs memory64 handling
1445        *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
1446        *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
1447        Ok(())
1448    }
1449}
1450
1451fn lower_string<T>(cx: &mut LowerContext<'_, T>, string: &str) -> Result<(usize, usize)> {
1452    // Note that in general the wasm module can't assume anything about what the
1453    // host strings are encoded as. Additionally hosts are allowed to have
1454    // differently-encoded strings at runtime. Finally when copying a string
1455    // into wasm it's somewhat strict in the sense that the various patterns of
1456    // allocation and such are already dictated for us.
1457    //
1458    // In general what this means is that when copying a string from the host
1459    // into the destination we need to follow one of the cases of copying into
1460    // WebAssembly. It doesn't particularly matter which case as long as it ends
1461    // up in the right encoding. For example a destination encoding of
1462    // latin1+utf16 has a number of ways to get copied into and we do something
1463    // here that isn't the default "utf8 to latin1+utf16" since we have access
1464    // to simd-accelerated helpers in the `encoding_rs` crate. This is ok though
1465    // because we can fake that the host string was already stored in latin1
1466    // format and follow that copy pattern instead.
1467    match cx.options.string_encoding() {
1468        // This corresponds to `store_string_copy` in the canonical ABI where
1469        // the host's representation is utf-8 and the wasm module wants utf-8 so
1470        // a copy is all that's needed (and the `realloc` can be precise for the
1471        // initial memory allocation).
1472        StringEncoding::Utf8 => {
1473            if string.len() > MAX_STRING_BYTE_LENGTH {
1474                bail!(
1475                    "string length of {} too large to copy into wasm",
1476                    string.len()
1477                );
1478            }
1479            let ptr = cx.realloc(0, 0, 1, string.len())?;
1480            cx.as_slice_mut()[ptr..][..string.len()].copy_from_slice(string.as_bytes());
1481            Ok((ptr, string.len()))
1482        }
1483
1484        // This corresponds to `store_utf8_to_utf16` in the canonical ABI. Here
1485        // an over-large allocation is performed and then shrunk afterwards if
1486        // necessary.
1487        StringEncoding::Utf16 => {
1488            let size = string.len() * 2;
1489            if size > MAX_STRING_BYTE_LENGTH {
1490                bail!(
1491                    "string length of {} too large to copy into wasm",
1492                    string.len()
1493                );
1494            }
1495            let mut ptr = cx.realloc(0, 0, 2, size)?;
1496            let mut copied = 0;
1497            let bytes = &mut cx.as_slice_mut()[ptr..][..size];
1498            for (u, bytes) in string.encode_utf16().zip(bytes.chunks_mut(2)) {
1499                let u_bytes = u.to_le_bytes();
1500                bytes[0] = u_bytes[0];
1501                bytes[1] = u_bytes[1];
1502                copied += 1;
1503            }
1504            if (copied * 2) < size {
1505                ptr = cx.realloc(ptr, size, 2, copied * 2)?;
1506            }
1507            Ok((ptr, copied))
1508        }
1509
1510        StringEncoding::CompactUtf16 => {
1511            // This corresponds to `store_string_to_latin1_or_utf16`
1512            let bytes = string.as_bytes();
1513            let mut iter = string.char_indices();
1514            let mut ptr = cx.realloc(0, 0, 2, bytes.len())?;
1515            let mut dst = &mut cx.as_slice_mut()[ptr..][..bytes.len()];
1516            let mut result = 0;
1517            while let Some((i, ch)) = iter.next() {
1518                // Test if this `char` fits into the latin1 encoding.
1519                if let Ok(byte) = u8::try_from(u32::from(ch)) {
1520                    dst[result] = byte;
1521                    result += 1;
1522                    continue;
1523                }
1524
1525                // .. if utf16 is forced to be used then the allocation is
1526                // bumped up to the maximum size.
1527                let worst_case = bytes
1528                    .len()
1529                    .checked_mul(2)
1530                    .ok_or_else(|| anyhow!("byte length overflow"))?;
1531                if worst_case > MAX_STRING_BYTE_LENGTH {
1532                    bail!("byte length too large");
1533                }
1534                ptr = cx.realloc(ptr, bytes.len(), 2, worst_case)?;
1535                dst = &mut cx.as_slice_mut()[ptr..][..worst_case];
1536
1537                // Previously encoded latin1 bytes are inflated to their 16-bit
1538                // size for utf16
1539                for i in (0..result).rev() {
1540                    dst[2 * i] = dst[i];
1541                    dst[2 * i + 1] = 0;
1542                }
1543
1544                // and then the remainder of the string is encoded.
1545                for (u, bytes) in string[i..]
1546                    .encode_utf16()
1547                    .zip(dst[2 * result..].chunks_mut(2))
1548                {
1549                    let u_bytes = u.to_le_bytes();
1550                    bytes[0] = u_bytes[0];
1551                    bytes[1] = u_bytes[1];
1552                    result += 1;
1553                }
1554                if worst_case > 2 * result {
1555                    ptr = cx.realloc(ptr, worst_case, 2, 2 * result)?;
1556                }
1557                return Ok((ptr, result | UTF16_TAG));
1558            }
1559            if result < bytes.len() {
1560                ptr = cx.realloc(ptr, bytes.len(), 2, result)?;
1561            }
1562            Ok((ptr, result))
1563        }
1564    }
1565}
1566
1567/// Representation of a string located in linear memory in a WebAssembly
1568/// instance.
1569///
1570/// This type can be used in place of `String` and `str` for string-taking APIs
1571/// in some situations. The purpose of this type is to represent a range of
1572/// validated bytes within a component but does not actually copy the bytes. The
1573/// primary method, [`WasmStr::to_str`], attempts to return a reference to the
1574/// string directly located in the component's memory, avoiding a copy into the
1575/// host if possible.
1576///
1577/// The downside of this type, however, is that accessing a string requires a
1578/// [`Store`](crate::Store) pointer (via [`StoreContext`]). Bindings generated
1579/// by [`bindgen!`](crate::component::bindgen), for example, do not have access
1580/// to [`StoreContext`] and thus can't use this type.
1581///
1582/// This is intended for more advanced use cases such as defining functions
1583/// directly in a [`Linker`](crate::component::Linker). It's expected that in
1584/// the future [`bindgen!`](crate::component::bindgen) will also have a way to
1585/// use this type.
1586///
1587/// This type is used with [`TypedFunc`], for example, when WebAssembly returns
1588/// a string. This type cannot be used to give a string to WebAssembly, instead
1589/// `&str` should be used for that (since it's coming from the host).
1590///
1591/// Note that this type represents an in-bounds string in linear memory, but it
1592/// does not represent a valid string (e.g. valid utf-8). Validation happens
1593/// when [`WasmStr::to_str`] is called.
1594///
1595/// Also note that this type does not implement [`Lower`], it only implements
1596/// [`Lift`].
1597pub struct WasmStr {
1598    ptr: usize,
1599    len: usize,
1600    options: Options,
1601}
1602
1603impl WasmStr {
1604    pub(crate) fn new(ptr: usize, len: usize, cx: &mut LiftContext<'_>) -> Result<WasmStr> {
1605        let byte_len = match cx.options.string_encoding() {
1606            StringEncoding::Utf8 => Some(len),
1607            StringEncoding::Utf16 => len.checked_mul(2),
1608            StringEncoding::CompactUtf16 => {
1609                if len & UTF16_TAG == 0 {
1610                    Some(len)
1611                } else {
1612                    (len ^ UTF16_TAG).checked_mul(2)
1613                }
1614            }
1615        };
1616        match byte_len.and_then(|len| ptr.checked_add(len)) {
1617            Some(n) if n <= cx.memory().len() => {}
1618            _ => bail!("string pointer/length out of bounds of memory"),
1619        }
1620        Ok(WasmStr {
1621            ptr,
1622            len,
1623            options: *cx.options,
1624        })
1625    }
1626
1627    /// Returns the underlying string that this cursor points to.
1628    ///
1629    /// Note that this will internally decode the string from the wasm's
1630    /// encoding to utf-8 and additionally perform validation.
1631    ///
1632    /// The `store` provided must be the store where this string lives to
1633    /// access the correct memory.
1634    ///
1635    /// # Errors
1636    ///
1637    /// Returns an error if the string wasn't encoded correctly (e.g. invalid
1638    /// utf-8).
1639    ///
1640    /// # Panics
1641    ///
1642    /// Panics if this string is not owned by `store`.
1643    //
1644    // TODO: should add accessors for specifically utf-8 and utf-16 that perhaps
1645    // in an opt-in basis don't do validation. Additionally there should be some
1646    // method that returns `[u16]` after validating to avoid the utf16-to-utf8
1647    // transcode.
1648    pub fn to_str<'a, T: 'static>(
1649        &self,
1650        store: impl Into<StoreContext<'a, T>>,
1651    ) -> Result<Cow<'a, str>> {
1652        let store = store.into().0;
1653        let memory = self.options.memory(store);
1654        self.to_str_from_memory(memory)
1655    }
1656
1657    pub(crate) fn to_str_from_memory<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1658        match self.options.string_encoding() {
1659            StringEncoding::Utf8 => self.decode_utf8(memory),
1660            StringEncoding::Utf16 => self.decode_utf16(memory, self.len),
1661            StringEncoding::CompactUtf16 => {
1662                if self.len & UTF16_TAG == 0 {
1663                    self.decode_latin1(memory)
1664                } else {
1665                    self.decode_utf16(memory, self.len ^ UTF16_TAG)
1666                }
1667            }
1668        }
1669    }
1670
1671    fn decode_utf8<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1672        // Note that bounds-checking already happen in construction of `WasmStr`
1673        // so this is never expected to panic. This could theoretically be
1674        // unchecked indexing if we're feeling wild enough.
1675        Ok(str::from_utf8(&memory[self.ptr..][..self.len])?.into())
1676    }
1677
1678    fn decode_utf16<'a>(&self, memory: &'a [u8], len: usize) -> Result<Cow<'a, str>> {
1679        // See notes in `decode_utf8` for why this is panicking indexing.
1680        let memory = &memory[self.ptr..][..len * 2];
1681        Ok(core::char::decode_utf16(
1682            memory
1683                .chunks(2)
1684                .map(|chunk| u16::from_le_bytes(chunk.try_into().unwrap())),
1685        )
1686        .collect::<Result<String, _>>()?
1687        .into())
1688    }
1689
1690    fn decode_latin1<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1691        // See notes in `decode_utf8` for why this is panicking indexing.
1692        Ok(encoding_rs::mem::decode_latin1(
1693            &memory[self.ptr..][..self.len],
1694        ))
1695    }
1696}
1697
1698// Note that this is similar to `ComponentType for str` except it can only be
1699// used for lifting, not lowering.
1700unsafe impl ComponentType for WasmStr {
1701    type Lower = <str as ComponentType>::Lower;
1702
1703    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1704
1705    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1706        match ty {
1707            InterfaceType::String => Ok(()),
1708            other => bail!("expected `string` found `{}`", desc(other)),
1709        }
1710    }
1711}
1712
1713unsafe impl Lift for WasmStr {
1714    #[inline]
1715    fn linear_lift_from_flat(
1716        cx: &mut LiftContext<'_>,
1717        ty: InterfaceType,
1718        src: &Self::Lower,
1719    ) -> Result<Self> {
1720        debug_assert!(matches!(ty, InterfaceType::String));
1721        // FIXME(#4311): needs memory64 treatment
1722        let ptr = src[0].get_u32();
1723        let len = src[1].get_u32();
1724        let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?);
1725        WasmStr::new(ptr, len, cx)
1726    }
1727
1728    #[inline]
1729    fn linear_lift_from_memory(
1730        cx: &mut LiftContext<'_>,
1731        ty: InterfaceType,
1732        bytes: &[u8],
1733    ) -> Result<Self> {
1734        debug_assert!(matches!(ty, InterfaceType::String));
1735        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1736        // FIXME(#4311): needs memory64 treatment
1737        let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap());
1738        let len = u32::from_le_bytes(bytes[4..].try_into().unwrap());
1739        let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?);
1740        WasmStr::new(ptr, len, cx)
1741    }
1742}
1743
1744unsafe impl<T> ComponentType for [T]
1745where
1746    T: ComponentType,
1747{
1748    type Lower = [ValRaw; 2];
1749
1750    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1751
1752    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1753        match ty {
1754            InterfaceType::List(t) => T::typecheck(&types.types[*t].element, types),
1755            other => bail!("expected `list` found `{}`", desc(other)),
1756        }
1757    }
1758}
1759
1760unsafe impl<T> Lower for [T]
1761where
1762    T: Lower,
1763{
1764    fn linear_lower_to_flat<U>(
1765        &self,
1766        cx: &mut LowerContext<'_, U>,
1767        ty: InterfaceType,
1768        dst: &mut MaybeUninit<[ValRaw; 2]>,
1769    ) -> Result<()> {
1770        let elem = match ty {
1771            InterfaceType::List(i) => cx.types[i].element,
1772            _ => bad_type_info(),
1773        };
1774        let (ptr, len) = lower_list(cx, elem, self)?;
1775        // See "WRITEPTR64" above for why this is always storing a 64-bit
1776        // integer.
1777        map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64));
1778        map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64));
1779        Ok(())
1780    }
1781
1782    fn linear_lower_to_memory<U>(
1783        &self,
1784        cx: &mut LowerContext<'_, U>,
1785        ty: InterfaceType,
1786        offset: usize,
1787    ) -> Result<()> {
1788        let elem = match ty {
1789            InterfaceType::List(i) => cx.types[i].element,
1790            _ => bad_type_info(),
1791        };
1792        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1793        let (ptr, len) = lower_list(cx, elem, self)?;
1794        *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
1795        *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
1796        Ok(())
1797    }
1798}
1799
1800// FIXME: this is not a memcpy for `T` where `T` is something like `u8`.
1801//
1802// Some attempts to fix this have proved not fruitful. In isolation an attempt
1803// was made where:
1804//
1805// * `MemoryMut` stored a `*mut [u8]` as its "last view" of memory to avoid
1806//   reloading the base pointer constantly. This view is reset on `realloc`.
1807// * The bounds-checks in `MemoryMut::get` were removed (replaced with unsafe
1808//   indexing)
1809//
1810// Even then though this didn't correctly vectorized for `Vec<u8>`. It's not
1811// entirely clear why but it appeared that it's related to reloading the base
1812// pointer to memory (I guess from `MemoryMut` itself?). Overall I'm not really
1813// clear on what's happening there, but this is surely going to be a performance
1814// bottleneck in the future.
1815fn lower_list<T, U>(
1816    cx: &mut LowerContext<'_, U>,
1817    ty: InterfaceType,
1818    list: &[T],
1819) -> Result<(usize, usize)>
1820where
1821    T: Lower,
1822{
1823    let elem_size = T::SIZE32;
1824    let size = list
1825        .len()
1826        .checked_mul(elem_size)
1827        .ok_or_else(|| anyhow!("size overflow copying a list"))?;
1828    let ptr = cx.realloc(0, 0, T::ALIGN32, size)?;
1829    T::linear_store_list_to_memory(cx, ty, ptr, list)?;
1830    Ok((ptr, list.len()))
1831}
1832
1833/// Representation of a list of values that are owned by a WebAssembly instance.
1834///
1835/// For some more commentary about the rationale for this type see the
1836/// documentation of [`WasmStr`]. In summary this type can avoid a copy when
1837/// passing data to the host in some situations but is additionally more
1838/// cumbersome to use by requiring a [`Store`](crate::Store) to be provided.
1839///
1840/// This type is used whenever a `(list T)` is returned from a [`TypedFunc`],
1841/// for example. This type represents a list of values that are stored in linear
1842/// memory which are waiting to be read.
1843///
1844/// Note that this type represents only a valid range of bytes for the list
1845/// itself, it does not represent validity of the elements themselves and that's
1846/// performed when they're iterated.
1847///
1848/// Note that this type does not implement the [`Lower`] trait, only [`Lift`].
1849pub struct WasmList<T> {
1850    ptr: usize,
1851    len: usize,
1852    options: Options,
1853    elem: InterfaceType,
1854    // NB: it would probably be more efficient to store a non-atomic index-style
1855    // reference to something inside a `StoreOpaque`, but that's not easily
1856    // available at this time, so it's left as a future exercise.
1857    types: Arc<ComponentTypes>,
1858    instance: Instance,
1859    _marker: marker::PhantomData<T>,
1860}
1861
1862impl<T: Lift> WasmList<T> {
1863    pub(crate) fn new(
1864        ptr: usize,
1865        len: usize,
1866        cx: &mut LiftContext<'_>,
1867        elem: InterfaceType,
1868    ) -> Result<WasmList<T>> {
1869        match len
1870            .checked_mul(T::SIZE32)
1871            .and_then(|len| ptr.checked_add(len))
1872        {
1873            Some(n) if n <= cx.memory().len() => {}
1874            _ => bail!("list pointer/length out of bounds of memory"),
1875        }
1876        if ptr % usize::try_from(T::ALIGN32)? != 0 {
1877            bail!("list pointer is not aligned")
1878        }
1879        Ok(WasmList {
1880            ptr,
1881            len,
1882            options: *cx.options,
1883            elem,
1884            types: cx.types.clone(),
1885            instance: cx.instance_handle(),
1886            _marker: marker::PhantomData,
1887        })
1888    }
1889
1890    /// Returns the item length of this vector
1891    #[inline]
1892    pub fn len(&self) -> usize {
1893        self.len
1894    }
1895
1896    /// Gets the `n`th element of this list.
1897    ///
1898    /// Returns `None` if `index` is out of bounds. Returns `Some(Err(..))` if
1899    /// the value couldn't be decoded (it was invalid). Returns `Some(Ok(..))`
1900    /// if the value is valid.
1901    ///
1902    /// # Panics
1903    ///
1904    /// This function will panic if the string did not originally come from the
1905    /// `store` specified.
1906    //
1907    // TODO: given that interface values are intended to be consumed in one go
1908    // should we even expose a random access iteration API? In theory all
1909    // consumers should be validating through the iterator.
1910    pub fn get(&self, mut store: impl AsContextMut, index: usize) -> Option<Result<T>> {
1911        let store = store.as_context_mut().0;
1912        self.options.store_id().assert_belongs_to(store.id());
1913        let mut cx = LiftContext::new(store, &self.options, &self.types, self.instance);
1914        self.get_from_store(&mut cx, index)
1915    }
1916
1917    fn get_from_store(&self, cx: &mut LiftContext<'_>, index: usize) -> Option<Result<T>> {
1918        if index >= self.len {
1919            return None;
1920        }
1921        // Note that this is using panicking indexing and this is expected to
1922        // never fail. The bounds-checking here happened during the construction
1923        // of the `WasmList` itself which means these should always be in-bounds
1924        // (and wasm memory can only grow). This could theoretically be
1925        // unchecked indexing if we're confident enough and it's actually a perf
1926        // issue one day.
1927        let bytes = &cx.memory()[self.ptr + index * T::SIZE32..][..T::SIZE32];
1928        Some(T::linear_lift_from_memory(cx, self.elem, bytes))
1929    }
1930
1931    /// Returns an iterator over the elements of this list.
1932    ///
1933    /// Each item of the list may fail to decode and is represented through the
1934    /// `Result` value of the iterator.
1935    pub fn iter<'a, U: 'static>(
1936        &'a self,
1937        store: impl Into<StoreContextMut<'a, U>>,
1938    ) -> impl ExactSizeIterator<Item = Result<T>> + 'a {
1939        let store = store.into().0;
1940        self.options.store_id().assert_belongs_to(store.id());
1941        let mut cx = LiftContext::new(store, &self.options, &self.types, self.instance);
1942        (0..self.len).map(move |i| self.get_from_store(&mut cx, i).unwrap())
1943    }
1944}
1945
1946macro_rules! raw_wasm_list_accessors {
1947    ($($i:ident)*) => ($(
1948        impl WasmList<$i> {
1949            /// Get access to the raw underlying memory for this list.
1950            ///
1951            /// This method will return a direct slice into the original wasm
1952            /// module's linear memory where the data for this slice is stored.
1953            /// This allows the embedder to have efficient access to the
1954            /// underlying memory if needed and avoid copies and such if
1955            /// desired.
1956            ///
1957            /// Note that multi-byte integers are stored in little-endian format
1958            /// so portable processing of this slice must be aware of the host's
1959            /// byte-endianness. The `from_le` constructors in the Rust standard
1960            /// library should be suitable for converting from little-endian.
1961            ///
1962            /// # Panics
1963            ///
1964            /// Panics if the `store` provided is not the one from which this
1965            /// slice originated.
1966            pub fn as_le_slice<'a, T: 'static>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a [$i] {
1967                let memory = self.options.memory(store.into().0);
1968                self._as_le_slice(memory)
1969            }
1970
1971            fn _as_le_slice<'a>(&self, all_of_memory: &'a [u8]) -> &'a [$i] {
1972                // See comments in `WasmList::get` for the panicking indexing
1973                let byte_size = self.len * mem::size_of::<$i>();
1974                let bytes = &all_of_memory[self.ptr..][..byte_size];
1975
1976                // The canonical ABI requires that everything is aligned to its
1977                // own size, so this should be an aligned array. Furthermore the
1978                // alignment of primitive integers for hosts should be smaller
1979                // than or equal to the size of the primitive itself, meaning
1980                // that a wasm canonical-abi-aligned list is also aligned for
1981                // the host. That should mean that the head/tail slices here are
1982                // empty.
1983                //
1984                // Also note that the `unsafe` here is needed since the type
1985                // we're aligning to isn't guaranteed to be valid, but in our
1986                // case it's just integers and bytes so this should be safe.
1987                unsafe {
1988                    let (head, body, tail) = bytes.align_to::<$i>();
1989                    assert!(head.is_empty() && tail.is_empty());
1990                    body
1991                }
1992            }
1993        }
1994    )*)
1995}
1996
1997raw_wasm_list_accessors! {
1998    i8 i16 i32 i64
1999    u8 u16 u32 u64
2000}
2001
2002// Note that this is similar to `ComponentType for str` except it can only be
2003// used for lifting, not lowering.
2004unsafe impl<T: ComponentType> ComponentType for WasmList<T> {
2005    type Lower = <[T] as ComponentType>::Lower;
2006
2007    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
2008
2009    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2010        <[T] as ComponentType>::typecheck(ty, types)
2011    }
2012}
2013
2014unsafe impl<T: Lift> Lift for WasmList<T> {
2015    fn linear_lift_from_flat(
2016        cx: &mut LiftContext<'_>,
2017        ty: InterfaceType,
2018        src: &Self::Lower,
2019    ) -> Result<Self> {
2020        let elem = match ty {
2021            InterfaceType::List(i) => cx.types[i].element,
2022            _ => bad_type_info(),
2023        };
2024        // FIXME(#4311): needs memory64 treatment
2025        let ptr = src[0].get_u32();
2026        let len = src[1].get_u32();
2027        let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?);
2028        WasmList::new(ptr, len, cx, elem)
2029    }
2030
2031    fn linear_lift_from_memory(
2032        cx: &mut LiftContext<'_>,
2033        ty: InterfaceType,
2034        bytes: &[u8],
2035    ) -> Result<Self> {
2036        let elem = match ty {
2037            InterfaceType::List(i) => cx.types[i].element,
2038            _ => bad_type_info(),
2039        };
2040        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2041        // FIXME(#4311): needs memory64 treatment
2042        let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap());
2043        let len = u32::from_le_bytes(bytes[4..].try_into().unwrap());
2044        let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?);
2045        WasmList::new(ptr, len, cx, elem)
2046    }
2047}
2048
2049/// Verify that the given wasm type is a tuple with the expected fields in the right order.
2050fn typecheck_tuple(
2051    ty: &InterfaceType,
2052    types: &InstanceType<'_>,
2053    expected: &[fn(&InterfaceType, &InstanceType<'_>) -> Result<()>],
2054) -> Result<()> {
2055    match ty {
2056        InterfaceType::Tuple(t) => {
2057            let tuple = &types.types[*t];
2058            if tuple.types.len() != expected.len() {
2059                bail!(
2060                    "expected {}-tuple, found {}-tuple",
2061                    expected.len(),
2062                    tuple.types.len()
2063                );
2064            }
2065            for (ty, check) in tuple.types.iter().zip(expected) {
2066                check(ty, types)?;
2067            }
2068            Ok(())
2069        }
2070        other => bail!("expected `tuple` found `{}`", desc(other)),
2071    }
2072}
2073
2074/// Verify that the given wasm type is a record with the expected fields in the right order and with the right
2075/// names.
2076pub fn typecheck_record(
2077    ty: &InterfaceType,
2078    types: &InstanceType<'_>,
2079    expected: &[(&str, fn(&InterfaceType, &InstanceType<'_>) -> Result<()>)],
2080) -> Result<()> {
2081    match ty {
2082        InterfaceType::Record(index) => {
2083            let fields = &types.types[*index].fields;
2084
2085            if fields.len() != expected.len() {
2086                bail!(
2087                    "expected record of {} fields, found {} fields",
2088                    expected.len(),
2089                    fields.len()
2090                );
2091            }
2092
2093            for (field, &(name, check)) in fields.iter().zip(expected) {
2094                check(&field.ty, types)
2095                    .with_context(|| format!("type mismatch for field {name}"))?;
2096
2097                if field.name != name {
2098                    bail!("expected record field named {}, found {}", name, field.name);
2099                }
2100            }
2101
2102            Ok(())
2103        }
2104        other => bail!("expected `record` found `{}`", desc(other)),
2105    }
2106}
2107
2108/// Verify that the given wasm type is a variant with the expected cases in the right order and with the right
2109/// names.
2110pub fn typecheck_variant(
2111    ty: &InterfaceType,
2112    types: &InstanceType<'_>,
2113    expected: &[(
2114        &str,
2115        Option<fn(&InterfaceType, &InstanceType<'_>) -> Result<()>>,
2116    )],
2117) -> Result<()> {
2118    match ty {
2119        InterfaceType::Variant(index) => {
2120            let cases = &types.types[*index].cases;
2121
2122            if cases.len() != expected.len() {
2123                bail!(
2124                    "expected variant of {} cases, found {} cases",
2125                    expected.len(),
2126                    cases.len()
2127                );
2128            }
2129
2130            for ((case_name, case_ty), &(name, check)) in cases.iter().zip(expected) {
2131                if *case_name != name {
2132                    bail!("expected variant case named {name}, found {case_name}");
2133                }
2134
2135                match (check, case_ty) {
2136                    (Some(check), Some(ty)) => check(ty, types)
2137                        .with_context(|| format!("type mismatch for case {name}"))?,
2138                    (None, None) => {}
2139                    (Some(_), None) => {
2140                        bail!("case `{name}` has no type but one was expected")
2141                    }
2142                    (None, Some(_)) => {
2143                        bail!("case `{name}` has a type but none was expected")
2144                    }
2145                }
2146            }
2147
2148            Ok(())
2149        }
2150        other => bail!("expected `variant` found `{}`", desc(other)),
2151    }
2152}
2153
2154/// Verify that the given wasm type is a enum with the expected cases in the right order and with the right
2155/// names.
2156pub fn typecheck_enum(
2157    ty: &InterfaceType,
2158    types: &InstanceType<'_>,
2159    expected: &[&str],
2160) -> Result<()> {
2161    match ty {
2162        InterfaceType::Enum(index) => {
2163            let names = &types.types[*index].names;
2164
2165            if names.len() != expected.len() {
2166                bail!(
2167                    "expected enum of {} names, found {} names",
2168                    expected.len(),
2169                    names.len()
2170                );
2171            }
2172
2173            for (name, expected) in names.iter().zip(expected) {
2174                if name != expected {
2175                    bail!("expected enum case named {}, found {}", expected, name);
2176                }
2177            }
2178
2179            Ok(())
2180        }
2181        other => bail!("expected `enum` found `{}`", desc(other)),
2182    }
2183}
2184
2185/// Verify that the given wasm type is a flags type with the expected flags in the right order and with the right
2186/// names.
2187pub fn typecheck_flags(
2188    ty: &InterfaceType,
2189    types: &InstanceType<'_>,
2190    expected: &[&str],
2191) -> Result<()> {
2192    match ty {
2193        InterfaceType::Flags(index) => {
2194            let names = &types.types[*index].names;
2195
2196            if names.len() != expected.len() {
2197                bail!(
2198                    "expected flags type with {} names, found {} names",
2199                    expected.len(),
2200                    names.len()
2201                );
2202            }
2203
2204            for (name, expected) in names.iter().zip(expected) {
2205                if name != expected {
2206                    bail!("expected flag named {}, found {}", expected, name);
2207                }
2208            }
2209
2210            Ok(())
2211        }
2212        other => bail!("expected `flags` found `{}`", desc(other)),
2213    }
2214}
2215
2216/// Format the specified bitflags using the specified names for debugging
2217pub fn format_flags(bits: &[u32], names: &[&str], f: &mut fmt::Formatter) -> fmt::Result {
2218    f.write_str("(")?;
2219    let mut wrote = false;
2220    for (index, name) in names.iter().enumerate() {
2221        if ((bits[index / 32] >> (index % 32)) & 1) != 0 {
2222            if wrote {
2223                f.write_str("|")?;
2224            } else {
2225                wrote = true;
2226            }
2227
2228            f.write_str(name)?;
2229        }
2230    }
2231    f.write_str(")")
2232}
2233
2234unsafe impl<T> ComponentType for Option<T>
2235where
2236    T: ComponentType,
2237{
2238    type Lower = TupleLower<<u32 as ComponentType>::Lower, T::Lower>;
2239
2240    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[None, Some(T::ABI)]);
2241
2242    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2243        match ty {
2244            InterfaceType::Option(t) => T::typecheck(&types.types[*t].ty, types),
2245            other => bail!("expected `option` found `{}`", desc(other)),
2246        }
2247    }
2248}
2249
2250unsafe impl<T> ComponentVariant for Option<T>
2251where
2252    T: ComponentType,
2253{
2254    const CASES: &'static [Option<CanonicalAbiInfo>] = &[None, Some(T::ABI)];
2255}
2256
2257unsafe impl<T> Lower for Option<T>
2258where
2259    T: Lower,
2260{
2261    fn linear_lower_to_flat<U>(
2262        &self,
2263        cx: &mut LowerContext<'_, U>,
2264        ty: InterfaceType,
2265        dst: &mut MaybeUninit<Self::Lower>,
2266    ) -> Result<()> {
2267        let payload = match ty {
2268            InterfaceType::Option(ty) => cx.types[ty].ty,
2269            _ => bad_type_info(),
2270        };
2271        match self {
2272            None => {
2273                map_maybe_uninit!(dst.A1).write(ValRaw::i32(0));
2274                // Note that this is unsafe as we're writing an arbitrary
2275                // bit-pattern to an arbitrary type, but part of the unsafe
2276                // contract of the `ComponentType` trait is that we can assign
2277                // any bit-pattern. By writing all zeros here we're ensuring
2278                // that the core wasm arguments this translates to will all be
2279                // zeros (as the canonical ABI requires).
2280                unsafe {
2281                    map_maybe_uninit!(dst.A2).as_mut_ptr().write_bytes(0u8, 1);
2282                }
2283            }
2284            Some(val) => {
2285                map_maybe_uninit!(dst.A1).write(ValRaw::i32(1));
2286                val.linear_lower_to_flat(cx, payload, map_maybe_uninit!(dst.A2))?;
2287            }
2288        }
2289        Ok(())
2290    }
2291
2292    fn linear_lower_to_memory<U>(
2293        &self,
2294        cx: &mut LowerContext<'_, U>,
2295        ty: InterfaceType,
2296        offset: usize,
2297    ) -> Result<()> {
2298        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2299        let payload = match ty {
2300            InterfaceType::Option(ty) => cx.types[ty].ty,
2301            _ => bad_type_info(),
2302        };
2303        match self {
2304            None => {
2305                cx.get::<1>(offset)[0] = 0;
2306            }
2307            Some(val) => {
2308                cx.get::<1>(offset)[0] = 1;
2309                val.linear_lower_to_memory(
2310                    cx,
2311                    payload,
2312                    offset + (Self::INFO.payload_offset32 as usize),
2313                )?;
2314            }
2315        }
2316        Ok(())
2317    }
2318}
2319
2320unsafe impl<T> Lift for Option<T>
2321where
2322    T: Lift,
2323{
2324    fn linear_lift_from_flat(
2325        cx: &mut LiftContext<'_>,
2326        ty: InterfaceType,
2327        src: &Self::Lower,
2328    ) -> Result<Self> {
2329        let payload = match ty {
2330            InterfaceType::Option(ty) => cx.types[ty].ty,
2331            _ => bad_type_info(),
2332        };
2333        Ok(match src.A1.get_i32() {
2334            0 => None,
2335            1 => Some(T::linear_lift_from_flat(cx, payload, &src.A2)?),
2336            _ => bail!("invalid option discriminant"),
2337        })
2338    }
2339
2340    fn linear_lift_from_memory(
2341        cx: &mut LiftContext<'_>,
2342        ty: InterfaceType,
2343        bytes: &[u8],
2344    ) -> Result<Self> {
2345        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2346        let payload_ty = match ty {
2347            InterfaceType::Option(ty) => cx.types[ty].ty,
2348            _ => bad_type_info(),
2349        };
2350        let discrim = bytes[0];
2351        let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2352        match discrim {
2353            0 => Ok(None),
2354            1 => Ok(Some(T::linear_lift_from_memory(cx, payload_ty, payload)?)),
2355            _ => bail!("invalid option discriminant"),
2356        }
2357    }
2358}
2359
2360#[derive(Clone, Copy)]
2361#[repr(C)]
2362pub struct ResultLower<T: Copy, E: Copy> {
2363    tag: ValRaw,
2364    payload: ResultLowerPayload<T, E>,
2365}
2366
2367#[derive(Clone, Copy)]
2368#[repr(C)]
2369union ResultLowerPayload<T: Copy, E: Copy> {
2370    ok: T,
2371    err: E,
2372}
2373
2374unsafe impl<T, E> ComponentType for Result<T, E>
2375where
2376    T: ComponentType,
2377    E: ComponentType,
2378{
2379    type Lower = ResultLower<T::Lower, E::Lower>;
2380
2381    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[Some(T::ABI), Some(E::ABI)]);
2382
2383    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2384        match ty {
2385            InterfaceType::Result(r) => {
2386                let result = &types.types[*r];
2387                match &result.ok {
2388                    Some(ty) => T::typecheck(ty, types)?,
2389                    None if T::IS_RUST_UNIT_TYPE => {}
2390                    None => bail!("expected no `ok` type"),
2391                }
2392                match &result.err {
2393                    Some(ty) => E::typecheck(ty, types)?,
2394                    None if E::IS_RUST_UNIT_TYPE => {}
2395                    None => bail!("expected no `err` type"),
2396                }
2397                Ok(())
2398            }
2399            other => bail!("expected `result` found `{}`", desc(other)),
2400        }
2401    }
2402}
2403
2404/// Lowers the payload of a variant into the storage for the entire payload,
2405/// handling writing zeros at the end of the representation if this payload is
2406/// smaller than the entire flat representation.
2407///
2408/// * `payload` - the flat storage space for the entire payload of the variant
2409/// * `typed_payload` - projection from the payload storage space to the
2410///   individual storage space for this variant.
2411/// * `lower` - lowering operation used to initialize the `typed_payload` return
2412///   value.
2413///
2414/// For more information on this se the comments in the `Lower for Result`
2415/// implementation below.
2416pub unsafe fn lower_payload<P, T>(
2417    payload: &mut MaybeUninit<P>,
2418    typed_payload: impl FnOnce(&mut MaybeUninit<P>) -> &mut MaybeUninit<T>,
2419    lower: impl FnOnce(&mut MaybeUninit<T>) -> Result<()>,
2420) -> Result<()> {
2421    let typed = typed_payload(payload);
2422    lower(typed)?;
2423
2424    let typed_len = storage_as_slice(typed).len();
2425    let payload = storage_as_slice_mut(payload);
2426    for slot in payload[typed_len..].iter_mut() {
2427        slot.write(ValRaw::u64(0));
2428    }
2429    Ok(())
2430}
2431
2432unsafe impl<T, E> ComponentVariant for Result<T, E>
2433where
2434    T: ComponentType,
2435    E: ComponentType,
2436{
2437    const CASES: &'static [Option<CanonicalAbiInfo>] = &[Some(T::ABI), Some(E::ABI)];
2438}
2439
2440unsafe impl<T, E> Lower for Result<T, E>
2441where
2442    T: Lower,
2443    E: Lower,
2444{
2445    fn linear_lower_to_flat<U>(
2446        &self,
2447        cx: &mut LowerContext<'_, U>,
2448        ty: InterfaceType,
2449        dst: &mut MaybeUninit<Self::Lower>,
2450    ) -> Result<()> {
2451        let (ok, err) = match ty {
2452            InterfaceType::Result(ty) => {
2453                let ty = &cx.types[ty];
2454                (ty.ok, ty.err)
2455            }
2456            _ => bad_type_info(),
2457        };
2458
2459        // This implementation of `Lower::lower`, if you're reading these from
2460        // the top of this file, is the first location that the "join" logic of
2461        // the component model's canonical ABI encountered. The rough problem is
2462        // that let's say we have a component model type of the form:
2463        //
2464        //      (result u64 (error (tuple f32 u16)))
2465        //
2466        // The flat representation of this is actually pretty tricky. Currently
2467        // it is:
2468        //
2469        //      i32 i64 i32
2470        //
2471        // The first `i32` is the discriminant for the `result`, and the payload
2472        // is represented by `i64 i32`. The "ok" variant will only use the `i64`
2473        // and the "err" variant will use both `i64` and `i32`.
2474        //
2475        // In the "ok" variant the first issue is encountered. The size of one
2476        // variant may not match the size of the other variants. All variants
2477        // start at the "front" but when lowering a type we need to be sure to
2478        // initialize the later variants (lest we leak random host memory into
2479        // the guest module). Due to how the `Lower` type is represented as a
2480        // `union` of all the variants what ends up happening here is that
2481        // internally within the `lower_payload` after the typed payload is
2482        // lowered the remaining bits of the payload that weren't initialized
2483        // are all set to zero. This will guarantee that we'll write to all the
2484        // slots for each variant.
2485        //
2486        // The "err" variant encounters the second issue, however, which is that
2487        // the flat representation for each type may differ between payloads. In
2488        // the "ok" arm an `i64` is written, but the `lower` implementation for
2489        // the "err" arm will write an `f32` and then an `i32`. For this
2490        // implementation of `lower` to be valid the `f32` needs to get inflated
2491        // to an `i64` with zero-padding in the upper bits. What may be
2492        // surprising, however, is that none of this is handled in this file.
2493        // This implementation looks like it's blindly deferring to `E::lower`
2494        // and hoping it does the right thing.
2495        //
2496        // In reality, however, the correctness of variant lowering relies on
2497        // two subtle details of the `ValRaw` implementation in Wasmtime:
2498        //
2499        // 1. First the `ValRaw` value always contains little-endian values.
2500        //    This means that if a `u32` is written, a `u64` is read, and then
2501        //    the `u64` has its upper bits truncated the original value will
2502        //    always be retained. This is primarily here for big-endian
2503        //    platforms where if it weren't little endian then the opposite
2504        //    would occur and the wrong value would be read.
2505        //
2506        // 2. Second, and perhaps even more subtly, the `ValRaw` constructors
2507        //    for 32-bit types actually always initialize 64-bits of the
2508        //    `ValRaw`. In the component model flat ABI only 32 and 64-bit types
2509        //    are used so 64-bits is big enough to contain everything. This
2510        //    means that when a `ValRaw` is written into the destination it will
2511        //    always, whether it's needed or not, be "ready" to get extended up
2512        //    to 64-bits.
2513        //
2514        // Put together these two subtle guarantees means that all `Lower`
2515        // implementations can be written "naturally" as one might naively
2516        // expect. Variants will, on each arm, zero out remaining fields and all
2517        // writes to the flat representation will automatically be 64-bit writes
2518        // meaning that if the value is read as a 64-bit value, which isn't
2519        // known at the time of the write, it'll still be correct.
2520        match self {
2521            Ok(e) => {
2522                map_maybe_uninit!(dst.tag).write(ValRaw::i32(0));
2523                unsafe {
2524                    lower_payload(
2525                        map_maybe_uninit!(dst.payload),
2526                        |payload| map_maybe_uninit!(payload.ok),
2527                        |dst| match ok {
2528                            Some(ok) => e.linear_lower_to_flat(cx, ok, dst),
2529                            None => Ok(()),
2530                        },
2531                    )
2532                }
2533            }
2534            Err(e) => {
2535                map_maybe_uninit!(dst.tag).write(ValRaw::i32(1));
2536                unsafe {
2537                    lower_payload(
2538                        map_maybe_uninit!(dst.payload),
2539                        |payload| map_maybe_uninit!(payload.err),
2540                        |dst| match err {
2541                            Some(err) => e.linear_lower_to_flat(cx, err, dst),
2542                            None => Ok(()),
2543                        },
2544                    )
2545                }
2546            }
2547        }
2548    }
2549
2550    fn linear_lower_to_memory<U>(
2551        &self,
2552        cx: &mut LowerContext<'_, U>,
2553        ty: InterfaceType,
2554        offset: usize,
2555    ) -> Result<()> {
2556        let (ok, err) = match ty {
2557            InterfaceType::Result(ty) => {
2558                let ty = &cx.types[ty];
2559                (ty.ok, ty.err)
2560            }
2561            _ => bad_type_info(),
2562        };
2563        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2564        let payload_offset = Self::INFO.payload_offset32 as usize;
2565        match self {
2566            Ok(e) => {
2567                cx.get::<1>(offset)[0] = 0;
2568                if let Some(ok) = ok {
2569                    e.linear_lower_to_memory(cx, ok, offset + payload_offset)?;
2570                }
2571            }
2572            Err(e) => {
2573                cx.get::<1>(offset)[0] = 1;
2574                if let Some(err) = err {
2575                    e.linear_lower_to_memory(cx, err, offset + payload_offset)?;
2576                }
2577            }
2578        }
2579        Ok(())
2580    }
2581}
2582
2583unsafe impl<T, E> Lift for Result<T, E>
2584where
2585    T: Lift,
2586    E: Lift,
2587{
2588    #[inline]
2589    fn linear_lift_from_flat(
2590        cx: &mut LiftContext<'_>,
2591        ty: InterfaceType,
2592        src: &Self::Lower,
2593    ) -> Result<Self> {
2594        let (ok, err) = match ty {
2595            InterfaceType::Result(ty) => {
2596                let ty = &cx.types[ty];
2597                (ty.ok, ty.err)
2598            }
2599            _ => bad_type_info(),
2600        };
2601        // Note that this implementation specifically isn't trying to actually
2602        // reinterpret or alter the bits of `lower` depending on which variant
2603        // we're lifting. This ends up all working out because the value is
2604        // stored in little-endian format.
2605        //
2606        // When stored in little-endian format the `{T,E}::Lower`, when each
2607        // individual `ValRaw` is read, means that if an i64 value, extended
2608        // from an i32 value, was stored then when the i32 value is read it'll
2609        // automatically ignore the upper bits.
2610        //
2611        // This "trick" allows us to seamlessly pass through the `Self::Lower`
2612        // representation into the lifting/lowering without trying to handle
2613        // "join"ed types as per the canonical ABI. It just so happens that i64
2614        // bits will naturally be reinterpreted as f64. Additionally if the
2615        // joined type is i64 but only the lower bits are read that's ok and we
2616        // don't need to validate the upper bits.
2617        //
2618        // This is largely enabled by WebAssembly/component-model#35 where no
2619        // validation needs to be performed for ignored bits and bytes here.
2620        Ok(match src.tag.get_i32() {
2621            0 => Ok(unsafe { lift_option(cx, ok, &src.payload.ok)? }),
2622            1 => Err(unsafe { lift_option(cx, err, &src.payload.err)? }),
2623            _ => bail!("invalid expected discriminant"),
2624        })
2625    }
2626
2627    #[inline]
2628    fn linear_lift_from_memory(
2629        cx: &mut LiftContext<'_>,
2630        ty: InterfaceType,
2631        bytes: &[u8],
2632    ) -> Result<Self> {
2633        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2634        let discrim = bytes[0];
2635        let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2636        let (ok, err) = match ty {
2637            InterfaceType::Result(ty) => {
2638                let ty = &cx.types[ty];
2639                (ty.ok, ty.err)
2640            }
2641            _ => bad_type_info(),
2642        };
2643        match discrim {
2644            0 => Ok(Ok(load_option(cx, ok, &payload[..T::SIZE32])?)),
2645            1 => Ok(Err(load_option(cx, err, &payload[..E::SIZE32])?)),
2646            _ => bail!("invalid expected discriminant"),
2647        }
2648    }
2649}
2650
2651fn lift_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, src: &T::Lower) -> Result<T>
2652where
2653    T: Lift,
2654{
2655    match ty {
2656        Some(ty) => T::linear_lift_from_flat(cx, ty, src),
2657        None => Ok(empty_lift()),
2658    }
2659}
2660
2661fn load_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, bytes: &[u8]) -> Result<T>
2662where
2663    T: Lift,
2664{
2665    match ty {
2666        Some(ty) => T::linear_lift_from_memory(cx, ty, bytes),
2667        None => Ok(empty_lift()),
2668    }
2669}
2670
2671fn empty_lift<T>() -> T
2672where
2673    T: Lift,
2674{
2675    assert!(T::IS_RUST_UNIT_TYPE);
2676    assert_eq!(mem::size_of::<T>(), 0);
2677    unsafe { MaybeUninit::uninit().assume_init() }
2678}
2679
2680/// Helper structure to define `Lower` for tuples below.
2681///
2682/// Uses default type parameters to have fields be zero-sized and not present
2683/// in memory for smaller tuple values.
2684#[expect(non_snake_case, reason = "more amenable to macro-generated code")]
2685#[doc(hidden)]
2686#[derive(Clone, Copy)]
2687#[repr(C)]
2688pub struct TupleLower<
2689    T1 = (),
2690    T2 = (),
2691    T3 = (),
2692    T4 = (),
2693    T5 = (),
2694    T6 = (),
2695    T7 = (),
2696    T8 = (),
2697    T9 = (),
2698    T10 = (),
2699    T11 = (),
2700    T12 = (),
2701    T13 = (),
2702    T14 = (),
2703    T15 = (),
2704    T16 = (),
2705    T17 = (),
2706> {
2707    // NB: these names match the names in `for_each_function_signature!`
2708    A1: T1,
2709    A2: T2,
2710    A3: T3,
2711    A4: T4,
2712    A5: T5,
2713    A6: T6,
2714    A7: T7,
2715    A8: T8,
2716    A9: T9,
2717    A10: T10,
2718    A11: T11,
2719    A12: T12,
2720    A13: T13,
2721    A14: T14,
2722    A15: T15,
2723    A16: T16,
2724    A17: T17,
2725    _align_tuple_lower0_correctly: [ValRaw; 0],
2726}
2727
2728macro_rules! impl_component_ty_for_tuples {
2729    ($n:tt $($t:ident)*) => {
2730        #[allow(non_snake_case, reason = "macro-generated code")]
2731        unsafe impl<$($t,)*> ComponentType for ($($t,)*)
2732            where $($t: ComponentType),*
2733        {
2734            type Lower = TupleLower<$($t::Lower),*>;
2735
2736            const ABI: CanonicalAbiInfo = CanonicalAbiInfo::record_static(&[
2737                $($t::ABI),*
2738            ]);
2739
2740            const IS_RUST_UNIT_TYPE: bool = {
2741                let mut _is_unit = true;
2742                $(
2743                    let _anything_to_bind_the_macro_variable = $t::IS_RUST_UNIT_TYPE;
2744                    _is_unit = false;
2745                )*
2746                _is_unit
2747            };
2748
2749            fn typecheck(
2750                ty: &InterfaceType,
2751                types: &InstanceType<'_>,
2752            ) -> Result<()> {
2753                typecheck_tuple(ty, types, &[$($t::typecheck),*])
2754            }
2755        }
2756
2757        #[allow(non_snake_case, reason = "macro-generated code")]
2758        unsafe impl<$($t,)*> Lower for ($($t,)*)
2759            where $($t: Lower),*
2760        {
2761            fn linear_lower_to_flat<U>(
2762                &self,
2763                cx: &mut LowerContext<'_, U>,
2764                ty: InterfaceType,
2765                _dst: &mut MaybeUninit<Self::Lower>,
2766            ) -> Result<()> {
2767                let types = match ty {
2768                    InterfaceType::Tuple(t) => &cx.types[t].types,
2769                    _ => bad_type_info(),
2770                };
2771                let ($($t,)*) = self;
2772                let mut _types = types.iter();
2773                $(
2774                    let ty = *_types.next().unwrap_or_else(bad_type_info);
2775                    $t.linear_lower_to_flat(cx, ty, map_maybe_uninit!(_dst.$t))?;
2776                )*
2777                Ok(())
2778            }
2779
2780            fn linear_lower_to_memory<U>(
2781                &self,
2782                cx: &mut LowerContext<'_, U>,
2783                ty: InterfaceType,
2784                mut _offset: usize,
2785            ) -> Result<()> {
2786                debug_assert!(_offset % (Self::ALIGN32 as usize) == 0);
2787                let types = match ty {
2788                    InterfaceType::Tuple(t) => &cx.types[t].types,
2789                    _ => bad_type_info(),
2790                };
2791                let ($($t,)*) = self;
2792                let mut _types = types.iter();
2793                $(
2794                    let ty = *_types.next().unwrap_or_else(bad_type_info);
2795                    $t.linear_lower_to_memory(cx, ty, $t::ABI.next_field32_size(&mut _offset))?;
2796                )*
2797                Ok(())
2798            }
2799        }
2800
2801        #[allow(non_snake_case, reason = "macro-generated code")]
2802        unsafe impl<$($t,)*> Lift for ($($t,)*)
2803            where $($t: Lift),*
2804        {
2805            #[inline]
2806            fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, _src: &Self::Lower) -> Result<Self> {
2807                let types = match ty {
2808                    InterfaceType::Tuple(t) => &cx.types[t].types,
2809                    _ => bad_type_info(),
2810                };
2811                let mut _types = types.iter();
2812                Ok(($(
2813                    $t::linear_lift_from_flat(
2814                        cx,
2815                        *_types.next().unwrap_or_else(bad_type_info),
2816                        &_src.$t,
2817                    )?,
2818                )*))
2819            }
2820
2821            #[inline]
2822            fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
2823                debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2824                let types = match ty {
2825                    InterfaceType::Tuple(t) => &cx.types[t].types,
2826                    _ => bad_type_info(),
2827                };
2828                let mut _types = types.iter();
2829                let mut _offset = 0;
2830                $(
2831                    let ty = *_types.next().unwrap_or_else(bad_type_info);
2832                    let $t = $t::linear_lift_from_memory(cx, ty, &bytes[$t::ABI.next_field32_size(&mut _offset)..][..$t::SIZE32])?;
2833                )*
2834                Ok(($($t,)*))
2835            }
2836        }
2837
2838        #[allow(non_snake_case, reason = "macro-generated code")]
2839        unsafe impl<$($t,)*> ComponentNamedList for ($($t,)*)
2840            where $($t: ComponentType),*
2841        {}
2842    };
2843}
2844
2845for_each_function_signature!(impl_component_ty_for_tuples);
2846
2847pub fn desc(ty: &InterfaceType) -> &'static str {
2848    match ty {
2849        InterfaceType::U8 => "u8",
2850        InterfaceType::S8 => "s8",
2851        InterfaceType::U16 => "u16",
2852        InterfaceType::S16 => "s16",
2853        InterfaceType::U32 => "u32",
2854        InterfaceType::S32 => "s32",
2855        InterfaceType::U64 => "u64",
2856        InterfaceType::S64 => "s64",
2857        InterfaceType::Float32 => "f32",
2858        InterfaceType::Float64 => "f64",
2859        InterfaceType::Bool => "bool",
2860        InterfaceType::Char => "char",
2861        InterfaceType::String => "string",
2862        InterfaceType::List(_) => "list",
2863        InterfaceType::Tuple(_) => "tuple",
2864        InterfaceType::Option(_) => "option",
2865        InterfaceType::Result(_) => "result",
2866
2867        InterfaceType::Record(_) => "record",
2868        InterfaceType::Variant(_) => "variant",
2869        InterfaceType::Flags(_) => "flags",
2870        InterfaceType::Enum(_) => "enum",
2871        InterfaceType::Own(_) => "owned resource",
2872        InterfaceType::Borrow(_) => "borrowed resource",
2873        InterfaceType::Future(_) => "future",
2874        InterfaceType::Stream(_) => "stream",
2875        InterfaceType::ErrorContext(_) => "error-context",
2876    }
2877}
2878
2879#[cold]
2880#[doc(hidden)]
2881pub fn bad_type_info<T>() -> T {
2882    // NB: should consider something like `unreachable_unchecked` here if this
2883    // becomes a performance bottleneck at some point, but that also comes with
2884    // a tradeoff of propagating a lot of unsafety, so it may not be worth it.
2885    panic!("bad type information detected");
2886}