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