1 //! Runtime support for the Component Model Async ABI.
2 //!
3 //! This module and its submodules provide host runtime support for Component
4 //! Model Async features such as async-lifted exports, async-lowered imports,
5 //! streams, futures, and related intrinsics.  See [the Async
6 //! Explainer](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Concurrency.md)
7 //! for a high-level overview.
8 //!
9 //! At the core of this support is an event loop which schedules and switches
10 //! between guest tasks and any host tasks they create.  Each
11 //! `Store` will have at most one event loop running at any given
12 //! time, and that loop may be suspended and resumed by the host embedder using
13 //! e.g. `StoreContextMut::run_concurrent`.  The `StoreContextMut::poll_until`
14 //! function contains the loop itself, while the
15 //! `StoreOpaque::concurrent_state` field holds its state.
16 //!
17 //! # Public API Overview
18 //!
19 //! ## Top-level API (e.g. kicking off host->guest calls and driving the event loop)
20 //!
21 //! - `[Typed]Func::call_concurrent`: Start a host->guest call to an
22 //! async-lifted or sync-lifted import, creating a guest task.
23 //!
24 //! - `StoreContextMut::run_concurrent`: Run the event loop for the specified
25 //! instance, allowing any and all tasks belonging to that instance to make
26 //! progress.
27 //!
28 //! - `StoreContextMut::spawn`: Run a background task as part of the event loop
29 //! for the specified instance.
30 //!
31 //! - `{Future,Stream}Reader::new`: Create a new Component Model `future` or
32 //! `stream` which may be passed to the guest.  This takes a
33 //! `{Future,Stream}Producer` implementation which will be polled for items when
34 //! the consumer requests them.
35 //!
36 //! - `{Future,Stream}Reader::pipe`: Consume a `future` or `stream` by
37 //! connecting it to a `{Future,Stream}Consumer` which will consume any items
38 //! produced by the write end.
39 //!
40 //! ## Host Task API (e.g. implementing concurrent host functions and background tasks)
41 //!
42 //! - `LinkerInstance::func_wrap_concurrent`: Register a concurrent host
43 //! function with the linker.  That function will take an `Accessor` as its
44 //! first parameter, which provides access to the store between (but not across)
45 //! await points.
46 //!
47 //! - `Accessor::with`: Access the store and its associated data.
48 //!
49 //! - `Accessor::spawn`: Run a background task as part of the event loop for the
50 //! store.  This is equivalent to `StoreContextMut::spawn` but more convenient to use
51 //! in host functions.
52 
53 use crate::component::func::{self, Func, call_post_return};
54 use crate::component::{
55     HasData, HasSelf, Instance, Resource, ResourceTable, ResourceTableError, RuntimeInstance,
56 };
57 use crate::fiber::{self, StoreFiber, StoreFiberYield};
58 use crate::prelude::*;
59 use crate::store::{Store, StoreId, StoreInner, StoreOpaque, StoreToken};
60 use crate::vm::component::{CallContext, ComponentInstance, InstanceState};
61 use crate::vm::{AlwaysMut, SendSyncPtr, VMFuncRef, VMMemoryDefinition, VMStore};
62 use crate::{
63     AsContext, AsContextMut, FuncType, Result, StoreContext, StoreContextMut, ValRaw, ValType,
64     bail, error::format_err,
65 };
66 use error_contexts::GlobalErrorContextRefCount;
67 use futures::channel::oneshot;
68 use futures::future::{self, FutureExt};
69 use futures::stream::{FuturesUnordered, StreamExt};
70 use futures_and_streams::{FlatAbi, ReturnCode, TransmitHandle, TransmitIndex};
71 use std::any::Any;
72 use std::borrow::ToOwned;
73 use std::boxed::Box;
74 use std::cell::UnsafeCell;
75 use std::collections::{BTreeMap, BTreeSet, HashSet, VecDeque};
76 use std::fmt;
77 use std::future::Future;
78 use std::marker::PhantomData;
79 use std::mem::{self, ManuallyDrop, MaybeUninit};
80 use std::ops::DerefMut;
81 use std::pin::{Pin, pin};
82 use std::ptr::{self, NonNull};
83 use std::task::{Context, Poll, Waker};
84 use std::vec::Vec;
85 use table::{TableDebug, TableId};
86 use wasmtime_environ::Trap;
87 use wasmtime_environ::component::{
88     CanonicalAbiInfo, CanonicalOptions, CanonicalOptionsDataModel, MAX_FLAT_PARAMS,
89     MAX_FLAT_RESULTS, OptionsIndex, PREPARE_ASYNC_NO_RESULT, PREPARE_ASYNC_WITH_RESULT,
90     RuntimeComponentInstanceIndex, RuntimeTableIndex, StringEncoding,
91     TypeComponentGlobalErrorContextTableIndex, TypeComponentLocalErrorContextTableIndex,
92     TypeFuncIndex, TypeFutureTableIndex, TypeStreamTableIndex, TypeTupleIndex,
93 };
94 use wasmtime_environ::packed_option::ReservedValue;
95 
96 pub use abort::JoinHandle;
97 pub use future_stream_any::{FutureAny, StreamAny};
98 pub use futures_and_streams::{
99     Destination, DirectDestination, DirectSource, ErrorContext, FutureConsumer, FutureProducer,
100     FutureReader, GuardedFutureReader, GuardedStreamReader, ReadBuffer, Source, StreamConsumer,
101     StreamProducer, StreamReader, StreamResult, VecBuffer, WriteBuffer,
102 };
103 pub(crate) use futures_and_streams::{ResourcePair, lower_error_context_to_index};
104 
105 mod abort;
106 mod error_contexts;
107 mod future_stream_any;
108 mod futures_and_streams;
109 pub(crate) mod table;
110 pub(crate) mod tls;
111 
112 /// Constant defined in the Component Model spec to indicate that the async
113 /// intrinsic (e.g. `future.write`) has not yet completed.
114 const BLOCKED: u32 = 0xffff_ffff;
115 
116 /// Corresponds to `CallState` in the upstream spec.
117 #[derive(Clone, Copy, Eq, PartialEq, Debug)]
118 pub enum Status {
119     Starting = 0,
120     Started = 1,
121     Returned = 2,
122     StartCancelled = 3,
123     ReturnCancelled = 4,
124 }
125 
126 impl Status {
127     /// Packs this status and the optional `waitable` provided into a 32-bit
128     /// result that the canonical ABI requires.
129     ///
130     /// The low 4 bits are reserved for the status while the upper 28 bits are
131     /// the waitable, if present.
132     pub fn pack(self, waitable: Option<u32>) -> u32 {
133         assert!(matches!(self, Status::Returned) == waitable.is_none());
134         let waitable = waitable.unwrap_or(0);
135         assert!(waitable < (1 << 28));
136         (waitable << 4) | (self as u32)
137     }
138 }
139 
140 /// Corresponds to `EventCode` in the Component Model spec, plus related payload
141 /// data.
142 #[derive(Clone, Copy, Debug)]
143 enum Event {
144     None,
145     Cancelled,
146     Subtask {
147         status: Status,
148     },
149     StreamRead {
150         code: ReturnCode,
151         pending: Option<(TypeStreamTableIndex, u32)>,
152     },
153     StreamWrite {
154         code: ReturnCode,
155         pending: Option<(TypeStreamTableIndex, u32)>,
156     },
157     FutureRead {
158         code: ReturnCode,
159         pending: Option<(TypeFutureTableIndex, u32)>,
160     },
161     FutureWrite {
162         code: ReturnCode,
163         pending: Option<(TypeFutureTableIndex, u32)>,
164     },
165 }
166 
167 impl Event {
168     /// Lower this event to core Wasm integers for delivery to the guest.
169     ///
170     /// Note that the waitable handle, if any, is assumed to be lowered
171     /// separately.
172     fn parts(self) -> (u32, u32) {
173         const EVENT_NONE: u32 = 0;
174         const EVENT_SUBTASK: u32 = 1;
175         const EVENT_STREAM_READ: u32 = 2;
176         const EVENT_STREAM_WRITE: u32 = 3;
177         const EVENT_FUTURE_READ: u32 = 4;
178         const EVENT_FUTURE_WRITE: u32 = 5;
179         const EVENT_CANCELLED: u32 = 6;
180         match self {
181             Event::None => (EVENT_NONE, 0),
182             Event::Cancelled => (EVENT_CANCELLED, 0),
183             Event::Subtask { status } => (EVENT_SUBTASK, status as u32),
184             Event::StreamRead { code, .. } => (EVENT_STREAM_READ, code.encode()),
185             Event::StreamWrite { code, .. } => (EVENT_STREAM_WRITE, code.encode()),
186             Event::FutureRead { code, .. } => (EVENT_FUTURE_READ, code.encode()),
187             Event::FutureWrite { code, .. } => (EVENT_FUTURE_WRITE, code.encode()),
188         }
189     }
190 }
191 
192 /// Corresponds to `CallbackCode` in the spec.
193 mod callback_code {
194     pub const EXIT: u32 = 0;
195     pub const YIELD: u32 = 1;
196     pub const WAIT: u32 = 2;
197 }
198 
199 /// A flag indicating that the callee is an async-lowered export.
200 ///
201 /// This may be passed to the `async-start` intrinsic from a fused adapter.
202 const START_FLAG_ASYNC_CALLEE: u32 = wasmtime_environ::component::START_FLAG_ASYNC_CALLEE as u32;
203 
204 /// Provides access to either store data (via the `get` method) or the store
205 /// itself (via [`AsContext`]/[`AsContextMut`]), as well as the component
206 /// instance to which the current host task belongs.
207 ///
208 /// See [`Accessor::with`] for details.
209 pub struct Access<'a, T: 'static, D: HasData + ?Sized = HasSelf<T>> {
210     store: StoreContextMut<'a, T>,
211     get_data: fn(&mut T) -> D::Data<'_>,
212 }
213 
214 impl<'a, T, D> Access<'a, T, D>
215 where
216     D: HasData + ?Sized,
217     T: 'static,
218 {
219     /// Creates a new [`Access`] from its component parts.
220     pub fn new(store: StoreContextMut<'a, T>, get_data: fn(&mut T) -> D::Data<'_>) -> Self {
221         Self { store, get_data }
222     }
223 
224     /// Get mutable access to the store data.
225     pub fn data_mut(&mut self) -> &mut T {
226         self.store.data_mut()
227     }
228 
229     /// Get mutable access to the store data.
230     pub fn get(&mut self) -> D::Data<'_> {
231         (self.get_data)(self.data_mut())
232     }
233 
234     /// Spawn a background task.
235     ///
236     /// See [`Accessor::spawn`] for details.
237     pub fn spawn(&mut self, task: impl AccessorTask<T, D>) -> JoinHandle
238     where
239         T: 'static,
240     {
241         let accessor = Accessor {
242             get_data: self.get_data,
243             token: StoreToken::new(self.store.as_context_mut()),
244         };
245         self.store
246             .as_context_mut()
247             .spawn_with_accessor(accessor, task)
248     }
249 
250     /// Returns the getter this accessor is using to project from `T` into
251     /// `D::Data`.
252     pub fn getter(&self) -> fn(&mut T) -> D::Data<'_> {
253         self.get_data
254     }
255 }
256 
257 impl<'a, T, D> AsContext for Access<'a, T, D>
258 where
259     D: HasData + ?Sized,
260     T: 'static,
261 {
262     type Data = T;
263 
264     fn as_context(&self) -> StoreContext<'_, T> {
265         self.store.as_context()
266     }
267 }
268 
269 impl<'a, T, D> AsContextMut for Access<'a, T, D>
270 where
271     D: HasData + ?Sized,
272     T: 'static,
273 {
274     fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
275         self.store.as_context_mut()
276     }
277 }
278 
279 /// Provides scoped mutable access to store data in the context of a concurrent
280 /// host task future.
281 ///
282 /// This allows multiple host task futures to execute concurrently and access
283 /// the store between (but not across) `await` points.
284 ///
285 /// # Rationale
286 ///
287 /// This structure is sort of like `&mut T` plus a projection from `&mut T` to
288 /// `D::Data<'_>`. The problem this is solving, however, is that it does not
289 /// literally store these values. The basic problem is that when a concurrent
290 /// host future is being polled it has access to `&mut T` (and the whole
291 /// `Store`) but when it's not being polled it does not have access to these
292 /// values. This reflects how the store is only ever polling one future at a
293 /// time so the store is effectively being passed between futures.
294 ///
295 /// Rust's `Future` trait, however, has no means of passing a `Store`
296 /// temporarily between futures. The [`Context`](std::task::Context) type does
297 /// not have the ability to attach arbitrary information to it at this time.
298 /// This type, [`Accessor`], is used to bridge this expressivity gap.
299 ///
300 /// The [`Accessor`] type here represents the ability to acquire, temporarily in
301 /// a synchronous manner, the current store. The [`Accessor::with`] function
302 /// yields an [`Access`] which can be used to access [`StoreContextMut`], `&mut
303 /// T`, or `D::Data<'_>`. Note though that [`Accessor::with`] intentionally does
304 /// not take an `async` closure as its argument, instead it's a synchronous
305 /// closure which must complete during on run of `Future::poll`. This reflects
306 /// how the store is temporarily made available while a host future is being
307 /// polled.
308 ///
309 /// # Implementation
310 ///
311 /// This type does not actually store `&mut T` nor `StoreContextMut<T>`, and
312 /// this type additionally doesn't even have a lifetime parameter. This is
313 /// instead a representation of proof of the ability to acquire these while a
314 /// future is being polled. Wasmtime will, when it polls a host future,
315 /// configure ambient state such that the `Accessor` that a future closes over
316 /// will work and be able to access the store.
317 ///
318 /// This has a number of implications for users such as:
319 ///
320 /// * It's intentional that `Accessor` cannot be cloned, it needs to stay within
321 ///   the lifetime of a single future.
322 /// * A future is expected to, however, close over an `Accessor` and keep it
323 ///   alive probably for the duration of the entire future.
324 /// * Different host futures will be given different `Accessor`s, and that's
325 ///   intentional.
326 /// * The `Accessor` type is `Send` and `Sync` irrespective of `T` which
327 ///   alleviates some otherwise required bounds to be written down.
328 ///
329 /// # Using `Accessor` in `Drop`
330 ///
331 /// The methods on `Accessor` are only expected to work in the context of
332 /// `Future::poll` and are not guaranteed to work in `Drop`. This is because a
333 /// host future can be dropped at any time throughout the system and Wasmtime
334 /// store context is not necessarily available at that time. It's recommended to
335 /// not use `Accessor` methods in anything connected to a `Drop` implementation
336 /// as they will panic and have unintended results. If you run into this though
337 /// feel free to file an issue on the Wasmtime repository.
338 pub struct Accessor<T: 'static, D = HasSelf<T>>
339 where
340     D: HasData + ?Sized,
341 {
342     token: StoreToken<T>,
343     get_data: fn(&mut T) -> D::Data<'_>,
344 }
345 
346 /// A helper trait to take any type of accessor-with-data in functions.
347 ///
348 /// This trait is similar to [`AsContextMut`] except that it's used when
349 /// working with an [`Accessor`] instead of a [`StoreContextMut`]. The
350 /// [`Accessor`] is the main type used in concurrent settings and is passed to
351 /// functions such as [`Func::call_concurrent`].
352 ///
353 /// This trait is implemented for [`Accessor`] and `&T` where `T` implements
354 /// this trait. This effectively means that regardless of the `D` in
355 /// `Accessor<T, D>` it can still be passed to a function which just needs a
356 /// store accessor.
357 ///
358 /// Acquiring an [`Accessor`] can be done through
359 /// [`StoreContextMut::run_concurrent`] for example or in a host function
360 /// through
361 /// [`Linker::func_wrap_concurrent`](crate::component::LinkerInstance::func_wrap_concurrent).
362 pub trait AsAccessor {
363     /// The `T` in `Store<T>` that this accessor refers to.
364     type Data: 'static;
365 
366     /// The `D` in `Accessor<T, D>`, or the projection out of
367     /// `Self::Data`.
368     type AccessorData: HasData + ?Sized;
369 
370     /// Returns the accessor that this is referring to.
371     fn as_accessor(&self) -> &Accessor<Self::Data, Self::AccessorData>;
372 }
373 
374 impl<T: AsAccessor + ?Sized> AsAccessor for &T {
375     type Data = T::Data;
376     type AccessorData = T::AccessorData;
377 
378     fn as_accessor(&self) -> &Accessor<Self::Data, Self::AccessorData> {
379         T::as_accessor(self)
380     }
381 }
382 
383 impl<T, D: HasData + ?Sized> AsAccessor for Accessor<T, D> {
384     type Data = T;
385     type AccessorData = D;
386 
387     fn as_accessor(&self) -> &Accessor<T, D> {
388         self
389     }
390 }
391 
392 // Note that it is intentional at this time that `Accessor` does not actually
393 // store `&mut T` or anything similar. This distinctly enables the `Accessor`
394 // structure to be both `Send` and `Sync` regardless of what `T` is (or `D` for
395 // that matter). This is used to ergonomically simplify bindings where the
396 // majority of the time `Accessor` is closed over in a future which then needs
397 // to be `Send` and `Sync`. To avoid needing to write `T: Send` everywhere (as
398 // you already have to write `T: 'static`...) it helps to avoid this.
399 //
400 // Note as well that `Accessor` doesn't actually store its data at all. Instead
401 // it's more of a "proof" of what can be accessed from TLS. API design around
402 // `Accessor` and functions like `Linker::func_wrap_concurrent` are
403 // intentionally made to ensure that `Accessor` is ideally only used in the
404 // context that TLS variables are actually set. For example host functions are
405 // given `&Accessor`, not `Accessor`, and this prevents them from persisting
406 // the value outside of a future. Within the future the TLS variables are all
407 // guaranteed to be set while the future is being polled.
408 //
409 // Finally though this is not an ironclad guarantee, but nor does it need to be.
410 // The TLS APIs are designed to panic or otherwise model usage where they're
411 // called recursively or similar. It's hoped that code cannot be constructed to
412 // actually hit this at runtime but this is not a safety requirement at this
413 // time.
414 const _: () = {
415     const fn assert<T: Send + Sync>() {}
416     assert::<Accessor<UnsafeCell<u32>>>();
417 };
418 
419 impl<T> Accessor<T> {
420     /// Creates a new `Accessor` backed by the specified functions.
421     ///
422     /// - `get`: used to retrieve the store
423     ///
424     /// - `get_data`: used to "project" from the store's associated data to
425     /// another type (e.g. a field of that data or a wrapper around it).
426     ///
427     /// - `spawn`: used to queue spawned background tasks to be run later
428     pub(crate) fn new(token: StoreToken<T>) -> Self {
429         Self {
430             token,
431             get_data: |x| x,
432         }
433     }
434 }
435 
436 impl<T, D> Accessor<T, D>
437 where
438     D: HasData + ?Sized,
439 {
440     /// Run the specified closure, passing it mutable access to the store.
441     ///
442     /// This function is one of the main building blocks of the [`Accessor`]
443     /// type. This yields synchronous, blocking, access to the store via an
444     /// [`Access`]. The [`Access`] implements [`AsContextMut`] in addition to
445     /// providing the ability to access `D` via [`Access::get`]. Note that the
446     /// `fun` here is given only temporary access to the store and `T`/`D`
447     /// meaning that the return value `R` here is not allowed to capture borrows
448     /// into the two. If access is needed to data within `T` or `D` outside of
449     /// this closure then it must be `clone`d out, for example.
450     ///
451     /// # Panics
452     ///
453     /// This function will panic if it is call recursively with any other
454     /// accessor already in scope. For example if `with` is called within `fun`,
455     /// then this function will panic. It is up to the embedder to ensure that
456     /// this does not happen.
457     pub fn with<R>(&self, fun: impl FnOnce(Access<'_, T, D>) -> R) -> R {
458         tls::get(|vmstore| {
459             fun(Access {
460                 store: self.token.as_context_mut(vmstore),
461                 get_data: self.get_data,
462             })
463         })
464     }
465 
466     /// Returns the getter this accessor is using to project from `T` into
467     /// `D::Data`.
468     pub fn getter(&self) -> fn(&mut T) -> D::Data<'_> {
469         self.get_data
470     }
471 
472     /// Changes this accessor to access `D2` instead of the current type
473     /// parameter `D`.
474     ///
475     /// This changes the underlying data access from `T` to `D2::Data<'_>`.
476     ///
477     /// # Panics
478     ///
479     /// When using this API the returned value is disconnected from `&self` and
480     /// the lifetime binding the `self` argument. An `Accessor` only works
481     /// within the context of the closure or async closure that it was
482     /// originally given to, however. This means that due to the fact that the
483     /// returned value has no lifetime connection it's possible to use the
484     /// accessor outside of `&self`, the original accessor, and panic.
485     ///
486     /// The returned value should only be used within the scope of the original
487     /// `Accessor` that `self` refers to.
488     pub fn with_getter<D2: HasData>(
489         &self,
490         get_data: fn(&mut T) -> D2::Data<'_>,
491     ) -> Accessor<T, D2> {
492         Accessor {
493             token: self.token,
494             get_data,
495         }
496     }
497 
498     /// Spawn a background task which will receive an `&Accessor<T, D>` and
499     /// run concurrently with any other tasks in progress for the current
500     /// store.
501     ///
502     /// This is particularly useful for host functions which return a `stream`
503     /// or `future` such that the code to write to the write end of that
504     /// `stream` or `future` must run after the function returns.
505     ///
506     /// The returned [`JoinHandle`] may be used to cancel the task.
507     ///
508     /// # Panics
509     ///
510     /// Panics if called within a closure provided to the [`Accessor::with`]
511     /// function. This can only be called outside an active invocation of
512     /// [`Accessor::with`].
513     pub fn spawn(&self, task: impl AccessorTask<T, D>) -> JoinHandle
514     where
515         T: 'static,
516     {
517         let accessor = self.clone_for_spawn();
518         self.with(|mut access| access.as_context_mut().spawn_with_accessor(accessor, task))
519     }
520 
521     fn clone_for_spawn(&self) -> Self {
522         Self {
523             token: self.token,
524             get_data: self.get_data,
525         }
526     }
527 }
528 
529 /// Represents a task which may be provided to `Accessor::spawn`,
530 /// `Accessor::forward`, or `StorecContextMut::spawn`.
531 // TODO: Replace this with `std::ops::AsyncFnOnce` when that becomes a viable
532 // option.
533 //
534 // As of this writing, it's not possible to specify e.g. `Send` and `Sync`
535 // bounds on the `Future` type returned by an `AsyncFnOnce`.  Also, using `F:
536 // Future<Output = Result<()>> + Send + Sync, FN: FnOnce(&Accessor<T>) -> F +
537 // Send + Sync + 'static` fails with a type mismatch error when we try to pass
538 // it an async closure (e.g. `async move |_| { ... }`).  So this seems to be the
539 // best we can do for the time being.
540 pub trait AccessorTask<T, D = HasSelf<T>>: Send + 'static
541 where
542     D: HasData + ?Sized,
543 {
544     /// Run the task.
545     fn run(self, accessor: &Accessor<T, D>) -> impl Future<Output = Result<()>> + Send;
546 }
547 
548 /// Represents parameter and result metadata for the caller side of a
549 /// guest->guest call orchestrated by a fused adapter.
550 enum CallerInfo {
551     /// Metadata for a call to an async-lowered import
552     Async {
553         params: Vec<ValRaw>,
554         has_result: bool,
555     },
556     /// Metadata for a call to an sync-lowered import
557     Sync {
558         params: Vec<ValRaw>,
559         result_count: u32,
560     },
561 }
562 
563 /// Indicates how a guest task is waiting on a waitable set.
564 enum WaitMode {
565     /// The guest task is waiting using `task.wait`
566     Fiber(StoreFiber<'static>),
567     /// The guest task is waiting via a callback declared as part of an
568     /// async-lifted export.
569     Callback(Instance),
570 }
571 
572 /// Represents the reason a fiber is suspending itself.
573 #[derive(Debug)]
574 enum SuspendReason {
575     /// The fiber is waiting for an event to be delivered to the specified
576     /// waitable set or task.
577     Waiting {
578         set: TableId<WaitableSet>,
579         thread: QualifiedThreadId,
580         skip_may_block_check: bool,
581     },
582     /// The fiber has finished handling its most recent work item and is waiting
583     /// for another (or to be dropped if it is no longer needed).
584     NeedWork,
585     /// The fiber is yielding and should be resumed once other tasks have had a
586     /// chance to run.
587     Yielding {
588         thread: QualifiedThreadId,
589         skip_may_block_check: bool,
590     },
591     /// The fiber was explicitly suspended with a call to `thread.suspend` or `thread.switch-to`.
592     ExplicitlySuspending {
593         thread: QualifiedThreadId,
594         skip_may_block_check: bool,
595     },
596 }
597 
598 /// Represents a pending call into guest code for a given guest task.
599 enum GuestCallKind {
600     /// Indicates there's an event to deliver to the task, possibly related to a
601     /// waitable set the task has been waiting on or polling.
602     DeliverEvent {
603         /// The instance to which the task belongs.
604         instance: Instance,
605         /// The waitable set the event belongs to, if any.
606         ///
607         /// If this is `None` the event will be waiting in the
608         /// `GuestTask::event` field for the task.
609         set: Option<TableId<WaitableSet>>,
610     },
611     /// Indicates that a new guest task call is pending and may be executed
612     /// using the specified closure.
613     ///
614     /// If the closure returns `Ok(Some(call))`, the `call` should be run
615     /// immediately using `handle_guest_call`.
616     StartImplicit(Box<dyn FnOnce(&mut dyn VMStore) -> Result<Option<GuestCall>> + Send + Sync>),
617     StartExplicit(Box<dyn FnOnce(&mut dyn VMStore) -> Result<()> + Send + Sync>),
618 }
619 
620 impl fmt::Debug for GuestCallKind {
621     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
622         match self {
623             Self::DeliverEvent { instance, set } => f
624                 .debug_struct("DeliverEvent")
625                 .field("instance", instance)
626                 .field("set", set)
627                 .finish(),
628             Self::StartImplicit(_) => f.debug_tuple("StartImplicit").finish(),
629             Self::StartExplicit(_) => f.debug_tuple("StartExplicit").finish(),
630         }
631     }
632 }
633 
634 /// The target of a suspension intrinsic.
635 #[derive(Copy, Clone, Debug)]
636 pub enum SuspensionTarget {
637     SomeSuspended(u32),
638     Some(u32),
639     None,
640 }
641 
642 impl SuspensionTarget {
643     fn is_none(&self) -> bool {
644         matches!(self, SuspensionTarget::None)
645     }
646     fn is_some(&self) -> bool {
647         !self.is_none()
648     }
649 }
650 
651 /// Represents a pending call into guest code for a given guest thread.
652 #[derive(Debug)]
653 struct GuestCall {
654     thread: QualifiedThreadId,
655     kind: GuestCallKind,
656 }
657 
658 impl GuestCall {
659     /// Returns whether or not the call is ready to run.
660     ///
661     /// A call will not be ready to run if either:
662     ///
663     /// - the (sub-)component instance to be called has already been entered and
664     /// cannot be reentered until an in-progress call completes
665     ///
666     /// - the call is for a not-yet started task and the (sub-)component
667     /// instance to be called has backpressure enabled
668     fn is_ready(&self, store: &mut StoreOpaque) -> Result<bool> {
669         let instance = store
670             .concurrent_state_mut()
671             .get_mut(self.thread.task)?
672             .instance;
673         let state = store.instance_state(instance).concurrent_state();
674 
675         let ready = match &self.kind {
676             GuestCallKind::DeliverEvent { .. } => !state.do_not_enter,
677             GuestCallKind::StartImplicit(_) => !(state.do_not_enter || state.backpressure > 0),
678             GuestCallKind::StartExplicit(_) => true,
679         };
680         log::trace!(
681             "call {self:?} ready? {ready} (do_not_enter: {}; backpressure: {})",
682             state.do_not_enter,
683             state.backpressure
684         );
685         Ok(ready)
686     }
687 }
688 
689 /// Job to be run on a worker fiber.
690 enum WorkerItem {
691     GuestCall(GuestCall),
692     Function(AlwaysMut<Box<dyn FnOnce(&mut dyn VMStore) -> Result<()> + Send>>),
693 }
694 
695 /// Represents a pending work item to be handled by the event loop for a given
696 /// component instance.
697 enum WorkItem {
698     /// A host task to be pushed to `ConcurrentState::futures`.
699     PushFuture(AlwaysMut<HostTaskFuture>),
700     /// A fiber to resume.
701     ResumeFiber(StoreFiber<'static>),
702     /// A thread to resume.
703     ResumeThread(RuntimeComponentInstanceIndex, QualifiedThreadId),
704     /// A pending call into guest code for a given guest task.
705     GuestCall(RuntimeComponentInstanceIndex, GuestCall),
706     /// A job to run on a worker fiber.
707     WorkerFunction(AlwaysMut<Box<dyn FnOnce(&mut dyn VMStore) -> Result<()> + Send>>),
708 }
709 
710 impl fmt::Debug for WorkItem {
711     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
712         match self {
713             Self::PushFuture(_) => f.debug_tuple("PushFuture").finish(),
714             Self::ResumeFiber(_) => f.debug_tuple("ResumeFiber").finish(),
715             Self::ResumeThread(instance, thread) => f
716                 .debug_tuple("ResumeThread")
717                 .field(instance)
718                 .field(thread)
719                 .finish(),
720             Self::GuestCall(instance, call) => f
721                 .debug_tuple("GuestCall")
722                 .field(instance)
723                 .field(call)
724                 .finish(),
725             Self::WorkerFunction(_) => f.debug_tuple("WorkerFunction").finish(),
726         }
727     }
728 }
729 
730 /// Whether a suspension intrinsic was cancelled or completed
731 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
732 pub(crate) enum WaitResult {
733     Cancelled,
734     Completed,
735 }
736 
737 /// Poll the specified future until it completes on behalf of a guest->host call
738 /// using a sync-lowered import.
739 ///
740 /// This is similar to `Instance::first_poll` except it's for sync-lowered
741 /// imports, meaning we don't need to handle cancellation and we can block the
742 /// caller until the task completes, at which point the caller can handle
743 /// lowering the result to the guest's stack and linear memory.
744 pub(crate) fn poll_and_block<R: Send + Sync + 'static>(
745     store: &mut dyn VMStore,
746     future: impl Future<Output = Result<R>> + Send + 'static,
747 ) -> Result<R> {
748     let state = store.concurrent_state_mut();
749     let task = state.unwrap_current_host_thread();
750 
751     // Wrap the future in a closure which will take care of stashing the result
752     // in `GuestTask::result` and resuming this fiber when the host task
753     // completes.
754     let mut future = Box::pin(async move {
755         let result = future.await?;
756         tls::get(move |store| {
757             let state = store.concurrent_state_mut();
758             let host_state = &mut state.get_mut(task)?.state;
759             assert!(matches!(host_state, HostTaskState::CalleeStarted));
760             *host_state = HostTaskState::CalleeFinished(Box::new(result));
761 
762             Waitable::Host(task).set_event(
763                 state,
764                 Some(Event::Subtask {
765                     status: Status::Returned,
766                 }),
767             )?;
768 
769             Ok(())
770         })
771     }) as HostTaskFuture;
772 
773     // Finally, poll the future.  We can use a dummy `Waker` here because we'll
774     // add the future to `ConcurrentState::futures` and poll it automatically
775     // from the event loop if it doesn't complete immediately here.
776     let poll = tls::set(store, || {
777         future
778             .as_mut()
779             .poll(&mut Context::from_waker(&Waker::noop()))
780     });
781 
782     match poll {
783         // It completed immediately; check the result and delete the task.
784         Poll::Ready(result) => result?,
785 
786         // It did not complete immediately; add it to
787         // `ConcurrentState::futures` so it will be polled via the event loop;
788         // then use `GuestTask::sync_call_set` to wait for the task to
789         // complete, suspending the current fiber until it does so.
790         Poll::Pending => {
791             let state = store.concurrent_state_mut();
792             state.push_future(future);
793 
794             let caller = state.get_mut(task)?.caller;
795             let set = state.get_mut(caller.task)?.sync_call_set;
796             Waitable::Host(task).join(state, Some(set))?;
797 
798             store.suspend(SuspendReason::Waiting {
799                 set,
800                 thread: caller,
801                 skip_may_block_check: false,
802             })?;
803 
804             // Remove the `task` from the `sync_call_set` to ensure that when
805             // this function returns and the task is deleted that there are no
806             // more lingering references to this host task.
807             Waitable::Host(task).join(store.concurrent_state_mut(), None)?;
808         }
809     }
810 
811     // Retrieve and return the result.
812     let host_state = &mut store.concurrent_state_mut().get_mut(task)?.state;
813     match mem::replace(host_state, HostTaskState::CalleeDone) {
814         HostTaskState::CalleeFinished(result) => Ok(*result.downcast().unwrap()),
815         _ => panic!("unexpected host task state after completion"),
816     }
817 }
818 
819 /// Execute the specified guest call.
820 fn handle_guest_call(store: &mut dyn VMStore, call: GuestCall) -> Result<()> {
821     let mut next = Some(call);
822     while let Some(call) = next.take() {
823         match call.kind {
824             GuestCallKind::DeliverEvent { instance, set } => {
825                 let (event, waitable) = instance
826                     .get_event(store, call.thread.task, set, true)?
827                     .unwrap();
828                 let state = store.concurrent_state_mut();
829                 let task = state.get_mut(call.thread.task)?;
830                 let runtime_instance = task.instance;
831                 let handle = waitable.map(|(_, v)| v).unwrap_or(0);
832 
833                 log::trace!(
834                     "use callback to deliver event {event:?} to {:?} for {waitable:?}",
835                     call.thread,
836                 );
837 
838                 let old_thread = store.set_thread(call.thread);
839                 log::trace!(
840                     "GuestCallKind::DeliverEvent: replaced {old_thread:?} with {:?} as current thread",
841                     call.thread
842                 );
843 
844                 store.enter_instance(runtime_instance);
845 
846                 let callback = store
847                     .concurrent_state_mut()
848                     .get_mut(call.thread.task)?
849                     .callback
850                     .take()
851                     .unwrap();
852 
853                 let code = callback(store, event, handle)?;
854 
855                 store
856                     .concurrent_state_mut()
857                     .get_mut(call.thread.task)?
858                     .callback = Some(callback);
859 
860                 store.exit_instance(runtime_instance)?;
861 
862                 store.set_thread(old_thread);
863 
864                 next = instance.handle_callback_code(
865                     store,
866                     call.thread,
867                     runtime_instance.index,
868                     code,
869                 )?;
870 
871                 log::trace!(
872                     "GuestCallKind::DeliverEvent: restored {old_thread:?} as current thread"
873                 );
874             }
875             GuestCallKind::StartImplicit(fun) => {
876                 next = fun(store)?;
877             }
878             GuestCallKind::StartExplicit(fun) => {
879                 fun(store)?;
880             }
881         }
882     }
883 
884     Ok(())
885 }
886 
887 impl<T> Store<T> {
888     /// Convenience wrapper for [`StoreContextMut::run_concurrent`].
889     pub async fn run_concurrent<R>(&mut self, fun: impl AsyncFnOnce(&Accessor<T>) -> R) -> Result<R>
890     where
891         T: Send + 'static,
892     {
893         ensure!(
894             self.as_context().0.concurrency_support(),
895             "cannot use `run_concurrent` when Config::concurrency_support disabled",
896         );
897         self.as_context_mut().run_concurrent(fun).await
898     }
899 
900     #[doc(hidden)]
901     pub fn assert_concurrent_state_empty(&mut self) {
902         self.as_context_mut().assert_concurrent_state_empty();
903     }
904 
905     #[doc(hidden)]
906     pub fn concurrent_state_table_size(&mut self) -> usize {
907         self.as_context_mut().concurrent_state_table_size()
908     }
909 
910     /// Convenience wrapper for [`StoreContextMut::spawn`].
911     pub fn spawn(&mut self, task: impl AccessorTask<T, HasSelf<T>>) -> JoinHandle
912     where
913         T: 'static,
914     {
915         self.as_context_mut().spawn(task)
916     }
917 }
918 
919 impl<T> StoreContextMut<'_, T> {
920     /// Assert that all the relevant tables and queues in the concurrent state
921     /// for this store are empty.
922     ///
923     /// This is for sanity checking in integration tests
924     /// (e.g. `component-async-tests`) that the relevant state has been cleared
925     /// after each test concludes.  This should help us catch leaks, e.g. guest
926     /// tasks which haven't been deleted despite having completed and having
927     /// been dropped by their supertasks.
928     ///
929     /// Only intended for use in Wasmtime's own testing.
930     #[doc(hidden)]
931     pub fn assert_concurrent_state_empty(self) {
932         let store = self.0;
933         store
934             .store_data_mut()
935             .components
936             .assert_instance_states_empty();
937         let state = store.concurrent_state_mut();
938         assert!(
939             state.table.get_mut().is_empty(),
940             "non-empty table: {:?}",
941             state.table.get_mut()
942         );
943         assert!(state.high_priority.is_empty());
944         assert!(state.low_priority.is_empty());
945         assert!(state.current_thread.is_none());
946         assert!(state.futures.get_mut().as_ref().unwrap().is_empty());
947         assert!(state.global_error_context_ref_counts.is_empty());
948     }
949 
950     /// Helper function to perform tests over the size of the concurrent state
951     /// table which can be useful for detecting leaks.
952     ///
953     /// Only intended for use in Wasmtime's own testing.
954     #[doc(hidden)]
955     pub fn concurrent_state_table_size(&mut self) -> usize {
956         self.0
957             .concurrent_state_mut()
958             .table
959             .get_mut()
960             .iter_mut()
961             .count()
962     }
963 
964     /// Spawn a background task to run as part of this instance's event loop.
965     ///
966     /// The task will receive an `&Accessor<U>` and run concurrently with
967     /// any other tasks in progress for the instance.
968     ///
969     /// Note that the task will only make progress if and when the event loop
970     /// for this instance is run.
971     ///
972     /// The returned [`JoinHandle`] may be used to cancel the task.
973     pub fn spawn(mut self, task: impl AccessorTask<T>) -> JoinHandle
974     where
975         T: 'static,
976     {
977         let accessor = Accessor::new(StoreToken::new(self.as_context_mut()));
978         self.spawn_with_accessor(accessor, task)
979     }
980 
981     /// Internal implementation of `spawn` functions where a `store` is
982     /// available along with an `Accessor`.
983     fn spawn_with_accessor<D>(
984         self,
985         accessor: Accessor<T, D>,
986         task: impl AccessorTask<T, D>,
987     ) -> JoinHandle
988     where
989         T: 'static,
990         D: HasData + ?Sized,
991     {
992         // Create an "abortable future" here where internally the future will
993         // hook calls to poll and possibly spawn more background tasks on each
994         // iteration.
995         let (handle, future) = JoinHandle::run(async move { task.run(&accessor).await });
996         self.0
997             .concurrent_state_mut()
998             .push_future(Box::pin(async move { future.await.unwrap_or(Ok(())) }));
999         handle
1000     }
1001 
1002     /// Run the specified closure `fun` to completion as part of this store's
1003     /// event loop.
1004     ///
1005     /// This will run `fun` as part of this store's event loop until it
1006     /// yields a result.  `fun` is provided an [`Accessor`], which provides
1007     /// controlled access to the store and its data.
1008     ///
1009     /// This function can be used to invoke [`Func::call_concurrent`] for
1010     /// example within the async closure provided here.
1011     ///
1012     /// This function will unconditionally return an error if
1013     /// [`Config::concurrency_support`] is disabled.
1014     ///
1015     /// [`Config::concurrency_support`]: crate::Config::concurrency_support
1016     ///
1017     /// # Store-blocking behavior
1018     ///
1019     /// At this time there are certain situations in which the `Future` returned
1020     /// by the `AsyncFnOnce` passed to this function will not be polled for an
1021     /// extended period of time, despite one or more `Waker::wake` events having
1022     /// occurred for the task to which it belongs.  This can manifest as the
1023     /// `Future` seeming to be "blocked" or "locked up", but is actually due to
1024     /// the `Store` being held by e.g. a blocking host function, preventing the
1025     /// `Future` from being polled. A canonical example of this is when the
1026     /// `fun` provided to this function attempts to set a timeout for an
1027     /// invocation of a wasm function. In this situation the async closure is
1028     /// waiting both on (a) the wasm computation to finish, and (b) the timeout
1029     /// to elapse. At this time this setup will not always work and the timeout
1030     /// may not reliably fire.
1031     ///
1032     /// This function will not block the current thread and as such is always
1033     /// suitable to run in an `async` context, but the current implementation of
1034     /// Wasmtime can lead to situations where a certain wasm computation is
1035     /// required to make progress the closure to make progress. This is an
1036     /// artifact of Wasmtime's historical implementation of `async` functions
1037     /// and is the topic of [#11869] and [#11870]. In the timeout example from
1038     /// above it means that Wasmtime can get "wedged" for a bit where (a) must
1039     /// progress for a readiness notification of (b) to get delivered.
1040     ///
1041     /// This effectively means that it's not possible to reliably perform a
1042     /// "select" operation within the `fun` closure, which timeouts for example
1043     /// are based on. Fixing this requires some relatively major refactoring
1044     /// work within Wasmtime itself. This is a known pitfall otherwise and one
1045     /// that is intended to be fixed one day. In the meantime it's recommended
1046     /// to apply timeouts or such to the entire `run_concurrent` call itself
1047     /// rather than internally.
1048     ///
1049     /// [#11869]: https://github.com/bytecodealliance/wasmtime/issues/11869
1050     /// [#11870]: https://github.com/bytecodealliance/wasmtime/issues/11870
1051     ///
1052     /// # Example
1053     ///
1054     /// ```
1055     /// # use {
1056     /// #   wasmtime::{
1057     /// #     error::{Result},
1058     /// #     component::{ Component, Linker, Resource, ResourceTable},
1059     /// #     Config, Engine, Store
1060     /// #   },
1061     /// # };
1062     /// #
1063     /// # struct MyResource(u32);
1064     /// # struct Ctx { table: ResourceTable }
1065     /// #
1066     /// # async fn foo() -> Result<()> {
1067     /// # let mut config = Config::new();
1068     /// # let engine = Engine::new(&config)?;
1069     /// # let mut store = Store::new(&engine, Ctx { table: ResourceTable::new() });
1070     /// # let mut linker = Linker::new(&engine);
1071     /// # let component = Component::new(&engine, "")?;
1072     /// # let instance = linker.instantiate_async(&mut store, &component).await?;
1073     /// # let foo = instance.get_typed_func::<(Resource<MyResource>,), (Resource<MyResource>,)>(&mut store, "foo")?;
1074     /// # let bar = instance.get_typed_func::<(u32,), ()>(&mut store, "bar")?;
1075     /// store.run_concurrent(async |accessor| -> wasmtime::Result<_> {
1076     ///    let resource = accessor.with(|mut access| access.get().table.push(MyResource(42)))?;
1077     ///    let (another_resource,) = foo.call_concurrent(accessor, (resource,)).await?;
1078     ///    let value = accessor.with(|mut access| access.get().table.delete(another_resource))?;
1079     ///    bar.call_concurrent(accessor, (value.0,)).await?;
1080     ///    Ok(())
1081     /// }).await??;
1082     /// # Ok(())
1083     /// # }
1084     /// ```
1085     pub async fn run_concurrent<R>(self, fun: impl AsyncFnOnce(&Accessor<T>) -> R) -> Result<R>
1086     where
1087         T: Send + 'static,
1088     {
1089         ensure!(
1090             self.0.concurrency_support(),
1091             "cannot use `run_concurrent` when Config::concurrency_support disabled",
1092         );
1093         self.do_run_concurrent(fun, false).await
1094     }
1095 
1096     pub(super) async fn run_concurrent_trap_on_idle<R>(
1097         self,
1098         fun: impl AsyncFnOnce(&Accessor<T>) -> R,
1099     ) -> Result<R>
1100     where
1101         T: Send + 'static,
1102     {
1103         self.do_run_concurrent(fun, true).await
1104     }
1105 
1106     async fn do_run_concurrent<R>(
1107         mut self,
1108         fun: impl AsyncFnOnce(&Accessor<T>) -> R,
1109         trap_on_idle: bool,
1110     ) -> Result<R>
1111     where
1112         T: Send + 'static,
1113     {
1114         debug_assert!(self.0.concurrency_support());
1115         check_recursive_run();
1116         let token = StoreToken::new(self.as_context_mut());
1117 
1118         struct Dropper<'a, T: 'static, V> {
1119             store: StoreContextMut<'a, T>,
1120             value: ManuallyDrop<V>,
1121         }
1122 
1123         impl<'a, T, V> Drop for Dropper<'a, T, V> {
1124             fn drop(&mut self) {
1125                 tls::set(self.store.0, || {
1126                     // SAFETY: Here we drop the value without moving it for the
1127                     // first and only time -- per the contract for `Drop::drop`,
1128                     // this code won't run again, and the `value` field will no
1129                     // longer be accessible.
1130                     unsafe { ManuallyDrop::drop(&mut self.value) }
1131                 });
1132             }
1133         }
1134 
1135         let accessor = &Accessor::new(token);
1136         let dropper = &mut Dropper {
1137             store: self,
1138             value: ManuallyDrop::new(fun(accessor)),
1139         };
1140         // SAFETY: We never move `dropper` nor its `value` field.
1141         let future = unsafe { Pin::new_unchecked(dropper.value.deref_mut()) };
1142 
1143         dropper
1144             .store
1145             .as_context_mut()
1146             .poll_until(future, trap_on_idle)
1147             .await
1148     }
1149 
1150     /// Run this store's event loop.
1151     ///
1152     /// The returned future will resolve when the specified future completes or,
1153     /// if `trap_on_idle` is true, when the event loop can't make further
1154     /// progress.
1155     async fn poll_until<R>(
1156         mut self,
1157         mut future: Pin<&mut impl Future<Output = R>>,
1158         trap_on_idle: bool,
1159     ) -> Result<R>
1160     where
1161         T: Send + 'static,
1162     {
1163         struct Reset<'a, T: 'static> {
1164             store: StoreContextMut<'a, T>,
1165             futures: Option<FuturesUnordered<HostTaskFuture>>,
1166         }
1167 
1168         impl<'a, T> Drop for Reset<'a, T> {
1169             fn drop(&mut self) {
1170                 if let Some(futures) = self.futures.take() {
1171                     *self.store.0.concurrent_state_mut().futures.get_mut() = Some(futures);
1172                 }
1173             }
1174         }
1175 
1176         loop {
1177             // Take `ConcurrentState::futures` out of the store so we can poll
1178             // it while also safely giving any of the futures inside access to
1179             // `self`.
1180             let futures = self.0.concurrent_state_mut().futures.get_mut().take();
1181             let mut reset = Reset {
1182                 store: self.as_context_mut(),
1183                 futures,
1184             };
1185             let mut next = pin!(reset.futures.as_mut().unwrap().next());
1186 
1187             enum PollResult<R> {
1188                 Complete(R),
1189                 ProcessWork(Vec<WorkItem>),
1190             }
1191             let result = future::poll_fn(|cx| {
1192                 // First, poll the future we were passed as an argument and
1193                 // return immediately if it's ready.
1194                 if let Poll::Ready(value) = tls::set(reset.store.0, || future.as_mut().poll(cx)) {
1195                     return Poll::Ready(Ok(PollResult::Complete(value)));
1196                 }
1197 
1198                 // Next, poll `ConcurrentState::futures` (which includes any
1199                 // pending host tasks and/or background tasks), returning
1200                 // immediately if one of them fails.
1201                 let next = match tls::set(reset.store.0, || next.as_mut().poll(cx)) {
1202                     Poll::Ready(Some(output)) => {
1203                         match output {
1204                             Err(e) => return Poll::Ready(Err(e)),
1205                             Ok(()) => {}
1206                         }
1207                         Poll::Ready(true)
1208                     }
1209                     Poll::Ready(None) => Poll::Ready(false),
1210                     Poll::Pending => Poll::Pending,
1211                 };
1212 
1213                 // Next, collect the next batch of work items to process, if any.
1214                 // This will be either all of the high-priority work items, or if
1215                 // there are none, a single low-priority work item.
1216                 let state = reset.store.0.concurrent_state_mut();
1217                 let ready = state.collect_work_items_to_run();
1218                 if !ready.is_empty() {
1219                     return Poll::Ready(Ok(PollResult::ProcessWork(ready)));
1220                 }
1221 
1222                 // Finally, if we have nothing else to do right now, determine what to do
1223                 // based on whether there are any pending futures in
1224                 // `ConcurrentState::futures`.
1225                 return match next {
1226                     Poll::Ready(true) => {
1227                         // In this case, one of the futures in
1228                         // `ConcurrentState::futures` completed
1229                         // successfully, so we return now and continue
1230                         // the outer loop in case there is another one
1231                         // ready to complete.
1232                         Poll::Ready(Ok(PollResult::ProcessWork(Vec::new())))
1233                     }
1234                     Poll::Ready(false) => {
1235                         // Poll the future we were passed one last time
1236                         // in case one of `ConcurrentState::futures` had
1237                         // the side effect of unblocking it.
1238                         if let Poll::Ready(value) =
1239                             tls::set(reset.store.0, || future.as_mut().poll(cx))
1240                         {
1241                             Poll::Ready(Ok(PollResult::Complete(value)))
1242                         } else {
1243                             // In this case, there are no more pending
1244                             // futures in `ConcurrentState::futures`,
1245                             // there are no remaining work items, _and_
1246                             // the future we were passed as an argument
1247                             // still hasn't completed.
1248                             if trap_on_idle {
1249                                 // `trap_on_idle` is true, so we exit
1250                                 // immediately.
1251                                 Poll::Ready(Err(format_err!(crate::Trap::AsyncDeadlock)))
1252                             } else {
1253                                 // `trap_on_idle` is false, so we assume
1254                                 // that future will wake up and give us
1255                                 // more work to do when it's ready to.
1256                                 Poll::Pending
1257                             }
1258                         }
1259                     }
1260                     // There is at least one pending future in
1261                     // `ConcurrentState::futures` and we have nothing
1262                     // else to do but wait for now, so we return
1263                     // `Pending`.
1264                     Poll::Pending => Poll::Pending,
1265                 };
1266             })
1267             .await;
1268 
1269             // Put the `ConcurrentState::futures` back into the store before we
1270             // return or handle any work items since one or more of those items
1271             // might append more futures.
1272             drop(reset);
1273 
1274             match result? {
1275                 // The future we were passed as an argument completed, so we
1276                 // return the result.
1277                 PollResult::Complete(value) => break Ok(value),
1278                 // The future we were passed has not yet completed, so handle
1279                 // any work items and then loop again.
1280                 PollResult::ProcessWork(ready) => {
1281                     struct Dispose<'a, T: 'static, I: Iterator<Item = WorkItem>> {
1282                         store: StoreContextMut<'a, T>,
1283                         ready: I,
1284                     }
1285 
1286                     impl<'a, T, I: Iterator<Item = WorkItem>> Drop for Dispose<'a, T, I> {
1287                         fn drop(&mut self) {
1288                             while let Some(item) = self.ready.next() {
1289                                 match item {
1290                                     WorkItem::ResumeFiber(mut fiber) => fiber.dispose(self.store.0),
1291                                     WorkItem::PushFuture(future) => {
1292                                         tls::set(self.store.0, move || drop(future))
1293                                     }
1294                                     _ => {}
1295                                 }
1296                             }
1297                         }
1298                     }
1299 
1300                     let mut dispose = Dispose {
1301                         store: self.as_context_mut(),
1302                         ready: ready.into_iter(),
1303                     };
1304 
1305                     while let Some(item) = dispose.ready.next() {
1306                         dispose
1307                             .store
1308                             .as_context_mut()
1309                             .handle_work_item(item)
1310                             .await?;
1311                     }
1312                 }
1313             }
1314         }
1315     }
1316 
1317     /// Handle the specified work item, possibly resuming a fiber if applicable.
1318     async fn handle_work_item(self, item: WorkItem) -> Result<()>
1319     where
1320         T: Send,
1321     {
1322         log::trace!("handle work item {item:?}");
1323         match item {
1324             WorkItem::PushFuture(future) => {
1325                 self.0
1326                     .concurrent_state_mut()
1327                     .futures
1328                     .get_mut()
1329                     .as_mut()
1330                     .unwrap()
1331                     .push(future.into_inner());
1332             }
1333             WorkItem::ResumeFiber(fiber) => {
1334                 self.0.resume_fiber(fiber).await?;
1335             }
1336             WorkItem::ResumeThread(_, thread) => {
1337                 if let GuestThreadState::Ready(fiber) = mem::replace(
1338                     &mut self.0.concurrent_state_mut().get_mut(thread.thread)?.state,
1339                     GuestThreadState::Running,
1340                 ) {
1341                     self.0.resume_fiber(fiber).await?;
1342                 } else {
1343                     bail!("cannot resume non-pending thread {thread:?}");
1344                 }
1345             }
1346             WorkItem::GuestCall(_, call) => {
1347                 if call.is_ready(self.0)? {
1348                     self.run_on_worker(WorkerItem::GuestCall(call)).await?;
1349                 } else {
1350                     let state = self.0.concurrent_state_mut();
1351                     let task = state.get_mut(call.thread.task)?;
1352                     if !task.starting_sent {
1353                         task.starting_sent = true;
1354                         if let GuestCallKind::StartImplicit(_) = &call.kind {
1355                             Waitable::Guest(call.thread.task).set_event(
1356                                 state,
1357                                 Some(Event::Subtask {
1358                                     status: Status::Starting,
1359                                 }),
1360                             )?;
1361                         }
1362                     }
1363 
1364                     let instance = state.get_mut(call.thread.task)?.instance;
1365                     self.0
1366                         .instance_state(instance)
1367                         .concurrent_state()
1368                         .pending
1369                         .insert(call.thread, call.kind);
1370                 }
1371             }
1372             WorkItem::WorkerFunction(fun) => {
1373                 self.run_on_worker(WorkerItem::Function(fun)).await?;
1374             }
1375         }
1376 
1377         Ok(())
1378     }
1379 
1380     /// Execute the specified guest call on a worker fiber.
1381     async fn run_on_worker(self, item: WorkerItem) -> Result<()>
1382     where
1383         T: Send,
1384     {
1385         let worker = if let Some(fiber) = self.0.concurrent_state_mut().worker.take() {
1386             fiber
1387         } else {
1388             fiber::make_fiber(self.0, move |store| {
1389                 loop {
1390                     match store.concurrent_state_mut().worker_item.take().unwrap() {
1391                         WorkerItem::GuestCall(call) => handle_guest_call(store, call)?,
1392                         WorkerItem::Function(fun) => fun.into_inner()(store)?,
1393                     }
1394 
1395                     store.suspend(SuspendReason::NeedWork)?;
1396                 }
1397             })?
1398         };
1399 
1400         let worker_item = &mut self.0.concurrent_state_mut().worker_item;
1401         assert!(worker_item.is_none());
1402         *worker_item = Some(item);
1403 
1404         self.0.resume_fiber(worker).await
1405     }
1406 
1407     /// Wrap the specified host function in a future which will call it, passing
1408     /// it an `&Accessor<T>`.
1409     ///
1410     /// See the `Accessor` documentation for details.
1411     pub(crate) fn wrap_call<F, R>(self, closure: F) -> impl Future<Output = Result<R>> + 'static
1412     where
1413         T: 'static,
1414         F: FnOnce(&Accessor<T>) -> Pin<Box<dyn Future<Output = Result<R>> + Send + '_>>
1415             + Send
1416             + Sync
1417             + 'static,
1418         R: Send + Sync + 'static,
1419     {
1420         let token = StoreToken::new(self);
1421         async move {
1422             let mut accessor = Accessor::new(token);
1423             closure(&mut accessor).await
1424         }
1425     }
1426 }
1427 
1428 impl StoreOpaque {
1429     /// Push a `GuestTask` onto the task stack for either a sync-to-sync,
1430     /// guest-to-guest call or a sync host-to-guest call.
1431     ///
1432     /// This task will only be used for the purpose of handling calls to
1433     /// intrinsic functions; both parameter lowering and result lifting are
1434     /// assumed to be taken care of elsewhere.
1435     pub(crate) fn enter_guest_sync_call(
1436         &mut self,
1437         guest_caller: Option<RuntimeInstance>,
1438         callee_async: bool,
1439         callee: RuntimeInstance,
1440     ) -> Result<()> {
1441         log::trace!("enter sync call {callee:?}");
1442         if !self.concurrency_support() {
1443             return Ok(self.enter_call_not_concurrent());
1444         }
1445 
1446         let state = self.concurrent_state_mut();
1447         let thread = state.current_thread;
1448         let instance = if let Some(thread) = thread.guest() {
1449             Some(state.get_mut(thread.task)?.instance)
1450         } else {
1451             None
1452         };
1453         let task = GuestTask::new(
1454             state,
1455             Box::new(move |_, _| unreachable!()),
1456             LiftResult {
1457                 lift: Box::new(move |_, _| unreachable!()),
1458                 ty: TypeTupleIndex::reserved_value(),
1459                 memory: None,
1460                 string_encoding: StringEncoding::Utf8,
1461             },
1462             if let Some(caller) = guest_caller {
1463                 assert_eq!(caller, instance.unwrap());
1464                 Caller::Guest {
1465                     thread: *thread.guest().unwrap(),
1466                 }
1467             } else {
1468                 Caller::Host {
1469                     tx: None,
1470                     host_future_present: false,
1471                     caller: thread,
1472                 }
1473             },
1474             None,
1475             callee,
1476             callee_async,
1477         )?;
1478 
1479         let guest_task = state.push(task)?;
1480         let new_thread = GuestThread::new_implicit(guest_task);
1481         let guest_thread = state.push(new_thread)?;
1482         Instance::from_wasmtime(self, callee.instance).add_guest_thread_to_instance_table(
1483             guest_thread,
1484             self,
1485             callee.index,
1486         )?;
1487 
1488         let state = self.concurrent_state_mut();
1489         state.get_mut(guest_task)?.threads.insert(guest_thread);
1490 
1491         self.set_thread(QualifiedThreadId {
1492             task: guest_task,
1493             thread: guest_thread,
1494         });
1495 
1496         Ok(())
1497     }
1498 
1499     /// Pop a `GuestTask` previously pushed using `enter_sync_call`.
1500     pub(crate) fn exit_guest_sync_call(&mut self, guest_caller: bool) -> Result<()> {
1501         if !self.concurrency_support() {
1502             return Ok(self.exit_call_not_concurrent());
1503         }
1504         let thread = *self.set_thread(CurrentThread::None).guest().unwrap();
1505         let instance = self.concurrent_state_mut().get_mut(thread.task)?.instance;
1506         log::trace!("exit sync call {instance:?}");
1507         Instance::from_wasmtime(self, instance.instance).cleanup_thread(
1508             self,
1509             thread,
1510             instance.index,
1511         )?;
1512 
1513         let state = self.concurrent_state_mut();
1514         let task = state.get_mut(thread.task)?;
1515         let caller = match &task.caller {
1516             &Caller::Guest { thread } => {
1517                 assert!(guest_caller);
1518                 thread.into()
1519             }
1520             &Caller::Host { caller, .. } => {
1521                 assert!(!guest_caller);
1522                 caller
1523             }
1524         };
1525         self.set_thread(caller);
1526 
1527         let state = self.concurrent_state_mut();
1528         let task = state.get_mut(thread.task)?;
1529         if task.ready_to_delete() {
1530             state.delete(thread.task)?.dispose(state)?;
1531         }
1532 
1533         Ok(())
1534     }
1535 
1536     /// Similar to `enter_guest_sync_call` except for when the guest makes a
1537     /// transition to the host.
1538     ///
1539     /// FIXME: this is called for all guest->host transitions and performs some
1540     /// relatively expensive table manipulations. This would ideally be
1541     /// optimized to avoid the full allocation of a `HostTask` in at least some
1542     /// situations.
1543     pub fn enter_host_call(&mut self) -> Result<()> {
1544         let state = self.concurrent_state_mut();
1545         let caller = state.unwrap_current_guest_thread();
1546         let task = state.push(HostTask::new(caller, HostTaskState::CalleeStarted))?;
1547         log::trace!("new host task {task:?}");
1548         self.set_thread(task);
1549         Ok(())
1550     }
1551 
1552     /// Dual of `enter_host_call` and signifies that the host has finished and
1553     /// will be cleaned up.
1554     ///
1555     /// Note that this isn't invoked when the host is invoked asynchronously and
1556     /// the host isn't complete yet. In that situation the host task persists
1557     /// and will be cleaned up separately.
1558     pub fn exit_host_call(&mut self) -> Result<()> {
1559         let task = self.concurrent_state_mut().unwrap_current_host_thread();
1560         log::trace!("delete host task {task:?}");
1561         let task = self.concurrent_state_mut().delete(task)?;
1562         self.set_thread(task.caller);
1563         Ok(())
1564     }
1565 
1566     /// Determine whether the specified instance may be entered from the host.
1567     ///
1568     /// We return `true` here only if all of the following hold:
1569     ///
1570     /// - The top-level instance is not already on the current task's call stack.
1571     /// - The instance is not in need of a post-return function call.
1572     /// - `self` has not been poisoned due to a trap.
1573     pub(crate) fn may_enter(&mut self, instance: RuntimeInstance) -> bool {
1574         if self.trapped() {
1575             return false;
1576         }
1577         if !self.concurrency_support() {
1578             return true;
1579         }
1580         let state = self.concurrent_state_mut();
1581         let mut cur = state.current_thread;
1582         loop {
1583             match cur {
1584                 CurrentThread::None => break true,
1585                 CurrentThread::Guest(thread) => {
1586                     let task = state.get_mut(thread.task).unwrap();
1587 
1588                     // Note that we only compare top-level instance IDs here.
1589                     // The idea is that the host is not allowed to recursively
1590                     // enter a top-level instance even if the specific leaf
1591                     // instance is not on the stack. This the behavior defined
1592                     // in the spec, and it allows us to elide runtime checks in
1593                     // guest-to-guest adapters.
1594                     if task.instance.instance == instance.instance {
1595                         break false;
1596                     }
1597                     cur = match task.caller {
1598                         Caller::Host { caller, .. } => caller,
1599                         Caller::Guest { thread } => thread.into(),
1600                     };
1601                 }
1602                 CurrentThread::Host(id) => {
1603                     cur = state.get_mut(id).unwrap().caller.into();
1604                 }
1605             }
1606         }
1607     }
1608 
1609     /// Helper function to retrieve the `InstanceState` for the
1610     /// specified instance.
1611     fn instance_state(&mut self, instance: RuntimeInstance) -> &mut InstanceState {
1612         self.component_instance_mut(instance.instance)
1613             .instance_state(instance.index)
1614     }
1615 
1616     fn set_thread(&mut self, thread: impl Into<CurrentThread>) -> CurrentThread {
1617         // Each time we switch threads, we conservatively set `task_may_block`
1618         // to `false` for the component instance we're switching away from (if
1619         // any), meaning it will be `false` for any new thread created for that
1620         // instance unless explicitly set otherwise.
1621         let state = self.concurrent_state_mut();
1622         let old_thread = mem::replace(&mut state.current_thread, thread.into());
1623         if let Some(old_thread) = old_thread.guest() {
1624             let instance = state.get_mut(old_thread.task).unwrap().instance.instance;
1625             self.component_instance_mut(instance)
1626                 .set_task_may_block(false)
1627         }
1628 
1629         // If we're switching to a new thread, set its component instance's
1630         // `task_may_block` according to where it left off.
1631         if self.concurrent_state_mut().current_thread.guest().is_some() {
1632             self.set_task_may_block();
1633         }
1634 
1635         old_thread
1636     }
1637 
1638     /// Set the global variable representing whether the current task may block
1639     /// prior to entering Wasm code.
1640     fn set_task_may_block(&mut self) {
1641         let state = self.concurrent_state_mut();
1642         let guest_thread = state.unwrap_current_guest_thread();
1643         let instance = state.get_mut(guest_thread.task).unwrap().instance.instance;
1644         let may_block = self.concurrent_state_mut().may_block(guest_thread.task);
1645         self.component_instance_mut(instance)
1646             .set_task_may_block(may_block)
1647     }
1648 
1649     pub(crate) fn check_blocking(&mut self) -> Result<()> {
1650         if !self.concurrency_support() {
1651             return Ok(());
1652         }
1653         let state = self.concurrent_state_mut();
1654         let task = state.unwrap_current_guest_thread().task;
1655         let instance = state.get_mut(task).unwrap().instance.instance;
1656         let task_may_block = self.component_instance(instance).get_task_may_block();
1657 
1658         if task_may_block {
1659             Ok(())
1660         } else {
1661             Err(Trap::CannotBlockSyncTask.into())
1662         }
1663     }
1664 
1665     /// Record that we're about to enter a (sub-)component instance which does
1666     /// not support more than one concurrent, stackful activation, meaning it
1667     /// cannot be entered again until the next call returns.
1668     fn enter_instance(&mut self, instance: RuntimeInstance) {
1669         log::trace!("enter {instance:?}");
1670         self.instance_state(instance)
1671             .concurrent_state()
1672             .do_not_enter = true;
1673     }
1674 
1675     /// Record that we've exited a (sub-)component instance previously entered
1676     /// with `Self::enter_instance` and then calls `Self::partition_pending`.
1677     /// See the documentation for the latter for details.
1678     fn exit_instance(&mut self, instance: RuntimeInstance) -> Result<()> {
1679         log::trace!("exit {instance:?}");
1680         self.instance_state(instance)
1681             .concurrent_state()
1682             .do_not_enter = false;
1683         self.partition_pending(instance)
1684     }
1685 
1686     /// Iterate over `InstanceState::pending`, moving any ready items into the
1687     /// "high priority" work item queue.
1688     ///
1689     /// See `GuestCall::is_ready` for details.
1690     fn partition_pending(&mut self, instance: RuntimeInstance) -> Result<()> {
1691         for (thread, kind) in
1692             mem::take(&mut self.instance_state(instance).concurrent_state().pending).into_iter()
1693         {
1694             let call = GuestCall { thread, kind };
1695             if call.is_ready(self)? {
1696                 self.concurrent_state_mut()
1697                     .push_high_priority(WorkItem::GuestCall(instance.index, call));
1698             } else {
1699                 self.instance_state(instance)
1700                     .concurrent_state()
1701                     .pending
1702                     .insert(call.thread, call.kind);
1703             }
1704         }
1705 
1706         Ok(())
1707     }
1708 
1709     /// Implements the `backpressure.{inc,dec}` intrinsics.
1710     pub(crate) fn backpressure_modify(
1711         &mut self,
1712         caller_instance: RuntimeInstance,
1713         modify: impl FnOnce(u16) -> Option<u16>,
1714     ) -> Result<()> {
1715         let state = self.instance_state(caller_instance).concurrent_state();
1716         let old = state.backpressure;
1717         let new = modify(old).ok_or_else(|| format_err!("backpressure counter overflow"))?;
1718         state.backpressure = new;
1719 
1720         if old > 0 && new == 0 {
1721             // Backpressure was previously enabled and is now disabled; move any
1722             // newly-eligible guest calls to the "high priority" queue.
1723             self.partition_pending(caller_instance)?;
1724         }
1725 
1726         Ok(())
1727     }
1728 
1729     /// Resume the specified fiber, giving it exclusive access to the specified
1730     /// store.
1731     async fn resume_fiber(&mut self, fiber: StoreFiber<'static>) -> Result<()> {
1732         let old_thread = self.concurrent_state_mut().current_thread;
1733         log::trace!("resume_fiber: save current thread {old_thread:?}");
1734 
1735         let fiber = fiber::resolve_or_release(self, fiber).await?;
1736 
1737         self.set_thread(old_thread);
1738 
1739         let state = self.concurrent_state_mut();
1740 
1741         if let Some(ot) = old_thread.guest() {
1742             state.get_mut(ot.thread)?.state = GuestThreadState::Running;
1743         }
1744         log::trace!("resume_fiber: restore current thread {old_thread:?}");
1745 
1746         if let Some(mut fiber) = fiber {
1747             log::trace!("resume_fiber: suspend reason {:?}", &state.suspend_reason);
1748             // See the `SuspendReason` documentation for what each case means.
1749             match state.suspend_reason.take().unwrap() {
1750                 SuspendReason::NeedWork => {
1751                     if state.worker.is_none() {
1752                         state.worker = Some(fiber);
1753                     } else {
1754                         fiber.dispose(self);
1755                     }
1756                 }
1757                 SuspendReason::Yielding { thread, .. } => {
1758                     state.get_mut(thread.thread)?.state = GuestThreadState::Ready(fiber);
1759                     let instance = state.get_mut(thread.task)?.instance.index;
1760                     state.push_low_priority(WorkItem::ResumeThread(instance, thread));
1761                 }
1762                 SuspendReason::ExplicitlySuspending { thread, .. } => {
1763                     state.get_mut(thread.thread)?.state = GuestThreadState::Suspended(fiber);
1764                 }
1765                 SuspendReason::Waiting { set, thread, .. } => {
1766                     let old = state
1767                         .get_mut(set)?
1768                         .waiting
1769                         .insert(thread, WaitMode::Fiber(fiber));
1770                     assert!(old.is_none());
1771                 }
1772             };
1773         } else {
1774             log::trace!("resume_fiber: fiber has exited");
1775         }
1776 
1777         Ok(())
1778     }
1779 
1780     /// Suspend the current fiber, storing the reason in
1781     /// `ConcurrentState::suspend_reason` to indicate the conditions under which
1782     /// it should be resumed.
1783     ///
1784     /// See the `SuspendReason` documentation for details.
1785     fn suspend(&mut self, reason: SuspendReason) -> Result<()> {
1786         log::trace!("suspend fiber: {reason:?}");
1787 
1788         // If we're yielding or waiting on behalf of a guest thread, we'll need to
1789         // pop the call context which manages resource borrows before suspending
1790         // and then push it again once we've resumed.
1791         let task = match &reason {
1792             SuspendReason::Yielding { thread, .. }
1793             | SuspendReason::Waiting { thread, .. }
1794             | SuspendReason::ExplicitlySuspending { thread, .. } => Some(thread.task),
1795             SuspendReason::NeedWork => None,
1796         };
1797 
1798         let old_guest_thread = if task.is_some() {
1799             self.concurrent_state_mut().current_thread
1800         } else {
1801             CurrentThread::None
1802         };
1803 
1804         // We should not have reached here unless either there's no current
1805         // task, or the current task is permitted to block.  In addition, we
1806         // special-case `thread.switch-to` and waiting for a subtask to go from
1807         // `starting` to `started`, both of which we consider non-blocking
1808         // operations despite requiring a suspend.
1809         assert!(
1810             matches!(
1811                 reason,
1812                 SuspendReason::ExplicitlySuspending {
1813                     skip_may_block_check: true,
1814                     ..
1815                 } | SuspendReason::Waiting {
1816                     skip_may_block_check: true,
1817                     ..
1818                 } | SuspendReason::Yielding {
1819                     skip_may_block_check: true,
1820                     ..
1821                 }
1822             ) || old_guest_thread
1823                 .guest()
1824                 .map(|thread| self.concurrent_state_mut().may_block(thread.task))
1825                 .unwrap_or(true)
1826         );
1827 
1828         let suspend_reason = &mut self.concurrent_state_mut().suspend_reason;
1829         assert!(suspend_reason.is_none());
1830         *suspend_reason = Some(reason);
1831 
1832         self.with_blocking(|_, cx| cx.suspend(StoreFiberYield::ReleaseStore))?;
1833 
1834         if task.is_some() {
1835             self.set_thread(old_guest_thread);
1836         }
1837 
1838         Ok(())
1839     }
1840 
1841     fn wait_for_event(&mut self, waitable: Waitable) -> Result<()> {
1842         let state = self.concurrent_state_mut();
1843         let caller = state.unwrap_current_guest_thread();
1844         let old_set = waitable.common(state)?.set;
1845         let set = state.get_mut(caller.task)?.sync_call_set;
1846         waitable.join(state, Some(set))?;
1847         self.suspend(SuspendReason::Waiting {
1848             set,
1849             thread: caller,
1850             skip_may_block_check: false,
1851         })?;
1852         let state = self.concurrent_state_mut();
1853         waitable.join(state, old_set)
1854     }
1855 }
1856 
1857 impl Instance {
1858     /// Get the next pending event for the specified task and (optional)
1859     /// waitable set, along with the waitable handle if applicable.
1860     fn get_event(
1861         self,
1862         store: &mut StoreOpaque,
1863         guest_task: TableId<GuestTask>,
1864         set: Option<TableId<WaitableSet>>,
1865         cancellable: bool,
1866     ) -> Result<Option<(Event, Option<(Waitable, u32)>)>> {
1867         let state = store.concurrent_state_mut();
1868 
1869         if let Some(event) = state.get_mut(guest_task)?.event.take() {
1870             log::trace!("deliver event {event:?} to {guest_task:?}");
1871 
1872             if cancellable || !matches!(event, Event::Cancelled) {
1873                 return Ok(Some((event, None)));
1874             } else {
1875                 state.get_mut(guest_task)?.event = Some(event);
1876             }
1877         }
1878 
1879         Ok(
1880             if let Some((set, waitable)) = set
1881                 .and_then(|set| {
1882                     state
1883                         .get_mut(set)
1884                         .map(|v| v.ready.pop_first().map(|v| (set, v)))
1885                         .transpose()
1886                 })
1887                 .transpose()?
1888             {
1889                 let common = waitable.common(state)?;
1890                 let handle = common.handle.unwrap();
1891                 let event = common.event.take().unwrap();
1892 
1893                 log::trace!(
1894                     "deliver event {event:?} to {guest_task:?} for {waitable:?} (handle {handle}); set {set:?}"
1895                 );
1896 
1897                 waitable.on_delivery(store, self, event);
1898 
1899                 Some((event, Some((waitable, handle))))
1900             } else {
1901                 None
1902             },
1903         )
1904     }
1905 
1906     /// Handle the `CallbackCode` returned from an async-lifted export or its
1907     /// callback.
1908     ///
1909     /// If this returns `Ok(Some(call))`, then `call` should be run immediately
1910     /// using `handle_guest_call`.
1911     fn handle_callback_code(
1912         self,
1913         store: &mut StoreOpaque,
1914         guest_thread: QualifiedThreadId,
1915         runtime_instance: RuntimeComponentInstanceIndex,
1916         code: u32,
1917     ) -> Result<Option<GuestCall>> {
1918         let (code, set) = unpack_callback_code(code);
1919 
1920         log::trace!("received callback code from {guest_thread:?}: {code} (set: {set})");
1921 
1922         let state = store.concurrent_state_mut();
1923 
1924         let get_set = |store: &mut StoreOpaque, handle| {
1925             if handle == 0 {
1926                 bail!("invalid waitable-set handle");
1927             }
1928 
1929             let set = store
1930                 .instance_state(RuntimeInstance {
1931                     instance: self.id().instance(),
1932                     index: runtime_instance,
1933                 })
1934                 .handle_table()
1935                 .waitable_set_rep(handle)?;
1936 
1937             Ok(TableId::<WaitableSet>::new(set))
1938         };
1939 
1940         Ok(match code {
1941             callback_code::EXIT => {
1942                 log::trace!("implicit thread {guest_thread:?} completed");
1943                 self.cleanup_thread(store, guest_thread, runtime_instance)?;
1944                 let task = store.concurrent_state_mut().get_mut(guest_thread.task)?;
1945                 if task.threads.is_empty() && !task.returned_or_cancelled() {
1946                     bail!(Trap::NoAsyncResult);
1947                 }
1948                 if let Caller::Guest { .. } = task.caller {
1949                     task.exited = true;
1950                     task.callback = None;
1951                 }
1952                 if task.ready_to_delete() {
1953                     Waitable::Guest(guest_thread.task).delete_from(store.concurrent_state_mut())?;
1954                 }
1955                 None
1956             }
1957             callback_code::YIELD => {
1958                 let task = state.get_mut(guest_thread.task)?;
1959                 // If an `Event::Cancelled` is pending, we'll deliver that;
1960                 // otherwise, we'll deliver `Event::None`.  Note that
1961                 // `GuestTask::event` is only ever set to one of those two
1962                 // `Event` variants.
1963                 if let Some(event) = task.event {
1964                     assert!(matches!(event, Event::None | Event::Cancelled));
1965                 } else {
1966                     task.event = Some(Event::None);
1967                 }
1968                 let call = GuestCall {
1969                     thread: guest_thread,
1970                     kind: GuestCallKind::DeliverEvent {
1971                         instance: self,
1972                         set: None,
1973                     },
1974                 };
1975                 if state.may_block(guest_thread.task) {
1976                     // Push this thread onto the "low priority" queue so it runs
1977                     // after any other threads have had a chance to run.
1978                     state.push_low_priority(WorkItem::GuestCall(runtime_instance, call));
1979                     None
1980                 } else {
1981                     // Yielding in a non-blocking context is defined as a no-op
1982                     // according to the spec, so we must run this thread
1983                     // immediately without allowing any others to run.
1984                     Some(call)
1985                 }
1986             }
1987             callback_code::WAIT => {
1988                 // The task may only return `WAIT` if it was created for a call
1989                 // to an async export).  Otherwise, we'll trap.
1990                 state.check_blocking_for(guest_thread.task)?;
1991 
1992                 let set = get_set(store, set)?;
1993                 let state = store.concurrent_state_mut();
1994 
1995                 if state.get_mut(guest_thread.task)?.event.is_some()
1996                     || !state.get_mut(set)?.ready.is_empty()
1997                 {
1998                     // An event is immediately available; deliver it ASAP.
1999                     state.push_high_priority(WorkItem::GuestCall(
2000                         runtime_instance,
2001                         GuestCall {
2002                             thread: guest_thread,
2003                             kind: GuestCallKind::DeliverEvent {
2004                                 instance: self,
2005                                 set: Some(set),
2006                             },
2007                         },
2008                     ));
2009                 } else {
2010                     // No event is immediately available.
2011                     //
2012                     // We're waiting, so register to be woken up when an event
2013                     // is published for this waitable set.
2014                     //
2015                     // Here we also set `GuestTask::wake_on_cancel` which allows
2016                     // `subtask.cancel` to interrupt the wait.
2017                     let old = state
2018                         .get_mut(guest_thread.thread)?
2019                         .wake_on_cancel
2020                         .replace(set);
2021                     assert!(old.is_none());
2022                     let old = state
2023                         .get_mut(set)?
2024                         .waiting
2025                         .insert(guest_thread, WaitMode::Callback(self));
2026                     assert!(old.is_none());
2027                 }
2028                 None
2029             }
2030             _ => bail!("unsupported callback code: {code}"),
2031         })
2032     }
2033 
2034     fn cleanup_thread(
2035         self,
2036         store: &mut StoreOpaque,
2037         guest_thread: QualifiedThreadId,
2038         runtime_instance: RuntimeComponentInstanceIndex,
2039     ) -> Result<()> {
2040         let guest_id = store
2041             .concurrent_state_mut()
2042             .get_mut(guest_thread.thread)?
2043             .instance_rep;
2044         store
2045             .instance_state(RuntimeInstance {
2046                 instance: self.id().instance(),
2047                 index: runtime_instance,
2048             })
2049             .thread_handle_table()
2050             .guest_thread_remove(guest_id.unwrap())?;
2051 
2052         store.concurrent_state_mut().delete(guest_thread.thread)?;
2053         let task = store.concurrent_state_mut().get_mut(guest_thread.task)?;
2054         task.threads.remove(&guest_thread.thread);
2055         Ok(())
2056     }
2057 
2058     /// Add the specified guest call to the "high priority" work item queue, to
2059     /// be started as soon as backpressure and/or reentrance rules allow.
2060     ///
2061     /// SAFETY: The raw pointer arguments must be valid references to guest
2062     /// functions (with the appropriate signatures) when the closures queued by
2063     /// this function are called.
2064     unsafe fn queue_call<T: 'static>(
2065         self,
2066         mut store: StoreContextMut<T>,
2067         guest_thread: QualifiedThreadId,
2068         callee: SendSyncPtr<VMFuncRef>,
2069         param_count: usize,
2070         result_count: usize,
2071         async_: bool,
2072         callback: Option<SendSyncPtr<VMFuncRef>>,
2073         post_return: Option<SendSyncPtr<VMFuncRef>>,
2074     ) -> Result<()> {
2075         /// Return a closure which will call the specified function in the scope
2076         /// of the specified task.
2077         ///
2078         /// This will use `GuestTask::lower_params` to lower the parameters, but
2079         /// will not lift the result; instead, it returns a
2080         /// `[MaybeUninit<ValRaw>; MAX_FLAT_PARAMS]` from which the result, if
2081         /// any, may be lifted.  Note that an async-lifted export will have
2082         /// returned its result using the `task.return` intrinsic (or not
2083         /// returned a result at all, in the case of `task.cancel`), in which
2084         /// case the "result" of this call will either be a callback code or
2085         /// nothing.
2086         ///
2087         /// SAFETY: `callee` must be a valid `*mut VMFuncRef` at the time when
2088         /// the returned closure is called.
2089         unsafe fn make_call<T: 'static>(
2090             store: StoreContextMut<T>,
2091             guest_thread: QualifiedThreadId,
2092             callee: SendSyncPtr<VMFuncRef>,
2093             param_count: usize,
2094             result_count: usize,
2095         ) -> impl FnOnce(&mut dyn VMStore) -> Result<[MaybeUninit<ValRaw>; MAX_FLAT_PARAMS]>
2096         + Send
2097         + Sync
2098         + 'static
2099         + use<T> {
2100             let token = StoreToken::new(store);
2101             move |store: &mut dyn VMStore| {
2102                 let mut storage = [MaybeUninit::uninit(); MAX_FLAT_PARAMS];
2103 
2104                 store
2105                     .concurrent_state_mut()
2106                     .get_mut(guest_thread.thread)?
2107                     .state = GuestThreadState::Running;
2108                 let task = store.concurrent_state_mut().get_mut(guest_thread.task)?;
2109                 let lower = task.lower_params.take().unwrap();
2110 
2111                 lower(store, &mut storage[..param_count])?;
2112 
2113                 let mut store = token.as_context_mut(store);
2114 
2115                 // SAFETY: Per the contract documented in `make_call's`
2116                 // documentation, `callee` must be a valid pointer.
2117                 unsafe {
2118                     crate::Func::call_unchecked_raw(
2119                         &mut store,
2120                         callee.as_non_null(),
2121                         NonNull::new(
2122                             &mut storage[..param_count.max(result_count)]
2123                                 as *mut [MaybeUninit<ValRaw>] as _,
2124                         )
2125                         .unwrap(),
2126                     )?;
2127                 }
2128 
2129                 Ok(storage)
2130             }
2131         }
2132 
2133         // SAFETY: Per the contract described in this function documentation,
2134         // the `callee` pointer which `call` closes over must be valid when
2135         // called by the closure we queue below.
2136         let call = unsafe {
2137             make_call(
2138                 store.as_context_mut(),
2139                 guest_thread,
2140                 callee,
2141                 param_count,
2142                 result_count,
2143             )
2144         };
2145 
2146         let callee_instance = store
2147             .0
2148             .concurrent_state_mut()
2149             .get_mut(guest_thread.task)?
2150             .instance;
2151 
2152         let fun = if callback.is_some() {
2153             assert!(async_);
2154 
2155             Box::new(move |store: &mut dyn VMStore| {
2156                 self.add_guest_thread_to_instance_table(
2157                     guest_thread.thread,
2158                     store,
2159                     callee_instance.index,
2160                 )?;
2161                 let old_thread = store.set_thread(guest_thread);
2162                 log::trace!(
2163                     "stackless call: replaced {old_thread:?} with {guest_thread:?} as current thread"
2164                 );
2165 
2166                 store.enter_instance(callee_instance);
2167 
2168                 // SAFETY: See the documentation for `make_call` to review the
2169                 // contract we must uphold for `call` here.
2170                 //
2171                 // Per the contract described in the `queue_call`
2172                 // documentation, the `callee` pointer which `call` closes
2173                 // over must be valid.
2174                 let storage = call(store)?;
2175 
2176                 store.exit_instance(callee_instance)?;
2177 
2178                 store.set_thread(old_thread);
2179                 let state = store.concurrent_state_mut();
2180                 old_thread
2181                     .guest()
2182                     .map(|t| state.get_mut(t.thread).unwrap().state = GuestThreadState::Running);
2183                 log::trace!("stackless call: restored {old_thread:?} as current thread");
2184 
2185                 // SAFETY: `wasmparser` will have validated that the callback
2186                 // function returns a `i32` result.
2187                 let code = unsafe { storage[0].assume_init() }.get_i32() as u32;
2188 
2189                 self.handle_callback_code(store, guest_thread, callee_instance.index, code)
2190             })
2191                 as Box<dyn FnOnce(&mut dyn VMStore) -> Result<Option<GuestCall>> + Send + Sync>
2192         } else {
2193             let token = StoreToken::new(store.as_context_mut());
2194             Box::new(move |store: &mut dyn VMStore| {
2195                 self.add_guest_thread_to_instance_table(
2196                     guest_thread.thread,
2197                     store,
2198                     callee_instance.index,
2199                 )?;
2200                 let old_thread = store.set_thread(guest_thread);
2201                 log::trace!(
2202                     "sync/async-stackful call: replaced {old_thread:?} with {guest_thread:?} as current thread",
2203                 );
2204                 let flags = self.id().get(store).instance_flags(callee_instance.index);
2205 
2206                 // Unless this is a callback-less (i.e. stackful)
2207                 // async-lifted export, we need to record that the instance
2208                 // cannot be entered until the call returns.
2209                 if !async_ {
2210                     store.enter_instance(callee_instance);
2211                 }
2212 
2213                 // SAFETY: See the documentation for `make_call` to review the
2214                 // contract we must uphold for `call` here.
2215                 //
2216                 // Per the contract described in the `queue_call`
2217                 // documentation, the `callee` pointer which `call` closes
2218                 // over must be valid.
2219                 let storage = call(store)?;
2220 
2221                 if async_ {
2222                     let task = store.concurrent_state_mut().get_mut(guest_thread.task)?;
2223                     if task.threads.len() == 1 && !task.returned_or_cancelled() {
2224                         bail!(Trap::NoAsyncResult);
2225                     }
2226                 } else {
2227                     // This is a sync-lifted export, so now is when we lift the
2228                     // result, optionally call the post-return function, if any,
2229                     // and finally notify any current or future waiters that the
2230                     // subtask has returned.
2231 
2232                     let lift = {
2233                         store.exit_instance(callee_instance)?;
2234 
2235                         let state = store.concurrent_state_mut();
2236                         assert!(state.get_mut(guest_thread.task)?.result.is_none());
2237 
2238                         state
2239                             .get_mut(guest_thread.task)?
2240                             .lift_result
2241                             .take()
2242                             .unwrap()
2243                     };
2244 
2245                     // SAFETY: `result_count` represents the number of core Wasm
2246                     // results returned, per `wasmparser`.
2247                     let result = (lift.lift)(store, unsafe {
2248                         mem::transmute::<&[MaybeUninit<ValRaw>], &[ValRaw]>(
2249                             &storage[..result_count],
2250                         )
2251                     })?;
2252 
2253                     let post_return_arg = match result_count {
2254                         0 => ValRaw::i32(0),
2255                         // SAFETY: `result_count` represents the number of
2256                         // core Wasm results returned, per `wasmparser`.
2257                         1 => unsafe { storage[0].assume_init() },
2258                         _ => unreachable!(),
2259                     };
2260 
2261                     unsafe {
2262                         call_post_return(
2263                             token.as_context_mut(store),
2264                             post_return.map(|v| v.as_non_null()),
2265                             post_return_arg,
2266                             flags,
2267                         )?;
2268                     }
2269 
2270                     self.task_complete(store, guest_thread.task, result, Status::Returned)?;
2271                 }
2272 
2273                 // This is a callback-less call, so the implicit thread has now completed
2274                 self.cleanup_thread(store, guest_thread, callee_instance.index)?;
2275 
2276                 store.set_thread(old_thread);
2277 
2278                 let state = store.concurrent_state_mut();
2279                 let task = state.get_mut(guest_thread.task)?;
2280 
2281                 match &task.caller {
2282                     Caller::Host { .. } => {
2283                         if task.ready_to_delete() {
2284                             Waitable::Guest(guest_thread.task).delete_from(state)?;
2285                         }
2286                     }
2287                     Caller::Guest { .. } => {
2288                         task.exited = true;
2289                     }
2290                 }
2291 
2292                 Ok(None)
2293             })
2294         };
2295 
2296         store
2297             .0
2298             .concurrent_state_mut()
2299             .push_high_priority(WorkItem::GuestCall(
2300                 callee_instance.index,
2301                 GuestCall {
2302                     thread: guest_thread,
2303                     kind: GuestCallKind::StartImplicit(fun),
2304                 },
2305             ));
2306 
2307         Ok(())
2308     }
2309 
2310     /// Prepare (but do not start) a guest->guest call.
2311     ///
2312     /// This is called from fused adapter code generated in
2313     /// `wasmtime_environ::fact::trampoline::Compiler`.  `start` and `return_`
2314     /// are synthesized Wasm functions which move the parameters from the caller
2315     /// to the callee and the result from the callee to the caller,
2316     /// respectively.  The adapter will call `Self::start_call` immediately
2317     /// after calling this function.
2318     ///
2319     /// SAFETY: All the pointer arguments must be valid pointers to guest
2320     /// entities (and with the expected signatures for the function references
2321     /// -- see `wasmtime_environ::fact::trampoline::Compiler` for details).
2322     unsafe fn prepare_call<T: 'static>(
2323         self,
2324         mut store: StoreContextMut<T>,
2325         start: *mut VMFuncRef,
2326         return_: *mut VMFuncRef,
2327         caller_instance: RuntimeComponentInstanceIndex,
2328         callee_instance: RuntimeComponentInstanceIndex,
2329         task_return_type: TypeTupleIndex,
2330         callee_async: bool,
2331         memory: *mut VMMemoryDefinition,
2332         string_encoding: u8,
2333         caller_info: CallerInfo,
2334     ) -> Result<()> {
2335         if let (CallerInfo::Sync { .. }, true) = (&caller_info, callee_async) {
2336             // A task may only call an async-typed function via a sync lower if
2337             // it was created by a call to an async export.  Otherwise, we'll
2338             // trap.
2339             store.0.check_blocking()?;
2340         }
2341 
2342         enum ResultInfo {
2343             Heap { results: u32 },
2344             Stack { result_count: u32 },
2345         }
2346 
2347         let result_info = match &caller_info {
2348             CallerInfo::Async {
2349                 has_result: true,
2350                 params,
2351             } => ResultInfo::Heap {
2352                 results: params.last().unwrap().get_u32(),
2353             },
2354             CallerInfo::Async {
2355                 has_result: false, ..
2356             } => ResultInfo::Stack { result_count: 0 },
2357             CallerInfo::Sync {
2358                 result_count,
2359                 params,
2360             } if *result_count > u32::try_from(MAX_FLAT_RESULTS).unwrap() => ResultInfo::Heap {
2361                 results: params.last().unwrap().get_u32(),
2362             },
2363             CallerInfo::Sync { result_count, .. } => ResultInfo::Stack {
2364                 result_count: *result_count,
2365             },
2366         };
2367 
2368         let sync_caller = matches!(caller_info, CallerInfo::Sync { .. });
2369 
2370         // Create a new guest task for the call, closing over the `start` and
2371         // `return_` functions to lift the parameters and lower the result,
2372         // respectively.
2373         let start = SendSyncPtr::new(NonNull::new(start).unwrap());
2374         let return_ = SendSyncPtr::new(NonNull::new(return_).unwrap());
2375         let token = StoreToken::new(store.as_context_mut());
2376         let state = store.0.concurrent_state_mut();
2377         let old_thread = state.unwrap_current_guest_thread();
2378 
2379         assert_eq!(
2380             state.get_mut(old_thread.task)?.instance,
2381             RuntimeInstance {
2382                 instance: self.id().instance(),
2383                 index: caller_instance,
2384             }
2385         );
2386 
2387         let new_task = GuestTask::new(
2388             state,
2389             Box::new(move |store, dst| {
2390                 let mut store = token.as_context_mut(store);
2391                 assert!(dst.len() <= MAX_FLAT_PARAMS);
2392                 // The `+ 1` here accounts for the return pointer, if any:
2393                 let mut src = [MaybeUninit::uninit(); MAX_FLAT_PARAMS + 1];
2394                 let count = match caller_info {
2395                     // Async callers, if they have a result, use the last
2396                     // parameter as a return pointer so chop that off if
2397                     // relevant here.
2398                     CallerInfo::Async { params, has_result } => {
2399                         let params = &params[..params.len() - usize::from(has_result)];
2400                         for (param, src) in params.iter().zip(&mut src) {
2401                             src.write(*param);
2402                         }
2403                         params.len()
2404                     }
2405 
2406                     // Sync callers forward everything directly.
2407                     CallerInfo::Sync { params, .. } => {
2408                         for (param, src) in params.iter().zip(&mut src) {
2409                             src.write(*param);
2410                         }
2411                         params.len()
2412                     }
2413                 };
2414                 // SAFETY: `start` is a valid `*mut VMFuncRef` from
2415                 // `wasmtime-cranelift`-generated fused adapter code.  Based on
2416                 // how it was constructed (see
2417                 // `wasmtime_environ::fact::trampoline::Compiler::compile_async_start_adapter`
2418                 // for details) we know it takes count parameters and returns
2419                 // `dst.len()` results.
2420                 unsafe {
2421                     crate::Func::call_unchecked_raw(
2422                         &mut store,
2423                         start.as_non_null(),
2424                         NonNull::new(
2425                             &mut src[..count.max(dst.len())] as *mut [MaybeUninit<ValRaw>] as _,
2426                         )
2427                         .unwrap(),
2428                     )?;
2429                 }
2430                 dst.copy_from_slice(&src[..dst.len()]);
2431                 let state = store.0.concurrent_state_mut();
2432                 Waitable::Guest(state.unwrap_current_guest_thread().task).set_event(
2433                     state,
2434                     Some(Event::Subtask {
2435                         status: Status::Started,
2436                     }),
2437                 )?;
2438                 Ok(())
2439             }),
2440             LiftResult {
2441                 lift: Box::new(move |store, src| {
2442                     // SAFETY: See comment in closure passed as `lower_params`
2443                     // parameter above.
2444                     let mut store = token.as_context_mut(store);
2445                     let mut my_src = src.to_owned(); // TODO: use stack to avoid allocation?
2446                     if let ResultInfo::Heap { results } = &result_info {
2447                         my_src.push(ValRaw::u32(*results));
2448                     }
2449                     // SAFETY: `return_` is a valid `*mut VMFuncRef` from
2450                     // `wasmtime-cranelift`-generated fused adapter code.  Based
2451                     // on how it was constructed (see
2452                     // `wasmtime_environ::fact::trampoline::Compiler::compile_async_return_adapter`
2453                     // for details) we know it takes `src.len()` parameters and
2454                     // returns up to 1 result.
2455                     unsafe {
2456                         crate::Func::call_unchecked_raw(
2457                             &mut store,
2458                             return_.as_non_null(),
2459                             my_src.as_mut_slice().into(),
2460                         )?;
2461                     }
2462                     let state = store.0.concurrent_state_mut();
2463                     let thread = state.unwrap_current_guest_thread();
2464                     if sync_caller {
2465                         state.get_mut(thread.task)?.sync_result = SyncResult::Produced(
2466                             if let ResultInfo::Stack { result_count } = &result_info {
2467                                 match result_count {
2468                                     0 => None,
2469                                     1 => Some(my_src[0]),
2470                                     _ => unreachable!(),
2471                                 }
2472                             } else {
2473                                 None
2474                             },
2475                         );
2476                     }
2477                     Ok(Box::new(DummyResult) as Box<dyn Any + Send + Sync>)
2478                 }),
2479                 ty: task_return_type,
2480                 memory: NonNull::new(memory).map(SendSyncPtr::new),
2481                 string_encoding: StringEncoding::from_u8(string_encoding).unwrap(),
2482             },
2483             Caller::Guest { thread: old_thread },
2484             None,
2485             RuntimeInstance {
2486                 instance: self.id().instance(),
2487                 index: callee_instance,
2488             },
2489             callee_async,
2490         )?;
2491 
2492         let guest_task = state.push(new_task)?;
2493         let new_thread = GuestThread::new_implicit(guest_task);
2494         let guest_thread = state.push(new_thread)?;
2495         state.get_mut(guest_task)?.threads.insert(guest_thread);
2496 
2497         // Make the new thread the current one so that `Self::start_call` knows
2498         // which one to start.
2499         store.0.set_thread(QualifiedThreadId {
2500             task: guest_task,
2501             thread: guest_thread,
2502         });
2503         log::trace!(
2504             "pushed {guest_task:?}:{guest_thread:?} as current thread; old thread was {old_thread:?}"
2505         );
2506 
2507         Ok(())
2508     }
2509 
2510     /// Call the specified callback function for an async-lifted export.
2511     ///
2512     /// SAFETY: `function` must be a valid reference to a guest function of the
2513     /// correct signature for a callback.
2514     unsafe fn call_callback<T>(
2515         self,
2516         mut store: StoreContextMut<T>,
2517         function: SendSyncPtr<VMFuncRef>,
2518         event: Event,
2519         handle: u32,
2520     ) -> Result<u32> {
2521         let (ordinal, result) = event.parts();
2522         let params = &mut [
2523             ValRaw::u32(ordinal),
2524             ValRaw::u32(handle),
2525             ValRaw::u32(result),
2526         ];
2527         // SAFETY: `func` is a valid `*mut VMFuncRef` from either
2528         // `wasmtime-cranelift`-generated fused adapter code or
2529         // `component::Options`.  Per `wasmparser` callback signature
2530         // validation, we know it takes three parameters and returns one.
2531         unsafe {
2532             crate::Func::call_unchecked_raw(
2533                 &mut store,
2534                 function.as_non_null(),
2535                 params.as_mut_slice().into(),
2536             )?;
2537         }
2538         Ok(params[0].get_u32())
2539     }
2540 
2541     /// Start a guest->guest call previously prepared using
2542     /// `Self::prepare_call`.
2543     ///
2544     /// This is called from fused adapter code generated in
2545     /// `wasmtime_environ::fact::trampoline::Compiler`.  The adapter will call
2546     /// this function immediately after calling `Self::prepare_call`.
2547     ///
2548     /// SAFETY: The `*mut VMFuncRef` arguments must be valid pointers to guest
2549     /// functions with the appropriate signatures for the current guest task.
2550     /// If this is a call to an async-lowered import, the actual call may be
2551     /// deferred and run after this function returns, in which case the pointer
2552     /// arguments must also be valid when the call happens.
2553     unsafe fn start_call<T: 'static>(
2554         self,
2555         mut store: StoreContextMut<T>,
2556         callback: *mut VMFuncRef,
2557         post_return: *mut VMFuncRef,
2558         callee: *mut VMFuncRef,
2559         param_count: u32,
2560         result_count: u32,
2561         flags: u32,
2562         storage: Option<&mut [MaybeUninit<ValRaw>]>,
2563     ) -> Result<u32> {
2564         let token = StoreToken::new(store.as_context_mut());
2565         let async_caller = storage.is_none();
2566         let state = store.0.concurrent_state_mut();
2567         let guest_thread = state.unwrap_current_guest_thread();
2568         let callee_async = state.get_mut(guest_thread.task)?.async_function;
2569         let callee = SendSyncPtr::new(NonNull::new(callee).unwrap());
2570         let param_count = usize::try_from(param_count).unwrap();
2571         assert!(param_count <= MAX_FLAT_PARAMS);
2572         let result_count = usize::try_from(result_count).unwrap();
2573         assert!(result_count <= MAX_FLAT_RESULTS);
2574 
2575         let task = state.get_mut(guest_thread.task)?;
2576         if !callback.is_null() {
2577             // We're calling an async-lifted export with a callback, so store
2578             // the callback and related context as part of the task so we can
2579             // call it later when needed.
2580             let callback = SendSyncPtr::new(NonNull::new(callback).unwrap());
2581             task.callback = Some(Box::new(move |store, event, handle| {
2582                 let store = token.as_context_mut(store);
2583                 unsafe { self.call_callback::<T>(store, callback, event, handle) }
2584             }));
2585         }
2586 
2587         let Caller::Guest { thread: caller } = &task.caller else {
2588             // As of this writing, `start_call` is only used for guest->guest
2589             // calls.
2590             unreachable!()
2591         };
2592         let caller = *caller;
2593         let caller_instance = state.get_mut(caller.task)?.instance;
2594 
2595         // Queue the call as a "high priority" work item.
2596         unsafe {
2597             self.queue_call(
2598                 store.as_context_mut(),
2599                 guest_thread,
2600                 callee,
2601                 param_count,
2602                 result_count,
2603                 (flags & START_FLAG_ASYNC_CALLEE) != 0,
2604                 NonNull::new(callback).map(SendSyncPtr::new),
2605                 NonNull::new(post_return).map(SendSyncPtr::new),
2606             )?;
2607         }
2608 
2609         let state = store.0.concurrent_state_mut();
2610 
2611         // Use the caller's `GuestTask::sync_call_set` to register interest in
2612         // the subtask...
2613         let guest_waitable = Waitable::Guest(guest_thread.task);
2614         let old_set = guest_waitable.common(state)?.set;
2615         let set = state.get_mut(caller.task)?.sync_call_set;
2616         guest_waitable.join(state, Some(set))?;
2617 
2618         // ... and suspend this fiber temporarily while we wait for it to start.
2619         //
2620         // Note that we _could_ call the callee directly using the current fiber
2621         // rather than suspend this one, but that would make reasoning about the
2622         // event loop more complicated and is probably only worth doing if
2623         // there's a measurable performance benefit.  In addition, it would mean
2624         // blocking the caller if the callee calls a blocking sync-lowered
2625         // import, and as of this writing the spec says we must not do that.
2626         //
2627         // Alternatively, the fused adapter code could be modified to call the
2628         // callee directly without calling a host-provided intrinsic at all (in
2629         // which case it would need to do its own, inline backpressure checks,
2630         // etc.).  Again, we'd want to see a measurable performance benefit
2631         // before committing to such an optimization.  And again, we'd need to
2632         // update the spec to allow that.
2633         let (status, waitable) = loop {
2634             store.0.suspend(SuspendReason::Waiting {
2635                 set,
2636                 thread: caller,
2637                 // Normally, `StoreOpaque::suspend` would assert it's being
2638                 // called from a context where blocking is allowed.  However, if
2639                 // `async_caller` is `true`, we'll only "block" long enough for
2640                 // the callee to start, i.e. we won't repeat this loop, so we
2641                 // tell `suspend` it's okay even if we're not allowed to block.
2642                 // Alternatively, if the callee is not an async function, then
2643                 // we know it won't block anyway.
2644                 skip_may_block_check: async_caller || !callee_async,
2645             })?;
2646 
2647             let state = store.0.concurrent_state_mut();
2648 
2649             log::trace!("taking event for {:?}", guest_thread.task);
2650             let event = guest_waitable.take_event(state)?;
2651             let Some(Event::Subtask { status }) = event else {
2652                 unreachable!();
2653             };
2654 
2655             log::trace!("status {status:?} for {:?}", guest_thread.task);
2656 
2657             if status == Status::Returned {
2658                 // It returned, so we can stop waiting.
2659                 break (status, None);
2660             } else if async_caller {
2661                 // It hasn't returned yet, but the caller is calling via an
2662                 // async-lowered import, so we generate a handle for the task
2663                 // waitable and return the status.
2664                 let handle = store
2665                     .0
2666                     .instance_state(caller_instance)
2667                     .handle_table()
2668                     .subtask_insert_guest(guest_thread.task.rep())?;
2669                 store
2670                     .0
2671                     .concurrent_state_mut()
2672                     .get_mut(guest_thread.task)?
2673                     .common
2674                     .handle = Some(handle);
2675                 break (status, Some(handle));
2676             } else {
2677                 // The callee hasn't returned yet, and the caller is calling via
2678                 // a sync-lowered import, so we loop and keep waiting until the
2679                 // callee returns.
2680             }
2681         };
2682 
2683         guest_waitable.join(store.0.concurrent_state_mut(), old_set)?;
2684 
2685         // Reset the current thread to point to the caller as it resumes control.
2686         store.0.set_thread(caller);
2687         store.0.concurrent_state_mut().get_mut(caller.thread)?.state = GuestThreadState::Running;
2688         log::trace!("popped current thread {guest_thread:?}; new thread is {caller:?}");
2689 
2690         if let Some(storage) = storage {
2691             // The caller used a sync-lowered import to call an async-lifted
2692             // export, in which case the result, if any, has been stashed in
2693             // `GuestTask::sync_result`.
2694             let state = store.0.concurrent_state_mut();
2695             let task = state.get_mut(guest_thread.task)?;
2696             if let Some(result) = task.sync_result.take() {
2697                 if let Some(result) = result {
2698                     storage[0] = MaybeUninit::new(result);
2699                 }
2700 
2701                 if task.exited && task.ready_to_delete() {
2702                     Waitable::Guest(guest_thread.task).delete_from(state)?;
2703                 }
2704             }
2705         }
2706 
2707         Ok(status.pack(waitable))
2708     }
2709 
2710     /// Poll the specified future once on behalf of a guest->host call using an
2711     /// async-lowered import.
2712     ///
2713     /// If it returns `Ready`, return `Ok(None)`.  Otherwise, if it returns
2714     /// `Pending`, add it to the set of futures to be polled as part of this
2715     /// instance's event loop until it completes, and then return
2716     /// `Ok(Some(handle))` where `handle` is the waitable handle to return.
2717     ///
2718     /// Whether the future returns `Ready` immediately or later, the `lower`
2719     /// function will be used to lower the result, if any, into the guest caller's
2720     /// stack and linear memory. The `lower` function is invoked with `None` if
2721     /// the future is cancelled.
2722     pub(crate) fn first_poll<T: 'static, R: Send + 'static>(
2723         self,
2724         mut store: StoreContextMut<'_, T>,
2725         future: impl Future<Output = Result<R>> + Send + 'static,
2726         lower: impl FnOnce(StoreContextMut<T>, Option<R>) -> Result<()> + Send + 'static,
2727     ) -> Result<Option<u32>> {
2728         let token = StoreToken::new(store.as_context_mut());
2729         let state = store.0.concurrent_state_mut();
2730         let task = state.unwrap_current_host_thread();
2731 
2732         // Create an abortable future which hooks calls to poll and manages call
2733         // context state for the future.
2734         let (join_handle, future) = JoinHandle::run(future);
2735         {
2736             let state = &mut state.get_mut(task)?.state;
2737             assert!(matches!(state, HostTaskState::CalleeStarted));
2738             *state = HostTaskState::CalleeRunning(join_handle);
2739         }
2740 
2741         let mut future = Box::pin(future);
2742 
2743         // Finally, poll the future.  We can use a dummy `Waker` here because
2744         // we'll add the future to `ConcurrentState::futures` and poll it
2745         // automatically from the event loop if it doesn't complete immediately
2746         // here.
2747         let poll = tls::set(store.0, || {
2748             future
2749                 .as_mut()
2750                 .poll(&mut Context::from_waker(&Waker::noop()))
2751         });
2752 
2753         match poll {
2754             // It finished immediately; lower the result and delete the task.
2755             Poll::Ready(Some(result)) => {
2756                 lower(store.as_context_mut(), Some(result?))?;
2757                 return Ok(None);
2758             }
2759 
2760             // Shouldn't be possible since the future isn't cancelled via the
2761             // `join_handle`.
2762             Poll::Ready(None) => unreachable!(),
2763 
2764             // Future isn't ready yet, so fall through.
2765             Poll::Pending => {}
2766         }
2767 
2768         // It hasn't finished yet; add the future to
2769         // `ConcurrentState::futures` so it will be polled by the event
2770         // loop and allocate a waitable handle to return to the guest.
2771 
2772         // Wrap the future in a closure responsible for lowering the result into
2773         // the guest's stack and memory, as well as notifying any waiters that
2774         // the task returned.
2775         let future = Box::pin(async move {
2776             let result = match future.await {
2777                 Some(result) => Some(result?),
2778                 None => None,
2779             };
2780             let on_complete = move |store: &mut dyn VMStore| {
2781                 // Restore the `current_thread` to be the host so `lower` knows
2782                 // how to manipulate borrows and knows which scope of borrows
2783                 // to check.
2784                 let mut store = token.as_context_mut(store);
2785                 let state = store.0.concurrent_state_mut();
2786                 assert!(state.current_thread.is_none());
2787                 store.0.set_thread(task);
2788 
2789                 let status = if result.is_some() {
2790                     Status::Returned
2791                 } else {
2792                     Status::ReturnCancelled
2793                 };
2794 
2795                 lower(store.as_context_mut(), result)?;
2796                 let state = store.0.concurrent_state_mut();
2797                 state.get_mut(task)?.state = HostTaskState::CalleeDone;
2798                 Waitable::Host(task).set_event(state, Some(Event::Subtask { status }))?;
2799 
2800                 // Go back to "no current thread" at the end.
2801                 store.0.set_thread(CurrentThread::None);
2802                 Ok(())
2803             };
2804 
2805             // Here we schedule a task to run on a worker fiber to do the
2806             // lowering since it may involve a call to the guest's realloc
2807             // function. This is necessary because calling the guest while
2808             // there are host embedder frames on the stack is unsound.
2809             tls::get(move |store| {
2810                 store
2811                     .concurrent_state_mut()
2812                     .push_high_priority(WorkItem::WorkerFunction(AlwaysMut::new(Box::new(
2813                         on_complete,
2814                     ))));
2815                 Ok(())
2816             })
2817         });
2818 
2819         // Make this task visible to the guest and then record what it
2820         // was made visible as.
2821         let state = store.0.concurrent_state_mut();
2822         state.push_future(future);
2823         let caller = state.get_mut(task)?.caller;
2824         let instance = state.get_mut(caller.task)?.instance;
2825         let handle = store
2826             .0
2827             .instance_state(instance)
2828             .handle_table()
2829             .subtask_insert_host(task.rep())?;
2830         store.0.concurrent_state_mut().get_mut(task)?.common.handle = Some(handle);
2831         log::trace!("assign {task:?} handle {handle} for {caller:?} instance {instance:?}");
2832 
2833         // Restore the currently running thread to this host task's
2834         // caller. Note that the host task isn't deallocated as it's
2835         // within the store and will get deallocated later.
2836         store.0.set_thread(caller);
2837         Ok(Some(handle))
2838     }
2839 
2840     /// Implements the `task.return` intrinsic, lifting the result for the
2841     /// current guest task.
2842     pub(crate) fn task_return(
2843         self,
2844         store: &mut dyn VMStore,
2845         ty: TypeTupleIndex,
2846         options: OptionsIndex,
2847         storage: &[ValRaw],
2848     ) -> Result<()> {
2849         let state = store.concurrent_state_mut();
2850         let guest_thread = state.unwrap_current_guest_thread();
2851         let lift = state
2852             .get_mut(guest_thread.task)?
2853             .lift_result
2854             .take()
2855             .ok_or_else(|| {
2856                 format_err!("`task.return` or `task.cancel` called more than once for current task")
2857             })?;
2858         assert!(state.get_mut(guest_thread.task)?.result.is_none());
2859 
2860         let CanonicalOptions {
2861             string_encoding,
2862             data_model,
2863             ..
2864         } = &self.id().get(store).component().env_component().options[options];
2865 
2866         let invalid = ty != lift.ty
2867             || string_encoding != &lift.string_encoding
2868             || match data_model {
2869                 CanonicalOptionsDataModel::LinearMemory(opts) => match opts.memory {
2870                     Some(memory) => {
2871                         let expected = lift.memory.map(|v| v.as_ptr()).unwrap_or(ptr::null_mut());
2872                         let actual = self.id().get(store).runtime_memory(memory);
2873                         expected != actual.as_ptr()
2874                     }
2875                     // Memory not specified, meaning it didn't need to be
2876                     // specified per validation, so not invalid.
2877                     None => false,
2878                 },
2879                 // Always invalid as this isn't supported.
2880                 CanonicalOptionsDataModel::Gc { .. } => true,
2881             };
2882 
2883         if invalid {
2884             bail!("invalid `task.return` signature and/or options for current task");
2885         }
2886 
2887         log::trace!("task.return for {guest_thread:?}");
2888 
2889         let result = (lift.lift)(store, storage)?;
2890         self.task_complete(store, guest_thread.task, result, Status::Returned)
2891     }
2892 
2893     /// Implements the `task.cancel` intrinsic.
2894     pub(crate) fn task_cancel(self, store: &mut StoreOpaque) -> Result<()> {
2895         let state = store.concurrent_state_mut();
2896         let guest_thread = state.unwrap_current_guest_thread();
2897         let task = state.get_mut(guest_thread.task)?;
2898         if !task.cancel_sent {
2899             bail!("`task.cancel` called by task which has not been cancelled")
2900         }
2901         _ = task.lift_result.take().ok_or_else(|| {
2902             format_err!("`task.return` or `task.cancel` called more than once for current task")
2903         })?;
2904 
2905         assert!(task.result.is_none());
2906 
2907         log::trace!("task.cancel for {guest_thread:?}");
2908 
2909         self.task_complete(
2910             store,
2911             guest_thread.task,
2912             Box::new(DummyResult),
2913             Status::ReturnCancelled,
2914         )
2915     }
2916 
2917     /// Complete the specified guest task (i.e. indicate that it has either
2918     /// returned a (possibly empty) result or cancelled itself).
2919     ///
2920     /// This will return any resource borrows and notify any current or future
2921     /// waiters that the task has completed.
2922     fn task_complete(
2923         self,
2924         store: &mut StoreOpaque,
2925         guest_task: TableId<GuestTask>,
2926         result: Box<dyn Any + Send + Sync>,
2927         status: Status,
2928     ) -> Result<()> {
2929         store
2930             .component_resource_tables(Some(self))
2931             .validate_scope_exit()?;
2932 
2933         let state = store.concurrent_state_mut();
2934         let task = state.get_mut(guest_task)?;
2935 
2936         if let Caller::Host { tx, .. } = &mut task.caller {
2937             if let Some(tx) = tx.take() {
2938                 _ = tx.send(result);
2939             }
2940         } else {
2941             task.result = Some(result);
2942             Waitable::Guest(guest_task).set_event(state, Some(Event::Subtask { status }))?;
2943         }
2944 
2945         Ok(())
2946     }
2947 
2948     /// Implements the `waitable-set.new` intrinsic.
2949     pub(crate) fn waitable_set_new(
2950         self,
2951         store: &mut StoreOpaque,
2952         caller_instance: RuntimeComponentInstanceIndex,
2953     ) -> Result<u32> {
2954         let set = store.concurrent_state_mut().push(WaitableSet::default())?;
2955         let handle = store
2956             .instance_state(RuntimeInstance {
2957                 instance: self.id().instance(),
2958                 index: caller_instance,
2959             })
2960             .handle_table()
2961             .waitable_set_insert(set.rep())?;
2962         log::trace!("new waitable set {set:?} (handle {handle})");
2963         Ok(handle)
2964     }
2965 
2966     /// Implements the `waitable-set.drop` intrinsic.
2967     pub(crate) fn waitable_set_drop(
2968         self,
2969         store: &mut StoreOpaque,
2970         caller_instance: RuntimeComponentInstanceIndex,
2971         set: u32,
2972     ) -> Result<()> {
2973         let rep = store
2974             .instance_state(RuntimeInstance {
2975                 instance: self.id().instance(),
2976                 index: caller_instance,
2977             })
2978             .handle_table()
2979             .waitable_set_remove(set)?;
2980 
2981         log::trace!("drop waitable set {rep} (handle {set})");
2982 
2983         let set = store
2984             .concurrent_state_mut()
2985             .delete(TableId::<WaitableSet>::new(rep))?;
2986 
2987         if !set.waiting.is_empty() {
2988             bail!("cannot drop waitable set with waiters");
2989         }
2990 
2991         Ok(())
2992     }
2993 
2994     /// Implements the `waitable.join` intrinsic.
2995     pub(crate) fn waitable_join(
2996         self,
2997         store: &mut StoreOpaque,
2998         caller_instance: RuntimeComponentInstanceIndex,
2999         waitable_handle: u32,
3000         set_handle: u32,
3001     ) -> Result<()> {
3002         let mut instance = self.id().get_mut(store);
3003         let waitable =
3004             Waitable::from_instance(instance.as_mut(), caller_instance, waitable_handle)?;
3005 
3006         let set = if set_handle == 0 {
3007             None
3008         } else {
3009             let set = instance.instance_states().0[caller_instance]
3010                 .handle_table()
3011                 .waitable_set_rep(set_handle)?;
3012 
3013             Some(TableId::<WaitableSet>::new(set))
3014         };
3015 
3016         log::trace!(
3017             "waitable {waitable:?} (handle {waitable_handle}) join set {set:?} (handle {set_handle})",
3018         );
3019 
3020         waitable.join(store.concurrent_state_mut(), set)
3021     }
3022 
3023     /// Implements the `subtask.drop` intrinsic.
3024     pub(crate) fn subtask_drop(
3025         self,
3026         store: &mut StoreOpaque,
3027         caller_instance: RuntimeComponentInstanceIndex,
3028         task_id: u32,
3029     ) -> Result<()> {
3030         self.waitable_join(store, caller_instance, task_id, 0)?;
3031 
3032         let (rep, is_host) = store
3033             .instance_state(RuntimeInstance {
3034                 instance: self.id().instance(),
3035                 index: caller_instance,
3036             })
3037             .handle_table()
3038             .subtask_remove(task_id)?;
3039 
3040         let concurrent_state = store.concurrent_state_mut();
3041         let (waitable, expected_caller, delete) = if is_host {
3042             let id = TableId::<HostTask>::new(rep);
3043             let task = concurrent_state.get_mut(id)?;
3044             match &task.state {
3045                 HostTaskState::CalleeRunning(_) => {
3046                     bail!("cannot drop a subtask which has not yet resolved");
3047                 }
3048                 HostTaskState::CalleeDone => {}
3049                 HostTaskState::CalleeStarted | HostTaskState::CalleeFinished(_) => unreachable!(),
3050             }
3051             (Waitable::Host(id), task.caller, true)
3052         } else {
3053             let id = TableId::<GuestTask>::new(rep);
3054             let task = concurrent_state.get_mut(id)?;
3055             if task.lift_result.is_some() {
3056                 bail!("cannot drop a subtask which has not yet resolved");
3057             }
3058             if let Caller::Guest { thread } = task.caller {
3059                 (
3060                     Waitable::Guest(id),
3061                     thread,
3062                     concurrent_state.get_mut(id)?.exited,
3063                 )
3064             } else {
3065                 unreachable!()
3066             }
3067         };
3068 
3069         waitable.common(concurrent_state)?.handle = None;
3070 
3071         if waitable.take_event(concurrent_state)?.is_some() {
3072             bail!("cannot drop a subtask with an undelivered event");
3073         }
3074 
3075         if delete {
3076             waitable.delete_from(concurrent_state)?;
3077         }
3078 
3079         // Since waitables can neither be passed between instances nor forged,
3080         // this should never fail unless there's a bug in Wasmtime, but we check
3081         // here to be sure:
3082         assert_eq!(
3083             expected_caller,
3084             concurrent_state.unwrap_current_guest_thread(),
3085         );
3086         log::trace!("subtask_drop {waitable:?} (handle {task_id})");
3087         Ok(())
3088     }
3089 
3090     /// Implements the `waitable-set.wait` intrinsic.
3091     pub(crate) fn waitable_set_wait(
3092         self,
3093         store: &mut StoreOpaque,
3094         options: OptionsIndex,
3095         set: u32,
3096         payload: u32,
3097     ) -> Result<u32> {
3098         if !self.options(store, options).async_ {
3099             // The caller may only call `waitable-set.wait` from an async task
3100             // (i.e. a task created via a call to an async export).
3101             // Otherwise, we'll trap.
3102             store.check_blocking()?;
3103         }
3104 
3105         let &CanonicalOptions {
3106             cancellable,
3107             instance: caller_instance,
3108             ..
3109         } = &self.id().get(store).component().env_component().options[options];
3110         let rep = store
3111             .instance_state(RuntimeInstance {
3112                 instance: self.id().instance(),
3113                 index: caller_instance,
3114             })
3115             .handle_table()
3116             .waitable_set_rep(set)?;
3117 
3118         self.waitable_check(
3119             store,
3120             cancellable,
3121             WaitableCheck::Wait,
3122             WaitableCheckParams {
3123                 set: TableId::new(rep),
3124                 options,
3125                 payload,
3126             },
3127         )
3128     }
3129 
3130     /// Implements the `waitable-set.poll` intrinsic.
3131     pub(crate) fn waitable_set_poll(
3132         self,
3133         store: &mut StoreOpaque,
3134         options: OptionsIndex,
3135         set: u32,
3136         payload: u32,
3137     ) -> Result<u32> {
3138         let &CanonicalOptions {
3139             cancellable,
3140             instance: caller_instance,
3141             ..
3142         } = &self.id().get(store).component().env_component().options[options];
3143         let rep = store
3144             .instance_state(RuntimeInstance {
3145                 instance: self.id().instance(),
3146                 index: caller_instance,
3147             })
3148             .handle_table()
3149             .waitable_set_rep(set)?;
3150 
3151         self.waitable_check(
3152             store,
3153             cancellable,
3154             WaitableCheck::Poll,
3155             WaitableCheckParams {
3156                 set: TableId::new(rep),
3157                 options,
3158                 payload,
3159             },
3160         )
3161     }
3162 
3163     /// Implements the `thread.index` intrinsic.
3164     pub(crate) fn thread_index(&self, store: &mut dyn VMStore) -> Result<u32> {
3165         let thread_id = store
3166             .concurrent_state_mut()
3167             .unwrap_current_guest_thread()
3168             .thread;
3169         // The unwrap is safe because `instance_rep` must be `Some` by this point
3170         Ok(store
3171             .concurrent_state_mut()
3172             .get_mut(thread_id)?
3173             .instance_rep
3174             .unwrap())
3175     }
3176 
3177     /// Implements the `thread.new-indirect` intrinsic.
3178     pub(crate) fn thread_new_indirect<T: 'static>(
3179         self,
3180         mut store: StoreContextMut<T>,
3181         runtime_instance: RuntimeComponentInstanceIndex,
3182         _func_ty_idx: TypeFuncIndex, // currently unused
3183         start_func_table_idx: RuntimeTableIndex,
3184         start_func_idx: u32,
3185         context: i32,
3186     ) -> Result<u32> {
3187         log::trace!("creating new thread");
3188 
3189         let start_func_ty = FuncType::new(store.engine(), [ValType::I32], []);
3190         let (instance, registry) = self.id().get_mut_and_registry(store.0);
3191         let callee = instance
3192             .index_runtime_func_table(registry, start_func_table_idx, start_func_idx as u64)?
3193             .ok_or_else(|| {
3194                 format_err!("the start function index points to an uninitialized function")
3195             })?;
3196         if callee.type_index(store.0) != start_func_ty.type_index() {
3197             bail!(
3198                 "start function does not match expected type (currently only `(i32) -> ()` is supported)"
3199             );
3200         }
3201 
3202         let token = StoreToken::new(store.as_context_mut());
3203         let start_func = Box::new(
3204             move |store: &mut dyn VMStore, guest_thread: QualifiedThreadId| -> Result<()> {
3205                 let old_thread = store.set_thread(guest_thread);
3206                 log::trace!(
3207                     "thread start: replaced {old_thread:?} with {guest_thread:?} as current thread"
3208                 );
3209 
3210                 let mut store = token.as_context_mut(store);
3211                 let mut params = [ValRaw::i32(context)];
3212                 // Use call_unchecked rather than call or call_async, as we don't want to run the function
3213                 // on a separate fiber if we're running in an async store.
3214                 unsafe { callee.call_unchecked(store.as_context_mut(), &mut params)? };
3215 
3216                 self.cleanup_thread(store.0, guest_thread, runtime_instance)?;
3217                 log::trace!("explicit thread {guest_thread:?} completed");
3218                 let state = store.0.concurrent_state_mut();
3219                 let task = state.get_mut(guest_thread.task)?;
3220                 if task.threads.is_empty() && !task.returned_or_cancelled() {
3221                     bail!(Trap::NoAsyncResult);
3222                 }
3223                 store.0.set_thread(old_thread);
3224                 let state = store.0.concurrent_state_mut();
3225                 old_thread
3226                     .guest()
3227                     .map(|t| state.get_mut(t.thread).unwrap().state = GuestThreadState::Running);
3228                 if state.get_mut(guest_thread.task)?.ready_to_delete() {
3229                     Waitable::Guest(guest_thread.task).delete_from(state)?;
3230                 }
3231                 log::trace!("thread start: restored {old_thread:?} as current thread");
3232 
3233                 Ok(())
3234             },
3235         );
3236 
3237         let state = store.0.concurrent_state_mut();
3238         let current_thread = state.unwrap_current_guest_thread();
3239         let parent_task = current_thread.task;
3240 
3241         let new_thread = GuestThread::new_explicit(parent_task, start_func);
3242         let thread_id = state.push(new_thread)?;
3243         state.get_mut(parent_task)?.threads.insert(thread_id);
3244 
3245         log::trace!("new thread with id {thread_id:?} created");
3246 
3247         self.add_guest_thread_to_instance_table(thread_id, store.0, runtime_instance)
3248     }
3249 
3250     pub(crate) fn resume_thread(
3251         self,
3252         store: &mut StoreOpaque,
3253         runtime_instance: RuntimeComponentInstanceIndex,
3254         thread_idx: u32,
3255         high_priority: bool,
3256         allow_ready: bool,
3257     ) -> Result<()> {
3258         let thread_id =
3259             GuestThread::from_instance(self.id().get_mut(store), runtime_instance, thread_idx)?;
3260         let state = store.concurrent_state_mut();
3261         let guest_thread = QualifiedThreadId::qualify(state, thread_id)?;
3262         let thread = state.get_mut(guest_thread.thread)?;
3263 
3264         match mem::replace(&mut thread.state, GuestThreadState::Running) {
3265             GuestThreadState::NotStartedExplicit(start_func) => {
3266                 log::trace!("starting thread {guest_thread:?}");
3267                 let guest_call = WorkItem::GuestCall(
3268                     runtime_instance,
3269                     GuestCall {
3270                         thread: guest_thread,
3271                         kind: GuestCallKind::StartExplicit(Box::new(move |store| {
3272                             start_func(store, guest_thread)
3273                         })),
3274                     },
3275                 );
3276                 store
3277                     .concurrent_state_mut()
3278                     .push_work_item(guest_call, high_priority);
3279             }
3280             GuestThreadState::Suspended(fiber) => {
3281                 log::trace!("resuming thread {thread_id:?} that was suspended");
3282                 store
3283                     .concurrent_state_mut()
3284                     .push_work_item(WorkItem::ResumeFiber(fiber), high_priority);
3285             }
3286             GuestThreadState::Ready(fiber) if allow_ready => {
3287                 log::trace!("resuming thread {thread_id:?} that was ready");
3288                 thread.state = GuestThreadState::Ready(fiber);
3289                 store
3290                     .concurrent_state_mut()
3291                     .promote_thread_work_item(guest_thread);
3292             }
3293             other => {
3294                 thread.state = other;
3295                 bail!("cannot resume thread which is not suspended");
3296             }
3297         }
3298         Ok(())
3299     }
3300 
3301     fn add_guest_thread_to_instance_table(
3302         self,
3303         thread_id: TableId<GuestThread>,
3304         store: &mut StoreOpaque,
3305         runtime_instance: RuntimeComponentInstanceIndex,
3306     ) -> Result<u32> {
3307         let guest_id = store
3308             .instance_state(RuntimeInstance {
3309                 instance: self.id().instance(),
3310                 index: runtime_instance,
3311             })
3312             .thread_handle_table()
3313             .guest_thread_insert(thread_id.rep())?;
3314         store
3315             .concurrent_state_mut()
3316             .get_mut(thread_id)?
3317             .instance_rep = Some(guest_id);
3318         Ok(guest_id)
3319     }
3320 
3321     /// Helper function for the `thread.yield`, `thread.yield-to-suspended`, `thread.suspend`,
3322     /// `thread.suspend-to`, and `thread.suspend-to-suspended` intrinsics.
3323     pub(crate) fn suspension_intrinsic(
3324         self,
3325         store: &mut StoreOpaque,
3326         caller: RuntimeComponentInstanceIndex,
3327         cancellable: bool,
3328         yielding: bool,
3329         to_thread: SuspensionTarget,
3330     ) -> Result<WaitResult> {
3331         let guest_thread = store.concurrent_state_mut().unwrap_current_guest_thread();
3332         if to_thread.is_none() {
3333             let state = store.concurrent_state_mut();
3334             if yielding {
3335                 // This is a `thread.yield` call
3336                 if !state.may_block(guest_thread.task) {
3337                     // In a non-blocking context, a `thread.yield` may trigger
3338                     // other threads in the same component instance to run.
3339                     if !state.promote_instance_local_thread_work_item(caller) {
3340                         // No other threads are runnable, so just return
3341                         return Ok(WaitResult::Completed);
3342                     }
3343                 }
3344             } else {
3345                 // The caller may only call `thread.suspend` from an async task
3346                 // (i.e. a task created via a call to an async export).
3347                 // Otherwise, we'll trap.
3348                 store.check_blocking()?;
3349             }
3350         }
3351 
3352         // There could be a pending cancellation from a previous uncancellable wait
3353         if cancellable && store.concurrent_state_mut().take_pending_cancellation() {
3354             return Ok(WaitResult::Cancelled);
3355         }
3356 
3357         match to_thread {
3358             SuspensionTarget::SomeSuspended(thread) => {
3359                 self.resume_thread(store, caller, thread, true, false)?
3360             }
3361             SuspensionTarget::Some(thread) => {
3362                 self.resume_thread(store, caller, thread, true, true)?
3363             }
3364             SuspensionTarget::None => { /* nothing to do */ }
3365         }
3366 
3367         let reason = if yielding {
3368             SuspendReason::Yielding {
3369                 thread: guest_thread,
3370                 // Tell `StoreOpaque::suspend` it's okay to suspend here since
3371                 // we're handling a `thread.yield-to-suspended` call; otherwise it would
3372                 // panic if we called it in a non-blocking context.
3373                 skip_may_block_check: to_thread.is_some(),
3374             }
3375         } else {
3376             SuspendReason::ExplicitlySuspending {
3377                 thread: guest_thread,
3378                 // Tell `StoreOpaque::suspend` it's okay to suspend here since
3379                 // we're handling a `thread.suspend-to(-suspended)` call; otherwise it would
3380                 // panic if we called it in a non-blocking context.
3381                 skip_may_block_check: to_thread.is_some(),
3382             }
3383         };
3384 
3385         store.suspend(reason)?;
3386 
3387         if cancellable && store.concurrent_state_mut().take_pending_cancellation() {
3388             Ok(WaitResult::Cancelled)
3389         } else {
3390             Ok(WaitResult::Completed)
3391         }
3392     }
3393 
3394     /// Helper function for the `waitable-set.wait` and `waitable-set.poll` intrinsics.
3395     fn waitable_check(
3396         self,
3397         store: &mut StoreOpaque,
3398         cancellable: bool,
3399         check: WaitableCheck,
3400         params: WaitableCheckParams,
3401     ) -> Result<u32> {
3402         let guest_thread = store.concurrent_state_mut().unwrap_current_guest_thread();
3403 
3404         log::trace!("waitable check for {guest_thread:?}; set {:?}", params.set);
3405 
3406         let state = store.concurrent_state_mut();
3407         let task = state.get_mut(guest_thread.task)?;
3408 
3409         // If we're waiting, and there are no events immediately available,
3410         // suspend the fiber until that changes.
3411         match &check {
3412             WaitableCheck::Wait => {
3413                 let set = params.set;
3414 
3415                 if (task.event.is_none()
3416                     || (matches!(task.event, Some(Event::Cancelled)) && !cancellable))
3417                     && state.get_mut(set)?.ready.is_empty()
3418                 {
3419                     if cancellable {
3420                         let old = state
3421                             .get_mut(guest_thread.thread)?
3422                             .wake_on_cancel
3423                             .replace(set);
3424                         assert!(old.is_none());
3425                     }
3426 
3427                     store.suspend(SuspendReason::Waiting {
3428                         set,
3429                         thread: guest_thread,
3430                         skip_may_block_check: false,
3431                     })?;
3432                 }
3433             }
3434             WaitableCheck::Poll => {}
3435         }
3436 
3437         log::trace!(
3438             "waitable check for {guest_thread:?}; set {:?}, part two",
3439             params.set
3440         );
3441 
3442         // Deliver any pending events to the guest and return.
3443         let event = self.get_event(store, guest_thread.task, Some(params.set), cancellable)?;
3444 
3445         let (ordinal, handle, result) = match &check {
3446             WaitableCheck::Wait => {
3447                 let (event, waitable) = event.unwrap();
3448                 let handle = waitable.map(|(_, v)| v).unwrap_or(0);
3449                 let (ordinal, result) = event.parts();
3450                 (ordinal, handle, result)
3451             }
3452             WaitableCheck::Poll => {
3453                 if let Some((event, waitable)) = event {
3454                     let handle = waitable.map(|(_, v)| v).unwrap_or(0);
3455                     let (ordinal, result) = event.parts();
3456                     (ordinal, handle, result)
3457                 } else {
3458                     log::trace!(
3459                         "no events ready to deliver via waitable-set.poll to {:?}; set {:?}",
3460                         guest_thread.task,
3461                         params.set
3462                     );
3463                     let (ordinal, result) = Event::None.parts();
3464                     (ordinal, 0, result)
3465                 }
3466             }
3467         };
3468         let memory = self.options_memory_mut(store, params.options);
3469         let ptr = func::validate_inbounds_dynamic(
3470             &CanonicalAbiInfo::POINTER_PAIR,
3471             memory,
3472             &ValRaw::u32(params.payload),
3473         )?;
3474         memory[ptr + 0..][..4].copy_from_slice(&handle.to_le_bytes());
3475         memory[ptr + 4..][..4].copy_from_slice(&result.to_le_bytes());
3476         Ok(ordinal)
3477     }
3478 
3479     /// Implements the `subtask.cancel` intrinsic.
3480     pub(crate) fn subtask_cancel(
3481         self,
3482         store: &mut StoreOpaque,
3483         caller_instance: RuntimeComponentInstanceIndex,
3484         async_: bool,
3485         task_id: u32,
3486     ) -> Result<u32> {
3487         if !async_ {
3488             // The caller may only sync call `subtask.cancel` from an async task
3489             // (i.e. a task created via a call to an async export).  Otherwise,
3490             // we'll trap.
3491             store.check_blocking()?;
3492         }
3493 
3494         let (rep, is_host) = store
3495             .instance_state(RuntimeInstance {
3496                 instance: self.id().instance(),
3497                 index: caller_instance,
3498             })
3499             .handle_table()
3500             .subtask_rep(task_id)?;
3501         let (waitable, expected_caller) = if is_host {
3502             let id = TableId::<HostTask>::new(rep);
3503             (
3504                 Waitable::Host(id),
3505                 store.concurrent_state_mut().get_mut(id)?.caller,
3506             )
3507         } else {
3508             let id = TableId::<GuestTask>::new(rep);
3509             if let Caller::Guest { thread } = store.concurrent_state_mut().get_mut(id)?.caller {
3510                 (Waitable::Guest(id), thread)
3511             } else {
3512                 unreachable!()
3513             }
3514         };
3515         // Since waitables can neither be passed between instances nor forged,
3516         // this should never fail unless there's a bug in Wasmtime, but we check
3517         // here to be sure:
3518         let concurrent_state = store.concurrent_state_mut();
3519         assert_eq!(
3520             expected_caller,
3521             concurrent_state.unwrap_current_guest_thread(),
3522         );
3523 
3524         log::trace!("subtask_cancel {waitable:?} (handle {task_id})");
3525 
3526         let needs_block;
3527         if let Waitable::Host(host_task) = waitable {
3528             let state = &mut concurrent_state.get_mut(host_task)?.state;
3529             match mem::replace(state, HostTaskState::CalleeDone) {
3530                 // If the callee is still running, signal an abort is requested.
3531                 // Then fall through to determine what to do next.
3532                 HostTaskState::CalleeRunning(handle) => handle.abort(),
3533 
3534                 // Cancellation was already requested, so fail as the task can't
3535                 // be cancelled twice.
3536                 HostTaskState::CalleeDone => {
3537                     bail!("`subtask.cancel` called after terminal status delivered");
3538                 }
3539 
3540                 // These states should not be possible for a subtask that's
3541                 // visible from the guest, so panic here.
3542                 HostTaskState::CalleeStarted | HostTaskState::CalleeFinished(_) => unreachable!(),
3543             }
3544 
3545             // Cancelling host tasks always needs to block on them to await the
3546             // result of the completion set up in `first_poll`. This'll resolve
3547             // the race of `handle.abort()` above to see if it actually
3548             // cancelled something or if the future ended up finishing.
3549             needs_block = true;
3550         } else {
3551             let caller = concurrent_state.unwrap_current_guest_thread();
3552             let guest_task = TableId::<GuestTask>::new(rep);
3553             let task = concurrent_state.get_mut(guest_task)?;
3554             if !task.already_lowered_parameters() {
3555                 // The task is in a `starting` state, meaning it hasn't run at
3556                 // all yet.  Here we update its fields to indicate that it is
3557                 // ready to delete immediately once `subtask.drop` is called.
3558                 task.lower_params = None;
3559                 task.lift_result = None;
3560                 task.exited = true;
3561 
3562                 let instance = task.instance;
3563 
3564                 assert_eq!(1, task.threads.len());
3565                 let thread = mem::take(&mut task.threads).into_iter().next().unwrap();
3566                 let concurrent_state = store.concurrent_state_mut();
3567                 concurrent_state.delete(thread)?;
3568                 assert!(concurrent_state.get_mut(guest_task)?.ready_to_delete());
3569 
3570                 // Not yet started; cancel and remove from pending
3571                 let pending = &mut store.instance_state(instance).concurrent_state().pending;
3572                 let pending_count = pending.len();
3573                 pending.retain(|thread, _| thread.task != guest_task);
3574                 // If there were no pending threads for this task, we're in an error state
3575                 if pending.len() == pending_count {
3576                     bail!("`subtask.cancel` called after terminal status delivered");
3577                 }
3578                 return Ok(Status::StartCancelled as u32);
3579             } else if !task.returned_or_cancelled() {
3580                 // Started, but not yet returned or cancelled; send the
3581                 // `CANCELLED` event
3582                 task.cancel_sent = true;
3583                 // Note that this might overwrite an event that was set earlier
3584                 // (e.g. `Event::None` if the task is yielding, or
3585                 // `Event::Cancelled` if it was already cancelled), but that's
3586                 // okay -- this should supersede the previous state.
3587                 task.event = Some(Event::Cancelled);
3588                 let runtime_instance = task.instance.index;
3589                 for thread in task.threads.clone() {
3590                     let thread = QualifiedThreadId {
3591                         task: guest_task,
3592                         thread,
3593                     };
3594                     if let Some(set) = concurrent_state
3595                         .get_mut(thread.thread)
3596                         .unwrap()
3597                         .wake_on_cancel
3598                         .take()
3599                     {
3600                         let item = match concurrent_state
3601                             .get_mut(set)?
3602                             .waiting
3603                             .remove(&thread)
3604                             .unwrap()
3605                         {
3606                             WaitMode::Fiber(fiber) => WorkItem::ResumeFiber(fiber),
3607                             WaitMode::Callback(instance) => WorkItem::GuestCall(
3608                                 runtime_instance,
3609                                 GuestCall {
3610                                     thread,
3611                                     kind: GuestCallKind::DeliverEvent {
3612                                         instance,
3613                                         set: None,
3614                                     },
3615                                 },
3616                             ),
3617                         };
3618                         concurrent_state.push_high_priority(item);
3619 
3620                         store.suspend(SuspendReason::Yielding {
3621                             thread: caller,
3622                             // `subtask.cancel` is not allowed to be called in a
3623                             // sync context, so we cannot skip the may-block check.
3624                             skip_may_block_check: false,
3625                         })?;
3626                         break;
3627                     }
3628                 }
3629 
3630                 // Guest tasks need to block if they have not yet returned or
3631                 // cancelled, even as a result of the event delivery above.
3632                 needs_block = !store
3633                     .concurrent_state_mut()
3634                     .get_mut(guest_task)?
3635                     .returned_or_cancelled()
3636             } else {
3637                 needs_block = false;
3638             }
3639         };
3640 
3641         // If we need to block waiting on the terminal status of this subtask
3642         // then return immediately in `async` mode, or otherwise wait for the
3643         // event to get signaled through the store.
3644         if needs_block {
3645             if async_ {
3646                 return Ok(BLOCKED);
3647             }
3648 
3649             // Wait for this waitable to get signaled with its terminal status
3650             // from the completion callback enqueued by `first_poll`. Once
3651             // that's done fall through to the sahred
3652             store.wait_for_event(waitable)?;
3653 
3654             // .. fall through to determine what event's in store for us.
3655         }
3656 
3657         let event = waitable.take_event(store.concurrent_state_mut())?;
3658         if let Some(Event::Subtask {
3659             status: status @ (Status::Returned | Status::ReturnCancelled),
3660         }) = event
3661         {
3662             Ok(status as u32)
3663         } else {
3664             bail!("`subtask.cancel` called after terminal status delivered");
3665         }
3666     }
3667 
3668     pub(crate) fn context_get(self, store: &mut StoreOpaque, slot: u32) -> Result<u32> {
3669         store.concurrent_state_mut().context_get(slot)
3670     }
3671 
3672     pub(crate) fn context_set(self, store: &mut StoreOpaque, slot: u32, value: u32) -> Result<()> {
3673         store.concurrent_state_mut().context_set(slot, value)
3674     }
3675 }
3676 
3677 /// Trait representing component model ABI async intrinsics and fused adapter
3678 /// helper functions.
3679 ///
3680 /// SAFETY (callers): Most of the methods in this trait accept raw pointers,
3681 /// which must be valid for at least the duration of the call (and possibly for
3682 /// as long as the relevant guest task exists, in the case of `*mut VMFuncRef`
3683 /// pointers used for async calls).
3684 pub trait VMComponentAsyncStore {
3685     /// A helper function for fused adapter modules involving calls where the
3686     /// one of the caller or callee is async.
3687     ///
3688     /// This helper is not used when the caller and callee both use the sync
3689     /// ABI, only when at least one is async is this used.
3690     unsafe fn prepare_call(
3691         &mut self,
3692         instance: Instance,
3693         memory: *mut VMMemoryDefinition,
3694         start: *mut VMFuncRef,
3695         return_: *mut VMFuncRef,
3696         caller_instance: RuntimeComponentInstanceIndex,
3697         callee_instance: RuntimeComponentInstanceIndex,
3698         task_return_type: TypeTupleIndex,
3699         callee_async: bool,
3700         string_encoding: u8,
3701         result_count: u32,
3702         storage: *mut ValRaw,
3703         storage_len: usize,
3704     ) -> Result<()>;
3705 
3706     /// A helper function for fused adapter modules involving calls where the
3707     /// caller is sync-lowered but the callee is async-lifted.
3708     unsafe fn sync_start(
3709         &mut self,
3710         instance: Instance,
3711         callback: *mut VMFuncRef,
3712         callee: *mut VMFuncRef,
3713         param_count: u32,
3714         storage: *mut MaybeUninit<ValRaw>,
3715         storage_len: usize,
3716     ) -> Result<()>;
3717 
3718     /// A helper function for fused adapter modules involving calls where the
3719     /// caller is async-lowered.
3720     unsafe fn async_start(
3721         &mut self,
3722         instance: Instance,
3723         callback: *mut VMFuncRef,
3724         post_return: *mut VMFuncRef,
3725         callee: *mut VMFuncRef,
3726         param_count: u32,
3727         result_count: u32,
3728         flags: u32,
3729     ) -> Result<u32>;
3730 
3731     /// The `future.write` intrinsic.
3732     fn future_write(
3733         &mut self,
3734         instance: Instance,
3735         caller: RuntimeComponentInstanceIndex,
3736         ty: TypeFutureTableIndex,
3737         options: OptionsIndex,
3738         future: u32,
3739         address: u32,
3740     ) -> Result<u32>;
3741 
3742     /// The `future.read` intrinsic.
3743     fn future_read(
3744         &mut self,
3745         instance: Instance,
3746         caller: RuntimeComponentInstanceIndex,
3747         ty: TypeFutureTableIndex,
3748         options: OptionsIndex,
3749         future: u32,
3750         address: u32,
3751     ) -> Result<u32>;
3752 
3753     /// The `future.drop-writable` intrinsic.
3754     fn future_drop_writable(
3755         &mut self,
3756         instance: Instance,
3757         ty: TypeFutureTableIndex,
3758         writer: u32,
3759     ) -> Result<()>;
3760 
3761     /// The `stream.write` intrinsic.
3762     fn stream_write(
3763         &mut self,
3764         instance: Instance,
3765         caller: RuntimeComponentInstanceIndex,
3766         ty: TypeStreamTableIndex,
3767         options: OptionsIndex,
3768         stream: u32,
3769         address: u32,
3770         count: u32,
3771     ) -> Result<u32>;
3772 
3773     /// The `stream.read` intrinsic.
3774     fn stream_read(
3775         &mut self,
3776         instance: Instance,
3777         caller: RuntimeComponentInstanceIndex,
3778         ty: TypeStreamTableIndex,
3779         options: OptionsIndex,
3780         stream: u32,
3781         address: u32,
3782         count: u32,
3783     ) -> Result<u32>;
3784 
3785     /// The "fast-path" implementation of the `stream.write` intrinsic for
3786     /// "flat" (i.e. memcpy-able) payloads.
3787     fn flat_stream_write(
3788         &mut self,
3789         instance: Instance,
3790         caller: RuntimeComponentInstanceIndex,
3791         ty: TypeStreamTableIndex,
3792         options: OptionsIndex,
3793         payload_size: u32,
3794         payload_align: u32,
3795         stream: u32,
3796         address: u32,
3797         count: u32,
3798     ) -> Result<u32>;
3799 
3800     /// The "fast-path" implementation of the `stream.read` intrinsic for "flat"
3801     /// (i.e. memcpy-able) payloads.
3802     fn flat_stream_read(
3803         &mut self,
3804         instance: Instance,
3805         caller: RuntimeComponentInstanceIndex,
3806         ty: TypeStreamTableIndex,
3807         options: OptionsIndex,
3808         payload_size: u32,
3809         payload_align: u32,
3810         stream: u32,
3811         address: u32,
3812         count: u32,
3813     ) -> Result<u32>;
3814 
3815     /// The `stream.drop-writable` intrinsic.
3816     fn stream_drop_writable(
3817         &mut self,
3818         instance: Instance,
3819         ty: TypeStreamTableIndex,
3820         writer: u32,
3821     ) -> Result<()>;
3822 
3823     /// The `error-context.debug-message` intrinsic.
3824     fn error_context_debug_message(
3825         &mut self,
3826         instance: Instance,
3827         ty: TypeComponentLocalErrorContextTableIndex,
3828         options: OptionsIndex,
3829         err_ctx_handle: u32,
3830         debug_msg_address: u32,
3831     ) -> Result<()>;
3832 
3833     /// The `thread.new-indirect` intrinsic
3834     fn thread_new_indirect(
3835         &mut self,
3836         instance: Instance,
3837         caller: RuntimeComponentInstanceIndex,
3838         func_ty_idx: TypeFuncIndex,
3839         start_func_table_idx: RuntimeTableIndex,
3840         start_func_idx: u32,
3841         context: i32,
3842     ) -> Result<u32>;
3843 }
3844 
3845 /// SAFETY: See trait docs.
3846 impl<T: 'static> VMComponentAsyncStore for StoreInner<T> {
3847     unsafe fn prepare_call(
3848         &mut self,
3849         instance: Instance,
3850         memory: *mut VMMemoryDefinition,
3851         start: *mut VMFuncRef,
3852         return_: *mut VMFuncRef,
3853         caller_instance: RuntimeComponentInstanceIndex,
3854         callee_instance: RuntimeComponentInstanceIndex,
3855         task_return_type: TypeTupleIndex,
3856         callee_async: bool,
3857         string_encoding: u8,
3858         result_count_or_max_if_async: u32,
3859         storage: *mut ValRaw,
3860         storage_len: usize,
3861     ) -> Result<()> {
3862         // SAFETY: The `wasmtime_cranelift`-generated code that calls
3863         // this method will have ensured that `storage` is a valid
3864         // pointer containing at least `storage_len` items.
3865         let params = unsafe { std::slice::from_raw_parts(storage, storage_len) }.to_vec();
3866 
3867         unsafe {
3868             instance.prepare_call(
3869                 StoreContextMut(self),
3870                 start,
3871                 return_,
3872                 caller_instance,
3873                 callee_instance,
3874                 task_return_type,
3875                 callee_async,
3876                 memory,
3877                 string_encoding,
3878                 match result_count_or_max_if_async {
3879                     PREPARE_ASYNC_NO_RESULT => CallerInfo::Async {
3880                         params,
3881                         has_result: false,
3882                     },
3883                     PREPARE_ASYNC_WITH_RESULT => CallerInfo::Async {
3884                         params,
3885                         has_result: true,
3886                     },
3887                     result_count => CallerInfo::Sync {
3888                         params,
3889                         result_count,
3890                     },
3891                 },
3892             )
3893         }
3894     }
3895 
3896     unsafe fn sync_start(
3897         &mut self,
3898         instance: Instance,
3899         callback: *mut VMFuncRef,
3900         callee: *mut VMFuncRef,
3901         param_count: u32,
3902         storage: *mut MaybeUninit<ValRaw>,
3903         storage_len: usize,
3904     ) -> Result<()> {
3905         unsafe {
3906             instance
3907                 .start_call(
3908                     StoreContextMut(self),
3909                     callback,
3910                     ptr::null_mut(),
3911                     callee,
3912                     param_count,
3913                     1,
3914                     START_FLAG_ASYNC_CALLEE,
3915                     // SAFETY: The `wasmtime_cranelift`-generated code that calls
3916                     // this method will have ensured that `storage` is a valid
3917                     // pointer containing at least `storage_len` items.
3918                     Some(std::slice::from_raw_parts_mut(storage, storage_len)),
3919                 )
3920                 .map(drop)
3921         }
3922     }
3923 
3924     unsafe fn async_start(
3925         &mut self,
3926         instance: Instance,
3927         callback: *mut VMFuncRef,
3928         post_return: *mut VMFuncRef,
3929         callee: *mut VMFuncRef,
3930         param_count: u32,
3931         result_count: u32,
3932         flags: u32,
3933     ) -> Result<u32> {
3934         unsafe {
3935             instance.start_call(
3936                 StoreContextMut(self),
3937                 callback,
3938                 post_return,
3939                 callee,
3940                 param_count,
3941                 result_count,
3942                 flags,
3943                 None,
3944             )
3945         }
3946     }
3947 
3948     fn future_write(
3949         &mut self,
3950         instance: Instance,
3951         caller: RuntimeComponentInstanceIndex,
3952         ty: TypeFutureTableIndex,
3953         options: OptionsIndex,
3954         future: u32,
3955         address: u32,
3956     ) -> Result<u32> {
3957         instance
3958             .guest_write(
3959                 StoreContextMut(self),
3960                 caller,
3961                 TransmitIndex::Future(ty),
3962                 options,
3963                 None,
3964                 future,
3965                 address,
3966                 1,
3967             )
3968             .map(|result| result.encode())
3969     }
3970 
3971     fn future_read(
3972         &mut self,
3973         instance: Instance,
3974         caller: RuntimeComponentInstanceIndex,
3975         ty: TypeFutureTableIndex,
3976         options: OptionsIndex,
3977         future: u32,
3978         address: u32,
3979     ) -> Result<u32> {
3980         instance
3981             .guest_read(
3982                 StoreContextMut(self),
3983                 caller,
3984                 TransmitIndex::Future(ty),
3985                 options,
3986                 None,
3987                 future,
3988                 address,
3989                 1,
3990             )
3991             .map(|result| result.encode())
3992     }
3993 
3994     fn stream_write(
3995         &mut self,
3996         instance: Instance,
3997         caller: RuntimeComponentInstanceIndex,
3998         ty: TypeStreamTableIndex,
3999         options: OptionsIndex,
4000         stream: u32,
4001         address: u32,
4002         count: u32,
4003     ) -> Result<u32> {
4004         instance
4005             .guest_write(
4006                 StoreContextMut(self),
4007                 caller,
4008                 TransmitIndex::Stream(ty),
4009                 options,
4010                 None,
4011                 stream,
4012                 address,
4013                 count,
4014             )
4015             .map(|result| result.encode())
4016     }
4017 
4018     fn stream_read(
4019         &mut self,
4020         instance: Instance,
4021         caller: RuntimeComponentInstanceIndex,
4022         ty: TypeStreamTableIndex,
4023         options: OptionsIndex,
4024         stream: u32,
4025         address: u32,
4026         count: u32,
4027     ) -> Result<u32> {
4028         instance
4029             .guest_read(
4030                 StoreContextMut(self),
4031                 caller,
4032                 TransmitIndex::Stream(ty),
4033                 options,
4034                 None,
4035                 stream,
4036                 address,
4037                 count,
4038             )
4039             .map(|result| result.encode())
4040     }
4041 
4042     fn future_drop_writable(
4043         &mut self,
4044         instance: Instance,
4045         ty: TypeFutureTableIndex,
4046         writer: u32,
4047     ) -> Result<()> {
4048         instance.guest_drop_writable(self, TransmitIndex::Future(ty), writer)
4049     }
4050 
4051     fn flat_stream_write(
4052         &mut self,
4053         instance: Instance,
4054         caller: RuntimeComponentInstanceIndex,
4055         ty: TypeStreamTableIndex,
4056         options: OptionsIndex,
4057         payload_size: u32,
4058         payload_align: u32,
4059         stream: u32,
4060         address: u32,
4061         count: u32,
4062     ) -> Result<u32> {
4063         instance
4064             .guest_write(
4065                 StoreContextMut(self),
4066                 caller,
4067                 TransmitIndex::Stream(ty),
4068                 options,
4069                 Some(FlatAbi {
4070                     size: payload_size,
4071                     align: payload_align,
4072                 }),
4073                 stream,
4074                 address,
4075                 count,
4076             )
4077             .map(|result| result.encode())
4078     }
4079 
4080     fn flat_stream_read(
4081         &mut self,
4082         instance: Instance,
4083         caller: RuntimeComponentInstanceIndex,
4084         ty: TypeStreamTableIndex,
4085         options: OptionsIndex,
4086         payload_size: u32,
4087         payload_align: u32,
4088         stream: u32,
4089         address: u32,
4090         count: u32,
4091     ) -> Result<u32> {
4092         instance
4093             .guest_read(
4094                 StoreContextMut(self),
4095                 caller,
4096                 TransmitIndex::Stream(ty),
4097                 options,
4098                 Some(FlatAbi {
4099                     size: payload_size,
4100                     align: payload_align,
4101                 }),
4102                 stream,
4103                 address,
4104                 count,
4105             )
4106             .map(|result| result.encode())
4107     }
4108 
4109     fn stream_drop_writable(
4110         &mut self,
4111         instance: Instance,
4112         ty: TypeStreamTableIndex,
4113         writer: u32,
4114     ) -> Result<()> {
4115         instance.guest_drop_writable(self, TransmitIndex::Stream(ty), writer)
4116     }
4117 
4118     fn error_context_debug_message(
4119         &mut self,
4120         instance: Instance,
4121         ty: TypeComponentLocalErrorContextTableIndex,
4122         options: OptionsIndex,
4123         err_ctx_handle: u32,
4124         debug_msg_address: u32,
4125     ) -> Result<()> {
4126         instance.error_context_debug_message(
4127             StoreContextMut(self),
4128             ty,
4129             options,
4130             err_ctx_handle,
4131             debug_msg_address,
4132         )
4133     }
4134 
4135     fn thread_new_indirect(
4136         &mut self,
4137         instance: Instance,
4138         caller: RuntimeComponentInstanceIndex,
4139         func_ty_idx: TypeFuncIndex,
4140         start_func_table_idx: RuntimeTableIndex,
4141         start_func_idx: u32,
4142         context: i32,
4143     ) -> Result<u32> {
4144         instance.thread_new_indirect(
4145             StoreContextMut(self),
4146             caller,
4147             func_ty_idx,
4148             start_func_table_idx,
4149             start_func_idx,
4150             context,
4151         )
4152     }
4153 }
4154 
4155 type HostTaskFuture = Pin<Box<dyn Future<Output = Result<()>> + Send + 'static>>;
4156 
4157 /// Represents the state of a pending host task.
4158 ///
4159 /// This is used to represent tasks when the guest calls into the host.
4160 struct HostTask {
4161     common: WaitableCommon,
4162 
4163     /// Guest thread which called the host.
4164     caller: QualifiedThreadId,
4165 
4166     /// State of borrows/etc the host needs to track. Used when the guest passes
4167     /// borrows to the host, for example.
4168     call_context: CallContext,
4169 
4170     state: HostTaskState,
4171 }
4172 
4173 enum HostTaskState {
4174     /// A host task has been created and it's considered "started".
4175     ///
4176     /// The host task has yet to enter `first_poll` or `poll_and_block` which
4177     /// is where this will get updated further.
4178     CalleeStarted,
4179 
4180     /// State used for tasks in `first_poll` meaning that the guest did an async
4181     /// lower of a host async function which is blocked. The specified handle is
4182     /// linked to the future in the main `FuturesUnordered` of a store which is
4183     /// used to cancel it if the guest requests cancellation.
4184     CalleeRunning(JoinHandle),
4185 
4186     /// Terminal state used for tasks in `poll_and_block` to store the result of
4187     /// their computation. Note that this state is not used for tasks in
4188     /// `first_poll`.
4189     CalleeFinished(LiftedResult),
4190 
4191     /// Terminal state for host tasks meaning that the task was cancelled or the
4192     /// result was taken.
4193     CalleeDone,
4194 }
4195 
4196 impl HostTask {
4197     fn new(caller: QualifiedThreadId, state: HostTaskState) -> Self {
4198         Self {
4199             common: WaitableCommon::default(),
4200             call_context: CallContext::default(),
4201             caller,
4202             state,
4203         }
4204     }
4205 }
4206 
4207 impl TableDebug for HostTask {
4208     fn type_name() -> &'static str {
4209         "HostTask"
4210     }
4211 }
4212 
4213 type CallbackFn = Box<dyn Fn(&mut dyn VMStore, Event, u32) -> Result<u32> + Send + Sync + 'static>;
4214 
4215 /// Represents the caller of a given guest task.
4216 enum Caller {
4217     /// The host called the guest task.
4218     Host {
4219         /// If present, may be used to deliver the result.
4220         tx: Option<oneshot::Sender<LiftedResult>>,
4221         /// If true, there's a host future that must be dropped before the task
4222         /// can be deleted.
4223         host_future_present: bool,
4224         /// Represents the caller of the host function which called back into a
4225         /// guest. Note that this thread could belong to an entirely unrelated
4226         /// top-level component instance than the one the host called into.
4227         caller: CurrentThread,
4228     },
4229     /// Another guest thread called the guest task
4230     Guest {
4231         /// The id of the caller
4232         thread: QualifiedThreadId,
4233     },
4234 }
4235 
4236 /// Represents a closure and related canonical ABI parameters required to
4237 /// validate a `task.return` call at runtime and lift the result.
4238 struct LiftResult {
4239     lift: RawLift,
4240     ty: TypeTupleIndex,
4241     memory: Option<SendSyncPtr<VMMemoryDefinition>>,
4242     string_encoding: StringEncoding,
4243 }
4244 
4245 /// The table ID for a guest thread, qualified by the task to which it belongs.
4246 ///
4247 /// This exists to minimize table lookups and the necessity to pass stores around mutably
4248 /// for the common case of identifying the task to which a thread belongs.
4249 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
4250 struct QualifiedThreadId {
4251     task: TableId<GuestTask>,
4252     thread: TableId<GuestThread>,
4253 }
4254 
4255 impl QualifiedThreadId {
4256     fn qualify(
4257         state: &mut ConcurrentState,
4258         thread: TableId<GuestThread>,
4259     ) -> Result<QualifiedThreadId> {
4260         Ok(QualifiedThreadId {
4261             task: state.get_mut(thread)?.parent_task,
4262             thread,
4263         })
4264     }
4265 }
4266 
4267 impl fmt::Debug for QualifiedThreadId {
4268     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4269         f.debug_tuple("QualifiedThreadId")
4270             .field(&self.task.rep())
4271             .field(&self.thread.rep())
4272             .finish()
4273     }
4274 }
4275 
4276 enum GuestThreadState {
4277     NotStartedImplicit,
4278     NotStartedExplicit(
4279         Box<dyn FnOnce(&mut dyn VMStore, QualifiedThreadId) -> Result<()> + Send + Sync>,
4280     ),
4281     Running,
4282     Suspended(StoreFiber<'static>),
4283     Ready(StoreFiber<'static>),
4284     Completed,
4285 }
4286 pub struct GuestThread {
4287     /// Context-local state used to implement the `context.{get,set}`
4288     /// intrinsics.
4289     context: [u32; 2],
4290     /// The owning guest task.
4291     parent_task: TableId<GuestTask>,
4292     /// If present, indicates that the thread is currently waiting on the
4293     /// specified set but may be cancelled and woken immediately.
4294     wake_on_cancel: Option<TableId<WaitableSet>>,
4295     /// The execution state of this guest thread
4296     state: GuestThreadState,
4297     /// The index of this thread in the component instance's handle table.
4298     /// This must always be `Some` after initialization.
4299     instance_rep: Option<u32>,
4300 }
4301 
4302 impl GuestThread {
4303     /// Retrieve the `GuestThread` corresponding to the specified guest-visible
4304     /// handle.
4305     fn from_instance(
4306         state: Pin<&mut ComponentInstance>,
4307         caller_instance: RuntimeComponentInstanceIndex,
4308         guest_thread: u32,
4309     ) -> Result<TableId<Self>> {
4310         let rep = state.instance_states().0[caller_instance]
4311             .thread_handle_table()
4312             .guest_thread_rep(guest_thread)?;
4313         Ok(TableId::new(rep))
4314     }
4315 
4316     fn new_implicit(parent_task: TableId<GuestTask>) -> Self {
4317         Self {
4318             context: [0; 2],
4319             parent_task,
4320             wake_on_cancel: None,
4321             state: GuestThreadState::NotStartedImplicit,
4322             instance_rep: None,
4323         }
4324     }
4325 
4326     fn new_explicit(
4327         parent_task: TableId<GuestTask>,
4328         start_func: Box<
4329             dyn FnOnce(&mut dyn VMStore, QualifiedThreadId) -> Result<()> + Send + Sync,
4330         >,
4331     ) -> Self {
4332         Self {
4333             context: [0; 2],
4334             parent_task,
4335             wake_on_cancel: None,
4336             state: GuestThreadState::NotStartedExplicit(start_func),
4337             instance_rep: None,
4338         }
4339     }
4340 }
4341 
4342 impl TableDebug for GuestThread {
4343     fn type_name() -> &'static str {
4344         "GuestThread"
4345     }
4346 }
4347 
4348 enum SyncResult {
4349     NotProduced,
4350     Produced(Option<ValRaw>),
4351     Taken,
4352 }
4353 
4354 impl SyncResult {
4355     fn take(&mut self) -> Option<Option<ValRaw>> {
4356         match mem::replace(self, SyncResult::Taken) {
4357             SyncResult::NotProduced => None,
4358             SyncResult::Produced(val) => Some(val),
4359             SyncResult::Taken => {
4360                 panic!("attempted to take a synchronous result that was already taken")
4361             }
4362         }
4363     }
4364 }
4365 
4366 #[derive(Debug)]
4367 enum HostFutureState {
4368     NotApplicable,
4369     Live,
4370     Dropped,
4371 }
4372 
4373 /// Represents a pending guest task.
4374 pub(crate) struct GuestTask {
4375     /// See `WaitableCommon`
4376     common: WaitableCommon,
4377     /// Closure to lower the parameters passed to this task.
4378     lower_params: Option<RawLower>,
4379     /// See `LiftResult`
4380     lift_result: Option<LiftResult>,
4381     /// A place to stash the type-erased lifted result if it can't be delivered
4382     /// immediately.
4383     result: Option<LiftedResult>,
4384     /// Closure to call the callback function for an async-lifted export, if
4385     /// provided.
4386     callback: Option<CallbackFn>,
4387     /// See `Caller`
4388     caller: Caller,
4389     /// Borrow state for this task.
4390     ///
4391     /// Keeps track of `borrow<T>` received to this task to ensure that
4392     /// everything is dropped by the time it exits.
4393     call_context: CallContext,
4394     /// A place to stash the lowered result for a sync-to-async call until it
4395     /// can be returned to the caller.
4396     sync_result: SyncResult,
4397     /// Whether or not the task has been cancelled (i.e. whether the task is
4398     /// permitted to call `task.cancel`).
4399     cancel_sent: bool,
4400     /// Whether or not we've sent a `Status::Starting` event to any current or
4401     /// future waiters for this waitable.
4402     starting_sent: bool,
4403     /// Scratch waitable set used to watch subtasks during synchronous calls.
4404     sync_call_set: TableId<WaitableSet>,
4405     /// The runtime instance to which the exported function for this guest task
4406     /// belongs.
4407     ///
4408     /// Note that the task may do a sync->sync call via a fused adapter which
4409     /// results in that task executing code in a different instance, and it may
4410     /// call host functions and intrinsics from that other instance.
4411     instance: RuntimeInstance,
4412     /// If present, a pending `Event::None` or `Event::Cancelled` to be
4413     /// delivered to this task.
4414     event: Option<Event>,
4415     /// Whether or not the task has exited.
4416     exited: bool,
4417     /// Threads belonging to this task
4418     threads: HashSet<TableId<GuestThread>>,
4419     /// The state of the host future that represents an async task, which must
4420     /// be dropped before we can delete the task.
4421     host_future_state: HostFutureState,
4422     /// Indicates whether this task was created for a call to an async-lifted
4423     /// export.
4424     async_function: bool,
4425 }
4426 
4427 impl GuestTask {
4428     fn already_lowered_parameters(&self) -> bool {
4429         // We reset `lower_params` after we lower the parameters
4430         self.lower_params.is_none()
4431     }
4432 
4433     fn returned_or_cancelled(&self) -> bool {
4434         // We reset `lift_result` after we return or exit
4435         self.lift_result.is_none()
4436     }
4437 
4438     fn ready_to_delete(&self) -> bool {
4439         let threads_completed = self.threads.is_empty();
4440         let has_sync_result = matches!(self.sync_result, SyncResult::Produced(_));
4441         let pending_completion_event = matches!(
4442             self.common.event,
4443             Some(Event::Subtask {
4444                 status: Status::Returned | Status::ReturnCancelled
4445             })
4446         );
4447         let ready = threads_completed
4448             && !has_sync_result
4449             && !pending_completion_event
4450             && !matches!(self.host_future_state, HostFutureState::Live);
4451         log::trace!(
4452             "ready to delete? {ready} (threads_completed: {}, has_sync_result: {}, pending_completion_event: {}, host_future_state: {:?})",
4453             threads_completed,
4454             has_sync_result,
4455             pending_completion_event,
4456             self.host_future_state
4457         );
4458         ready
4459     }
4460 
4461     fn new(
4462         state: &mut ConcurrentState,
4463         lower_params: RawLower,
4464         lift_result: LiftResult,
4465         caller: Caller,
4466         callback: Option<CallbackFn>,
4467         instance: RuntimeInstance,
4468         async_function: bool,
4469     ) -> Result<Self> {
4470         let sync_call_set = state.push(WaitableSet::default())?;
4471         let host_future_state = match &caller {
4472             Caller::Guest { .. } => HostFutureState::NotApplicable,
4473             Caller::Host {
4474                 host_future_present,
4475                 ..
4476             } => {
4477                 if *host_future_present {
4478                     HostFutureState::Live
4479                 } else {
4480                     HostFutureState::NotApplicable
4481                 }
4482             }
4483         };
4484         Ok(Self {
4485             common: WaitableCommon::default(),
4486             lower_params: Some(lower_params),
4487             lift_result: Some(lift_result),
4488             result: None,
4489             callback,
4490             caller,
4491             call_context: CallContext::default(),
4492             sync_result: SyncResult::NotProduced,
4493             cancel_sent: false,
4494             starting_sent: false,
4495             sync_call_set,
4496             instance,
4497             event: None,
4498             exited: false,
4499             threads: HashSet::new(),
4500             host_future_state,
4501             async_function,
4502         })
4503     }
4504 
4505     /// Dispose of this guest task, reparenting any pending subtasks to the
4506     /// caller.
4507     fn dispose(self, state: &mut ConcurrentState) -> Result<()> {
4508         // If there are not-yet-delivered completion events for subtasks in
4509         // `self.sync_call_set`, recursively dispose of those subtasks as well.
4510         for waitable in mem::take(&mut state.get_mut(self.sync_call_set)?.ready) {
4511             if let Some(Event::Subtask {
4512                 status: Status::Returned | Status::ReturnCancelled,
4513             }) = waitable.common(state)?.event
4514             {
4515                 waitable.delete_from(state)?;
4516             }
4517         }
4518 
4519         assert!(self.threads.is_empty());
4520 
4521         state.delete(self.sync_call_set)?;
4522 
4523         Ok(())
4524     }
4525 }
4526 
4527 impl TableDebug for GuestTask {
4528     fn type_name() -> &'static str {
4529         "GuestTask"
4530     }
4531 }
4532 
4533 /// Represents state common to all kinds of waitables.
4534 #[derive(Default)]
4535 struct WaitableCommon {
4536     /// The currently pending event for this waitable, if any.
4537     event: Option<Event>,
4538     /// The set to which this waitable belongs, if any.
4539     set: Option<TableId<WaitableSet>>,
4540     /// The handle with which the guest refers to this waitable, if any.
4541     handle: Option<u32>,
4542 }
4543 
4544 /// Represents a Component Model Async `waitable`.
4545 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
4546 enum Waitable {
4547     /// A host task
4548     Host(TableId<HostTask>),
4549     /// A guest task
4550     Guest(TableId<GuestTask>),
4551     /// The read or write end of a stream or future
4552     Transmit(TableId<TransmitHandle>),
4553 }
4554 
4555 impl Waitable {
4556     /// Retrieve the `Waitable` corresponding to the specified guest-visible
4557     /// handle.
4558     fn from_instance(
4559         state: Pin<&mut ComponentInstance>,
4560         caller_instance: RuntimeComponentInstanceIndex,
4561         waitable: u32,
4562     ) -> Result<Self> {
4563         use crate::runtime::vm::component::Waitable;
4564 
4565         let (waitable, kind) = state.instance_states().0[caller_instance]
4566             .handle_table()
4567             .waitable_rep(waitable)?;
4568 
4569         Ok(match kind {
4570             Waitable::Subtask { is_host: true } => Self::Host(TableId::new(waitable)),
4571             Waitable::Subtask { is_host: false } => Self::Guest(TableId::new(waitable)),
4572             Waitable::Stream | Waitable::Future => Self::Transmit(TableId::new(waitable)),
4573         })
4574     }
4575 
4576     /// Retrieve the host-visible identifier for this `Waitable`.
4577     fn rep(&self) -> u32 {
4578         match self {
4579             Self::Host(id) => id.rep(),
4580             Self::Guest(id) => id.rep(),
4581             Self::Transmit(id) => id.rep(),
4582         }
4583     }
4584 
4585     /// Move this `Waitable` to the specified set (when `set` is `Some(_)`) or
4586     /// remove it from any set it may currently belong to (when `set` is
4587     /// `None`).
4588     fn join(&self, state: &mut ConcurrentState, set: Option<TableId<WaitableSet>>) -> Result<()> {
4589         log::trace!("waitable {self:?} join set {set:?}",);
4590 
4591         let old = mem::replace(&mut self.common(state)?.set, set);
4592 
4593         if let Some(old) = old {
4594             match *self {
4595                 Waitable::Host(id) => state.remove_child(id, old),
4596                 Waitable::Guest(id) => state.remove_child(id, old),
4597                 Waitable::Transmit(id) => state.remove_child(id, old),
4598             }?;
4599 
4600             state.get_mut(old)?.ready.remove(self);
4601         }
4602 
4603         if let Some(set) = set {
4604             match *self {
4605                 Waitable::Host(id) => state.add_child(id, set),
4606                 Waitable::Guest(id) => state.add_child(id, set),
4607                 Waitable::Transmit(id) => state.add_child(id, set),
4608             }?;
4609 
4610             if self.common(state)?.event.is_some() {
4611                 self.mark_ready(state)?;
4612             }
4613         }
4614 
4615         Ok(())
4616     }
4617 
4618     /// Retrieve mutable access to the `WaitableCommon` for this `Waitable`.
4619     fn common<'a>(&self, state: &'a mut ConcurrentState) -> Result<&'a mut WaitableCommon> {
4620         Ok(match self {
4621             Self::Host(id) => &mut state.get_mut(*id)?.common,
4622             Self::Guest(id) => &mut state.get_mut(*id)?.common,
4623             Self::Transmit(id) => &mut state.get_mut(*id)?.common,
4624         })
4625     }
4626 
4627     /// Set or clear the pending event for this waitable and either deliver it
4628     /// to the first waiter, if any, or mark it as ready to be delivered to the
4629     /// next waiter that arrives.
4630     fn set_event(&self, state: &mut ConcurrentState, event: Option<Event>) -> Result<()> {
4631         log::trace!("set event for {self:?}: {event:?}");
4632         self.common(state)?.event = event;
4633         self.mark_ready(state)
4634     }
4635 
4636     /// Take the pending event from this waitable, leaving `None` in its place.
4637     fn take_event(&self, state: &mut ConcurrentState) -> Result<Option<Event>> {
4638         let common = self.common(state)?;
4639         let event = common.event.take();
4640         if let Some(set) = self.common(state)?.set {
4641             state.get_mut(set)?.ready.remove(self);
4642         }
4643 
4644         Ok(event)
4645     }
4646 
4647     /// Deliver the current event for this waitable to the first waiter, if any,
4648     /// or else mark it as ready to be delivered to the next waiter that
4649     /// arrives.
4650     fn mark_ready(&self, state: &mut ConcurrentState) -> Result<()> {
4651         if let Some(set) = self.common(state)?.set {
4652             state.get_mut(set)?.ready.insert(*self);
4653             if let Some((thread, mode)) = state.get_mut(set)?.waiting.pop_first() {
4654                 let wake_on_cancel = state.get_mut(thread.thread)?.wake_on_cancel.take();
4655                 assert!(wake_on_cancel.is_none() || wake_on_cancel == Some(set));
4656 
4657                 let item = match mode {
4658                     WaitMode::Fiber(fiber) => WorkItem::ResumeFiber(fiber),
4659                     WaitMode::Callback(instance) => WorkItem::GuestCall(
4660                         state.get_mut(thread.task)?.instance.index,
4661                         GuestCall {
4662                             thread,
4663                             kind: GuestCallKind::DeliverEvent {
4664                                 instance,
4665                                 set: Some(set),
4666                             },
4667                         },
4668                     ),
4669                 };
4670                 state.push_high_priority(item);
4671             }
4672         }
4673         Ok(())
4674     }
4675 
4676     /// Remove this waitable from the instance's rep table.
4677     fn delete_from(&self, state: &mut ConcurrentState) -> Result<()> {
4678         match self {
4679             Self::Host(task) => {
4680                 log::trace!("delete host task {task:?}");
4681                 state.delete(*task)?;
4682             }
4683             Self::Guest(task) => {
4684                 log::trace!("delete guest task {task:?}");
4685                 state.delete(*task)?.dispose(state)?;
4686             }
4687             Self::Transmit(task) => {
4688                 state.delete(*task)?;
4689             }
4690         }
4691 
4692         Ok(())
4693     }
4694 }
4695 
4696 impl fmt::Debug for Waitable {
4697     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4698         match self {
4699             Self::Host(id) => write!(f, "{id:?}"),
4700             Self::Guest(id) => write!(f, "{id:?}"),
4701             Self::Transmit(id) => write!(f, "{id:?}"),
4702         }
4703     }
4704 }
4705 
4706 /// Represents a Component Model Async `waitable-set`.
4707 #[derive(Default)]
4708 struct WaitableSet {
4709     /// Which waitables in this set have pending events, if any.
4710     ready: BTreeSet<Waitable>,
4711     /// Which guest threads are currently waiting on this set, if any.
4712     waiting: BTreeMap<QualifiedThreadId, WaitMode>,
4713 }
4714 
4715 impl TableDebug for WaitableSet {
4716     fn type_name() -> &'static str {
4717         "WaitableSet"
4718     }
4719 }
4720 
4721 /// Type-erased closure to lower the parameters for a guest task.
4722 type RawLower =
4723     Box<dyn FnOnce(&mut dyn VMStore, &mut [MaybeUninit<ValRaw>]) -> Result<()> + Send + Sync>;
4724 
4725 /// Type-erased closure to lift the result for a guest task.
4726 type RawLift = Box<
4727     dyn FnOnce(&mut dyn VMStore, &[ValRaw]) -> Result<Box<dyn Any + Send + Sync>> + Send + Sync,
4728 >;
4729 
4730 /// Type erased result of a guest task which may be downcast to the expected
4731 /// type by a host caller (or simply ignored in the case of a guest caller; see
4732 /// `DummyResult`).
4733 type LiftedResult = Box<dyn Any + Send + Sync>;
4734 
4735 /// Used to return a result from a `LiftFn` when the actual result has already
4736 /// been lowered to a guest task's stack and linear memory.
4737 struct DummyResult;
4738 
4739 /// Represents the Component Model Async state of a (sub-)component instance.
4740 #[derive(Default)]
4741 pub struct ConcurrentInstanceState {
4742     /// Whether backpressure is set for this instance (enabled if >0)
4743     backpressure: u16,
4744     /// Whether this instance can be entered
4745     do_not_enter: bool,
4746     /// Pending calls for this instance which require `Self::backpressure` to be
4747     /// `true` and/or `Self::do_not_enter` to be false before they can proceed.
4748     pending: BTreeMap<QualifiedThreadId, GuestCallKind>,
4749 }
4750 
4751 impl ConcurrentInstanceState {
4752     pub fn pending_is_empty(&self) -> bool {
4753         self.pending.is_empty()
4754     }
4755 }
4756 
4757 #[derive(Debug, Copy, Clone)]
4758 enum CurrentThread {
4759     Guest(QualifiedThreadId),
4760     Host(TableId<HostTask>),
4761     None,
4762 }
4763 
4764 impl CurrentThread {
4765     fn guest(&self) -> Option<&QualifiedThreadId> {
4766         match self {
4767             Self::Guest(id) => Some(id),
4768             _ => None,
4769         }
4770     }
4771 
4772     fn host(&self) -> Option<TableId<HostTask>> {
4773         match self {
4774             Self::Host(id) => Some(*id),
4775             _ => None,
4776         }
4777     }
4778 
4779     fn is_none(&self) -> bool {
4780         matches!(self, Self::None)
4781     }
4782 }
4783 
4784 impl From<QualifiedThreadId> for CurrentThread {
4785     fn from(id: QualifiedThreadId) -> Self {
4786         Self::Guest(id)
4787     }
4788 }
4789 
4790 impl From<TableId<HostTask>> for CurrentThread {
4791     fn from(id: TableId<HostTask>) -> Self {
4792         Self::Host(id)
4793     }
4794 }
4795 
4796 /// Represents the Component Model Async state of a store.
4797 pub struct ConcurrentState {
4798     /// The currently running thread, if any.
4799     current_thread: CurrentThread,
4800 
4801     /// The set of pending host and background tasks, if any.
4802     ///
4803     /// See `ComponentInstance::poll_until` for where we temporarily take this
4804     /// out, poll it, then put it back to avoid any mutable aliasing hazards.
4805     futures: AlwaysMut<Option<FuturesUnordered<HostTaskFuture>>>,
4806     /// The table of waitables, waitable sets, etc.
4807     table: AlwaysMut<ResourceTable>,
4808     /// The "high priority" work queue for this store's event loop.
4809     high_priority: Vec<WorkItem>,
4810     /// The "low priority" work queue for this store's event loop.
4811     low_priority: VecDeque<WorkItem>,
4812     /// A place to stash the reason a fiber is suspending so that the code which
4813     /// resumed it will know under what conditions the fiber should be resumed
4814     /// again.
4815     suspend_reason: Option<SuspendReason>,
4816     /// A cached fiber which is waiting for work to do.
4817     ///
4818     /// This helps us avoid creating a new fiber for each `GuestCall` work item.
4819     worker: Option<StoreFiber<'static>>,
4820     /// A place to stash the work item for which we're resuming a worker fiber.
4821     worker_item: Option<WorkerItem>,
4822 
4823     /// Reference counts for all component error contexts
4824     ///
4825     /// NOTE: it is possible the global ref count to be *greater* than the sum of
4826     /// (sub)component ref counts as tracked by `error_context_tables`, for
4827     /// example when the host holds one or more references to error contexts.
4828     ///
4829     /// The key of this primary map is often referred to as the "rep" (i.e. host-side
4830     /// component-wide representation) of the index into concurrent state for a given
4831     /// stored `ErrorContext`.
4832     ///
4833     /// Stated another way, `TypeComponentGlobalErrorContextTableIndex` is essentially the same
4834     /// as a `TableId<ErrorContextState>`.
4835     global_error_context_ref_counts:
4836         BTreeMap<TypeComponentGlobalErrorContextTableIndex, GlobalErrorContextRefCount>,
4837 }
4838 
4839 impl Default for ConcurrentState {
4840     fn default() -> Self {
4841         Self {
4842             current_thread: CurrentThread::None,
4843             table: AlwaysMut::new(ResourceTable::new()),
4844             futures: AlwaysMut::new(Some(FuturesUnordered::new())),
4845             high_priority: Vec::new(),
4846             low_priority: VecDeque::new(),
4847             suspend_reason: None,
4848             worker: None,
4849             worker_item: None,
4850             global_error_context_ref_counts: BTreeMap::new(),
4851         }
4852     }
4853 }
4854 
4855 impl ConcurrentState {
4856     /// Take ownership of any fibers and futures owned by this object.
4857     ///
4858     /// This should be used when disposing of the `Store` containing this object
4859     /// in order to gracefully resolve any and all fibers using
4860     /// `StoreFiber::dispose`.  This is necessary to avoid possible
4861     /// use-after-free bugs due to fibers which may still have access to the
4862     /// `Store`.
4863     ///
4864     /// Additionally, the futures collected with this function should be dropped
4865     /// within a `tls::set` call, which will ensure than any futures closing
4866     /// over an `&Accessor` will have access to the store when dropped, allowing
4867     /// e.g. `WithAccessor[AndValue]` instances to be disposed of without
4868     /// panicking.
4869     ///
4870     /// Note that this will leave the object in an inconsistent and unusable
4871     /// state, so it should only be used just prior to dropping it.
4872     pub(crate) fn take_fibers_and_futures(
4873         &mut self,
4874         fibers: &mut Vec<StoreFiber<'static>>,
4875         futures: &mut Vec<FuturesUnordered<HostTaskFuture>>,
4876     ) {
4877         for entry in self.table.get_mut().iter_mut() {
4878             if let Some(set) = entry.downcast_mut::<WaitableSet>() {
4879                 for mode in mem::take(&mut set.waiting).into_values() {
4880                     if let WaitMode::Fiber(fiber) = mode {
4881                         fibers.push(fiber);
4882                     }
4883                 }
4884             } else if let Some(thread) = entry.downcast_mut::<GuestThread>() {
4885                 if let GuestThreadState::Suspended(fiber) | GuestThreadState::Ready(fiber) =
4886                     mem::replace(&mut thread.state, GuestThreadState::Completed)
4887                 {
4888                     fibers.push(fiber);
4889                 }
4890             }
4891         }
4892 
4893         if let Some(fiber) = self.worker.take() {
4894             fibers.push(fiber);
4895         }
4896 
4897         let mut handle_item = |item| match item {
4898             WorkItem::ResumeFiber(fiber) => {
4899                 fibers.push(fiber);
4900             }
4901             WorkItem::PushFuture(future) => {
4902                 self.futures
4903                     .get_mut()
4904                     .as_mut()
4905                     .unwrap()
4906                     .push(future.into_inner());
4907             }
4908             _ => {}
4909         };
4910 
4911         for item in mem::take(&mut self.high_priority) {
4912             handle_item(item);
4913         }
4914         for item in mem::take(&mut self.low_priority) {
4915             handle_item(item);
4916         }
4917 
4918         if let Some(them) = self.futures.get_mut().take() {
4919             futures.push(them);
4920         }
4921     }
4922 
4923     /// Collect the next set of work items to run. This will be either all
4924     /// high-priority items, or a single low-priority item if there are no
4925     /// high-priority items.
4926     fn collect_work_items_to_run(&mut self) -> Vec<WorkItem> {
4927         let mut ready = mem::take(&mut self.high_priority);
4928         if ready.is_empty() {
4929             if let Some(item) = self.low_priority.pop_back() {
4930                 ready.push(item);
4931             }
4932         }
4933         ready
4934     }
4935 
4936     fn push<V: Send + Sync + 'static>(
4937         &mut self,
4938         value: V,
4939     ) -> Result<TableId<V>, ResourceTableError> {
4940         self.table.get_mut().push(value).map(TableId::from)
4941     }
4942 
4943     fn get_mut<V: 'static>(&mut self, id: TableId<V>) -> Result<&mut V, ResourceTableError> {
4944         self.table.get_mut().get_mut(&Resource::from(id))
4945     }
4946 
4947     pub fn add_child<T: 'static, U: 'static>(
4948         &mut self,
4949         child: TableId<T>,
4950         parent: TableId<U>,
4951     ) -> Result<(), ResourceTableError> {
4952         self.table
4953             .get_mut()
4954             .add_child(Resource::from(child), Resource::from(parent))
4955     }
4956 
4957     pub fn remove_child<T: 'static, U: 'static>(
4958         &mut self,
4959         child: TableId<T>,
4960         parent: TableId<U>,
4961     ) -> Result<(), ResourceTableError> {
4962         self.table
4963             .get_mut()
4964             .remove_child(Resource::from(child), Resource::from(parent))
4965     }
4966 
4967     fn delete<V: 'static>(&mut self, id: TableId<V>) -> Result<V, ResourceTableError> {
4968         self.table.get_mut().delete(Resource::from(id))
4969     }
4970 
4971     fn push_future(&mut self, future: HostTaskFuture) {
4972         // Note that we can't directly push to `ConcurrentState::futures` here
4973         // since this may be called from a future that's being polled inside
4974         // `Self::poll_until`, which temporarily removes the `FuturesUnordered`
4975         // so it has exclusive access while polling it.  Therefore, we push a
4976         // work item to the "high priority" queue, which will actually push to
4977         // `ConcurrentState::futures` later.
4978         self.push_high_priority(WorkItem::PushFuture(AlwaysMut::new(future)));
4979     }
4980 
4981     fn push_high_priority(&mut self, item: WorkItem) {
4982         log::trace!("push high priority: {item:?}");
4983         self.high_priority.push(item);
4984     }
4985 
4986     fn push_low_priority(&mut self, item: WorkItem) {
4987         log::trace!("push low priority: {item:?}");
4988         self.low_priority.push_front(item);
4989     }
4990 
4991     fn push_work_item(&mut self, item: WorkItem, high_priority: bool) {
4992         if high_priority {
4993             self.push_high_priority(item);
4994         } else {
4995             self.push_low_priority(item);
4996         }
4997     }
4998 
4999     fn promote_instance_local_thread_work_item(
5000         &mut self,
5001         current_instance: RuntimeComponentInstanceIndex,
5002     ) -> bool {
5003         self.promote_work_items_matching(|item: &WorkItem| match item {
5004             WorkItem::ResumeThread(instance, _) | WorkItem::GuestCall(instance, _) => {
5005                 *instance == current_instance
5006             }
5007             _ => false,
5008         })
5009     }
5010 
5011     fn promote_thread_work_item(&mut self, thread: QualifiedThreadId) -> bool {
5012         self.promote_work_items_matching(|item: &WorkItem| match item {
5013             WorkItem::ResumeThread(_, t) | WorkItem::GuestCall(_, GuestCall { thread: t, .. }) => {
5014                 *t == thread
5015             }
5016             _ => false,
5017         })
5018     }
5019 
5020     fn promote_work_items_matching<F>(&mut self, mut predicate: F) -> bool
5021     where
5022         F: FnMut(&WorkItem) -> bool,
5023     {
5024         // If there's a high-priority work item to resume the current guest thread,
5025         // we don't need to promote anything, but we return true to indicate that
5026         // work is pending for the current instance.
5027         if self.high_priority.iter().any(&mut predicate) {
5028             true
5029         }
5030         // Otherwise, look for a low-priority work item that matches the current
5031         // instance and promote it to high-priority.
5032         else if let Some(idx) = self.low_priority.iter().position(&mut predicate) {
5033             let item = self.low_priority.remove(idx).unwrap();
5034             self.push_high_priority(item);
5035             true
5036         } else {
5037             false
5038         }
5039     }
5040 
5041     /// Implements the `context.get` intrinsic.
5042     pub(crate) fn context_get(&mut self, slot: u32) -> Result<u32> {
5043         let thread = self.unwrap_current_guest_thread();
5044         let val = self.get_mut(thread.thread)?.context[usize::try_from(slot).unwrap()];
5045         log::trace!("context_get {thread:?} slot {slot} val {val:#x}");
5046         Ok(val)
5047     }
5048 
5049     /// Implements the `context.set` intrinsic.
5050     pub(crate) fn context_set(&mut self, slot: u32, val: u32) -> Result<()> {
5051         let thread = self.unwrap_current_guest_thread();
5052         log::trace!("context_set {thread:?} slot {slot} val {val:#x}");
5053         self.get_mut(thread.thread)?.context[usize::try_from(slot).unwrap()] = val;
5054         Ok(())
5055     }
5056 
5057     /// Returns whether there's a pending cancellation on the current guest thread,
5058     /// consuming the event if so.
5059     fn take_pending_cancellation(&mut self) -> bool {
5060         let thread = self.unwrap_current_guest_thread();
5061         if let Some(event) = self.get_mut(thread.task).unwrap().event.take() {
5062             assert!(matches!(event, Event::Cancelled));
5063             true
5064         } else {
5065             false
5066         }
5067     }
5068 
5069     fn check_blocking_for(&mut self, task: TableId<GuestTask>) -> Result<()> {
5070         if self.may_block(task) {
5071             Ok(())
5072         } else {
5073             Err(Trap::CannotBlockSyncTask.into())
5074         }
5075     }
5076 
5077     fn may_block(&mut self, task: TableId<GuestTask>) -> bool {
5078         let task = self.get_mut(task).unwrap();
5079         task.async_function || task.returned_or_cancelled()
5080     }
5081 
5082     /// Used by `ResourceTables` to acquire the current `CallContext` for the
5083     /// specified task.
5084     ///
5085     /// The `task` is bit-packed as returned by `current_call_context_scope_id`
5086     /// below.
5087     pub fn call_context(&mut self, task: u32) -> &mut CallContext {
5088         let (task, is_host) = (task >> 1, task & 1 == 1);
5089         if is_host {
5090             let task: TableId<HostTask> = TableId::new(task);
5091             &mut self.get_mut(task).unwrap().call_context
5092         } else {
5093             let task: TableId<GuestTask> = TableId::new(task);
5094             &mut self.get_mut(task).unwrap().call_context
5095         }
5096     }
5097 
5098     /// Used by `ResourceTables` to record the scope of a borrow to get undone
5099     /// in the future.
5100     pub fn current_call_context_scope_id(&self) -> u32 {
5101         let (bits, is_host) = match self.current_thread {
5102             CurrentThread::Guest(id) => (id.task.rep(), false),
5103             CurrentThread::Host(id) => (id.rep(), true),
5104             CurrentThread::None => unreachable!(),
5105         };
5106         assert_eq!((bits << 1) >> 1, bits);
5107         (bits << 1) | u32::from(is_host)
5108     }
5109 
5110     fn unwrap_current_guest_thread(&self) -> QualifiedThreadId {
5111         *self.current_thread.guest().unwrap()
5112     }
5113 
5114     fn unwrap_current_host_thread(&self) -> TableId<HostTask> {
5115         self.current_thread.host().unwrap()
5116     }
5117 }
5118 
5119 /// Provide a type hint to compiler about the shape of a parameter lower
5120 /// closure.
5121 fn for_any_lower<
5122     F: FnOnce(&mut dyn VMStore, &mut [MaybeUninit<ValRaw>]) -> Result<()> + Send + Sync,
5123 >(
5124     fun: F,
5125 ) -> F {
5126     fun
5127 }
5128 
5129 /// Provide a type hint to compiler about the shape of a result lift closure.
5130 fn for_any_lift<
5131     F: FnOnce(&mut dyn VMStore, &[ValRaw]) -> Result<Box<dyn Any + Send + Sync>> + Send + Sync,
5132 >(
5133     fun: F,
5134 ) -> F {
5135     fun
5136 }
5137 
5138 /// Wrap the specified future in a `poll_fn` which asserts that the future is
5139 /// only polled from the event loop of the specified `Store`.
5140 ///
5141 /// See `StoreContextMut::run_concurrent` for details.
5142 fn checked<F: Future + Send + 'static>(
5143     id: StoreId,
5144     fut: F,
5145 ) -> impl Future<Output = F::Output> + Send + 'static {
5146     async move {
5147         let mut fut = pin!(fut);
5148         future::poll_fn(move |cx| {
5149             let message = "\
5150                 `Future`s which depend on asynchronous component tasks, streams, or \
5151                 futures to complete may only be polled from the event loop of the \
5152                 store to which they belong.  Please use \
5153                 `StoreContextMut::{run_concurrent,spawn}` to poll or await them.\
5154             ";
5155             tls::try_get(|store| {
5156                 let matched = match store {
5157                     tls::TryGet::Some(store) => store.id() == id,
5158                     tls::TryGet::Taken | tls::TryGet::None => false,
5159                 };
5160 
5161                 if !matched {
5162                     panic!("{message}")
5163                 }
5164             });
5165             fut.as_mut().poll(cx)
5166         })
5167         .await
5168     }
5169 }
5170 
5171 /// Assert that `StoreContextMut::run_concurrent` has not been called from
5172 /// within an store's event loop.
5173 fn check_recursive_run() {
5174     tls::try_get(|store| {
5175         if !matches!(store, tls::TryGet::None) {
5176             panic!("Recursive `StoreContextMut::run_concurrent` calls not supported")
5177         }
5178     });
5179 }
5180 
5181 fn unpack_callback_code(code: u32) -> (u32, u32) {
5182     (code & 0xF, code >> 4)
5183 }
5184 
5185 /// Helper struct for packaging parameters to be passed to
5186 /// `ComponentInstance::waitable_check` for calls to `waitable-set.wait` or
5187 /// `waitable-set.poll`.
5188 struct WaitableCheckParams {
5189     set: TableId<WaitableSet>,
5190     options: OptionsIndex,
5191     payload: u32,
5192 }
5193 
5194 /// Indicates whether `ComponentInstance::waitable_check` is being called for
5195 /// `waitable-set.wait` or `waitable-set.poll`.
5196 enum WaitableCheck {
5197     Wait,
5198     Poll,
5199 }
5200 
5201 /// Represents a guest task called from the host, prepared using `prepare_call`.
5202 pub(crate) struct PreparedCall<R> {
5203     /// The guest export to be called
5204     handle: Func,
5205     /// The guest thread created by `prepare_call`
5206     thread: QualifiedThreadId,
5207     /// The number of lowered core Wasm parameters to pass to the call.
5208     param_count: usize,
5209     /// The `oneshot::Receiver` to which the result of the call will be
5210     /// delivered when it is available.
5211     rx: oneshot::Receiver<LiftedResult>,
5212     _phantom: PhantomData<R>,
5213 }
5214 
5215 impl<R> PreparedCall<R> {
5216     /// Get a copy of the `TaskId` for this `PreparedCall`.
5217     pub(crate) fn task_id(&self) -> TaskId {
5218         TaskId {
5219             task: self.thread.task,
5220         }
5221     }
5222 }
5223 
5224 /// Represents a task created by `prepare_call`.
5225 pub(crate) struct TaskId {
5226     task: TableId<GuestTask>,
5227 }
5228 
5229 impl TaskId {
5230     /// The host future for an async task was dropped. If the parameters have not been lowered yet,
5231     /// it is no longer valid to do so, as the lowering closure would see a dangling pointer. In this case,
5232     /// we delete the task eagerly. Otherwise, there may be running threads, or ones that are suspended
5233     /// and can be resumed by other tasks for this component, so we mark the future as dropped
5234     /// and delete the task when all threads are done.
5235     pub(crate) fn host_future_dropped<T>(&self, store: StoreContextMut<T>) -> Result<()> {
5236         let task = store.0.concurrent_state_mut().get_mut(self.task)?;
5237         if !task.already_lowered_parameters() {
5238             Waitable::Guest(self.task).delete_from(store.0.concurrent_state_mut())?
5239         } else {
5240             task.host_future_state = HostFutureState::Dropped;
5241             if task.ready_to_delete() {
5242                 Waitable::Guest(self.task).delete_from(store.0.concurrent_state_mut())?
5243             }
5244         }
5245         Ok(())
5246     }
5247 }
5248 
5249 /// Prepare a call to the specified exported Wasm function, providing functions
5250 /// for lowering the parameters and lifting the result.
5251 ///
5252 /// To enqueue the returned `PreparedCall` in the `ComponentInstance`'s event
5253 /// loop, use `queue_call`.
5254 pub(crate) fn prepare_call<T, R>(
5255     mut store: StoreContextMut<T>,
5256     handle: Func,
5257     param_count: usize,
5258     host_future_present: bool,
5259     lower_params: impl FnOnce(Func, StoreContextMut<T>, &mut [MaybeUninit<ValRaw>]) -> Result<()>
5260     + Send
5261     + Sync
5262     + 'static,
5263     lift_result: impl FnOnce(Func, &mut StoreOpaque, &[ValRaw]) -> Result<Box<dyn Any + Send + Sync>>
5264     + Send
5265     + Sync
5266     + 'static,
5267 ) -> Result<PreparedCall<R>> {
5268     let (options, _flags, ty, raw_options) = handle.abi_info(store.0);
5269 
5270     let instance = handle.instance().id().get(store.0);
5271     let options = &instance.component().env_component().options[options];
5272     let ty = &instance.component().types()[ty];
5273     let async_function = ty.async_;
5274     let task_return_type = ty.results;
5275     let component_instance = raw_options.instance;
5276     let callback = options.callback.map(|i| instance.runtime_callback(i));
5277     let memory = options
5278         .memory()
5279         .map(|i| instance.runtime_memory(i))
5280         .map(SendSyncPtr::new);
5281     let string_encoding = options.string_encoding;
5282     let token = StoreToken::new(store.as_context_mut());
5283     let state = store.0.concurrent_state_mut();
5284 
5285     let (tx, rx) = oneshot::channel();
5286 
5287     let instance = RuntimeInstance {
5288         instance: handle.instance().id().instance(),
5289         index: component_instance,
5290     };
5291     let caller = state.current_thread;
5292     let task = GuestTask::new(
5293         state,
5294         Box::new(for_any_lower(move |store, params| {
5295             lower_params(handle, token.as_context_mut(store), params)
5296         })),
5297         LiftResult {
5298             lift: Box::new(for_any_lift(move |store, result| {
5299                 lift_result(handle, store, result)
5300             })),
5301             ty: task_return_type,
5302             memory,
5303             string_encoding,
5304         },
5305         Caller::Host {
5306             tx: Some(tx),
5307             host_future_present,
5308             caller,
5309         },
5310         callback.map(|callback| {
5311             let callback = SendSyncPtr::new(callback);
5312             let instance = handle.instance();
5313             Box::new(move |store: &mut dyn VMStore, event, handle| {
5314                 let store = token.as_context_mut(store);
5315                 // SAFETY: Per the contract of `prepare_call`, the callback
5316                 // will remain valid at least as long is this task exists.
5317                 unsafe { instance.call_callback(store, callback, event, handle) }
5318             }) as CallbackFn
5319         }),
5320         instance,
5321         async_function,
5322     )?;
5323 
5324     let task = state.push(task)?;
5325     let thread = state.push(GuestThread::new_implicit(task))?;
5326     state.get_mut(task)?.threads.insert(thread);
5327 
5328     if !store.0.may_enter(instance) {
5329         bail!(crate::Trap::CannotEnterComponent);
5330     }
5331 
5332     Ok(PreparedCall {
5333         handle,
5334         thread: QualifiedThreadId { task, thread },
5335         param_count,
5336         rx,
5337         _phantom: PhantomData,
5338     })
5339 }
5340 
5341 /// Queue a call previously prepared using `prepare_call` to be run as part of
5342 /// the associated `ComponentInstance`'s event loop.
5343 ///
5344 /// The returned future will resolve to the result once it is available, but
5345 /// must only be polled via the instance's event loop. See
5346 /// `StoreContextMut::run_concurrent` for details.
5347 pub(crate) fn queue_call<T: 'static, R: Send + 'static>(
5348     mut store: StoreContextMut<T>,
5349     prepared: PreparedCall<R>,
5350 ) -> Result<impl Future<Output = Result<R>> + Send + 'static + use<T, R>> {
5351     let PreparedCall {
5352         handle,
5353         thread,
5354         param_count,
5355         rx,
5356         ..
5357     } = prepared;
5358 
5359     queue_call0(store.as_context_mut(), handle, thread, param_count)?;
5360 
5361     Ok(checked(
5362         store.0.id(),
5363         rx.map(move |result| {
5364             result
5365                 .map(|v| *v.downcast().unwrap())
5366                 .map_err(crate::Error::from)
5367         }),
5368     ))
5369 }
5370 
5371 /// Queue a call previously prepared using `prepare_call` to be run as part of
5372 /// the associated `ComponentInstance`'s event loop.
5373 fn queue_call0<T: 'static>(
5374     store: StoreContextMut<T>,
5375     handle: Func,
5376     guest_thread: QualifiedThreadId,
5377     param_count: usize,
5378 ) -> Result<()> {
5379     let (_options, _, _ty, raw_options) = handle.abi_info(store.0);
5380     let is_concurrent = raw_options.async_;
5381     let callback = raw_options.callback;
5382     let instance = handle.instance();
5383     let callee = handle.lifted_core_func(store.0);
5384     let post_return = handle.post_return_core_func(store.0);
5385     let callback = callback.map(|i| {
5386         let instance = instance.id().get(store.0);
5387         SendSyncPtr::new(instance.runtime_callback(i))
5388     });
5389 
5390     log::trace!("queueing call {guest_thread:?}");
5391 
5392     // SAFETY: `callee`, `callback`, and `post_return` are valid pointers
5393     // (with signatures appropriate for this call) and will remain valid as
5394     // long as this instance is valid.
5395     unsafe {
5396         instance.queue_call(
5397             store,
5398             guest_thread,
5399             SendSyncPtr::new(callee),
5400             param_count,
5401             1,
5402             is_concurrent,
5403             callback,
5404             post_return.map(SendSyncPtr::new),
5405         )
5406     }
5407 }
5408