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