wasmtime/runtime/component/func/
typed.rs

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