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