Skip to main content

wasmtime/runtime/component/
concurrent.rs

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