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