1 //! Wasmtime's "store" type
2 //!
3 //! This module, and its submodules, contain the `Store` type and various types
4 //! used to interact with it. At first glance this is a pretty confusing module
5 //! where you need to know the difference between:
6 //!
7 //! * `Store<T>`
8 //! * `StoreContext<T>`
9 //! * `StoreContextMut<T>`
10 //! * `AsContext`
11 //! * `AsContextMut`
12 //! * `StoreInner<T>`
13 //! * `StoreOpaque`
14 //! * `StoreData`
15 //!
16 //! There's... quite a lot going on here, and it's easy to be confused. This
17 //! comment is ideally going to serve the purpose of clarifying what all these
18 //! types are for and why they're motivated.
19 //!
20 //! First it's important to know what's "internal" and what's "external". Almost
21 //! everything above is defined as `pub`, but only some of the items are
22 //! reexported to the outside world to be usable from this crate. Otherwise all
23 //! items are `pub` within this `store` module, and the `store` module is
24 //! private to the `wasmtime` crate. Notably `Store<T>`, `StoreContext<T>`,
25 //! `StoreContextMut<T>`, `AsContext`, and `AsContextMut` are all public
26 //! interfaces to the `wasmtime` crate. You can think of these as:
27 //!
28 //! * `Store<T>` - an owned reference to a store, the "root of everything"
29 //! * `StoreContext<T>` - basically `&StoreInner<T>`
30 //! * `StoreContextMut<T>` - more-or-less `&mut StoreInner<T>` with caveats.
31 //!   Explained later.
32 //! * `AsContext` - similar to `AsRef`, but produces `StoreContext<T>`
33 //! * `AsContextMut` - similar to `AsMut`, but produces `StoreContextMut<T>`
34 //!
35 //! Next comes the internal structure of the `Store<T>` itself. This looks like:
36 //!
37 //! * `Store<T>` - this type is just a pointer large. It's primarily just
38 //!   intended to be consumed by the outside world. Note that the "just a
39 //!   pointer large" is a load-bearing implementation detail in Wasmtime. This
40 //!   enables it to store a pointer to its own trait object which doesn't need
41 //!   to change over time.
42 //!
43 //! * `StoreInner<T>` - the first layer of the contents of a `Store<T>`, what's
44 //!   stored inside the `Box`. This is the general Rust pattern when one struct
45 //!   is a layer over another. The surprising part, though, is that this is
46 //!   further subdivided. This structure only contains things which actually
47 //!   need `T` itself. The downside of this structure is that it's always
48 //!   generic and means that code is monomorphized into consumer crates. We
49 //!   strive to have things be as monomorphic as possible in `wasmtime` so this
50 //!   type is not heavily used.
51 //!
52 //! * `StoreOpaque` - this is the primary contents of the `StoreInner<T>` type.
53 //!   Stored inline in the outer type the "opaque" here means that it's a
54 //!   "store" but it doesn't have access to the `T`. This is the primary
55 //!   "internal" reference that Wasmtime uses since `T` is rarely needed by the
56 //!   internals of Wasmtime.
57 //!
58 //! * `StoreData` - this is a final helper struct stored within `StoreOpaque`.
59 //!   All references of Wasm items into a `Store` are actually indices into a
60 //!   table in this structure, and the `StoreData` being separate makes it a bit
61 //!   easier to manage/define/work with. There's no real fundamental reason this
62 //!   is split out, although sometimes it's useful to have separate borrows into
63 //!   these tables than the `StoreOpaque`.
64 //!
65 //! A major caveat with these representations is that the internal `&mut
66 //! StoreInner<T>` is never handed out publicly to consumers of this crate, only
67 //! through a wrapper of `StoreContextMut<'_, T>`. The reason for this is that
68 //! we want to provide mutable, but not destructive, access to the contents of a
69 //! `Store`. For example if a `StoreInner<T>` were replaced with some other
70 //! `StoreInner<T>` then that would drop live instances, possibly those
71 //! currently executing beneath the current stack frame. This would not be a
72 //! safe operation.
73 //!
74 //! This means, though, that the `wasmtime` crate, which liberally uses `&mut
75 //! StoreOpaque` internally, has to be careful to never actually destroy the
76 //! contents of `StoreOpaque`. This is an invariant that we, as the authors of
77 //! `wasmtime`, must uphold for the public interface to be safe.
78 
79 use crate::RootSet;
80 use crate::module::RegisteredModuleId;
81 use crate::prelude::*;
82 #[cfg(feature = "gc")]
83 use crate::runtime::vm::GcRootsList;
84 #[cfg(feature = "stack-switching")]
85 use crate::runtime::vm::VMContRef;
86 use crate::runtime::vm::mpk::ProtectionKey;
87 use crate::runtime::vm::{
88     self, GcStore, Imports, InstanceAllocationRequest, InstanceAllocator, InstanceHandle,
89     Interpreter, InterpreterRef, ModuleRuntimeInfo, OnDemandInstanceAllocator, SendSyncPtr,
90     SignalHandler, StoreBox, StorePtr, Unwind, VMContext, VMFuncRef, VMGcRef, VMStoreContext,
91 };
92 use crate::trampoline::VMHostGlobalContext;
93 use crate::{Engine, Module, Trap, Val, ValRaw, module::ModuleRegistry};
94 use crate::{Global, Instance, Memory, Table, Uninhabited};
95 use alloc::sync::Arc;
96 use core::fmt;
97 use core::marker;
98 use core::mem::{self, ManuallyDrop};
99 use core::num::NonZeroU64;
100 use core::ops::{Deref, DerefMut};
101 use core::pin::Pin;
102 use core::ptr::NonNull;
103 use wasmtime_environ::{DefinedGlobalIndex, DefinedTableIndex, EntityRef, PrimaryMap, TripleExt};
104 
105 mod context;
106 pub use self::context::*;
107 mod data;
108 pub use self::data::*;
109 mod func_refs;
110 use func_refs::FuncRefs;
111 #[cfg(feature = "async")]
112 mod async_;
113 #[cfg(all(feature = "async", feature = "call-hook"))]
114 pub use self::async_::CallHookHandler;
115 #[cfg(feature = "async")]
116 use self::async_::*;
117 #[cfg(feature = "gc")]
118 mod gc;
119 
120 /// A [`Store`] is a collection of WebAssembly instances and host-defined state.
121 ///
122 /// All WebAssembly instances and items will be attached to and refer to a
123 /// [`Store`]. For example instances, functions, globals, and tables are all
124 /// attached to a [`Store`]. Instances are created by instantiating a
125 /// [`Module`](crate::Module) within a [`Store`].
126 ///
127 /// A [`Store`] is intended to be a short-lived object in a program. No form
128 /// of GC is implemented at this time so once an instance is created within a
129 /// [`Store`] it will not be deallocated until the [`Store`] itself is dropped.
130 /// This makes [`Store`] unsuitable for creating an unbounded number of
131 /// instances in it because [`Store`] will never release this memory. It's
132 /// recommended to have a [`Store`] correspond roughly to the lifetime of a
133 /// "main instance" that an embedding is interested in executing.
134 ///
135 /// ## Type parameter `T`
136 ///
137 /// Each [`Store`] has a type parameter `T` associated with it. This `T`
138 /// represents state defined by the host. This state will be accessible through
139 /// the [`Caller`](crate::Caller) type that host-defined functions get access
140 /// to. This `T` is suitable for storing `Store`-specific information which
141 /// imported functions may want access to.
142 ///
143 /// The data `T` can be accessed through methods like [`Store::data`] and
144 /// [`Store::data_mut`].
145 ///
146 /// ## Stores, contexts, oh my
147 ///
148 /// Most methods in Wasmtime take something of the form
149 /// [`AsContext`](crate::AsContext) or [`AsContextMut`](crate::AsContextMut) as
150 /// the first argument. These two traits allow ergonomically passing in the
151 /// context you currently have to any method. The primary two sources of
152 /// contexts are:
153 ///
154 /// * `Store<T>`
155 /// * `Caller<'_, T>`
156 ///
157 /// corresponding to what you create and what you have access to in a host
158 /// function. You can also explicitly acquire a [`StoreContext`] or
159 /// [`StoreContextMut`] and pass that around as well.
160 ///
161 /// Note that all methods on [`Store`] are mirrored onto [`StoreContext`],
162 /// [`StoreContextMut`], and [`Caller`](crate::Caller). This way no matter what
163 /// form of context you have you can call various methods, create objects, etc.
164 ///
165 /// ## Stores and `Default`
166 ///
167 /// You can create a store with default configuration settings using
168 /// `Store::default()`. This will create a brand new [`Engine`] with default
169 /// configuration (see [`Config`](crate::Config) for more information).
170 ///
171 /// ## Cross-store usage of items
172 ///
173 /// In `wasmtime` wasm items such as [`Global`] and [`Memory`] "belong" to a
174 /// [`Store`]. The store they belong to is the one they were created with
175 /// (passed in as a parameter) or instantiated with. This store is the only
176 /// store that can be used to interact with wasm items after they're created.
177 ///
178 /// The `wasmtime` crate will panic if the [`Store`] argument passed in to these
179 /// operations is incorrect. In other words it's considered a programmer error
180 /// rather than a recoverable error for the wrong [`Store`] to be used when
181 /// calling APIs.
182 pub struct Store<T: 'static> {
183     // for comments about `ManuallyDrop`, see `Store::into_data`
184     inner: ManuallyDrop<Box<StoreInner<T>>>,
185 }
186 
187 #[derive(Copy, Clone, Debug)]
188 /// Passed to the argument of [`Store::call_hook`] to indicate a state transition in
189 /// the WebAssembly VM.
190 pub enum CallHook {
191     /// Indicates the VM is calling a WebAssembly function, from the host.
192     CallingWasm,
193     /// Indicates the VM is returning from a WebAssembly function, to the host.
194     ReturningFromWasm,
195     /// Indicates the VM is calling a host function, from WebAssembly.
196     CallingHost,
197     /// Indicates the VM is returning from a host function, to WebAssembly.
198     ReturningFromHost,
199 }
200 
201 impl CallHook {
202     /// Indicates the VM is entering host code (exiting WebAssembly code)
203     pub fn entering_host(&self) -> bool {
204         match self {
205             CallHook::ReturningFromWasm | CallHook::CallingHost => true,
206             _ => false,
207         }
208     }
209     /// Indicates the VM is exiting host code (entering WebAssembly code)
210     pub fn exiting_host(&self) -> bool {
211         match self {
212             CallHook::ReturningFromHost | CallHook::CallingWasm => true,
213             _ => false,
214         }
215     }
216 }
217 
218 /// Internal contents of a `Store<T>` that live on the heap.
219 ///
220 /// The members of this struct are those that need to be generic over `T`, the
221 /// store's internal type storage. Otherwise all things that don't rely on `T`
222 /// should go into `StoreOpaque`.
223 pub struct StoreInner<T: 'static> {
224     /// Generic metadata about the store that doesn't need access to `T`.
225     inner: StoreOpaque,
226 
227     limiter: Option<ResourceLimiterInner<T>>,
228     call_hook: Option<CallHookInner<T>>,
229     #[cfg(target_has_atomic = "64")]
230     epoch_deadline_behavior:
231         Option<Box<dyn FnMut(StoreContextMut<T>) -> Result<UpdateDeadline> + Send + Sync>>,
232     // for comments about `ManuallyDrop`, see `Store::into_data`
233     data: ManuallyDrop<T>,
234 }
235 
236 enum ResourceLimiterInner<T> {
237     Sync(Box<dyn FnMut(&mut T) -> &mut (dyn crate::ResourceLimiter) + Send + Sync>),
238     #[cfg(feature = "async")]
239     Async(Box<dyn FnMut(&mut T) -> &mut (dyn crate::ResourceLimiterAsync) + Send + Sync>),
240 }
241 
242 enum CallHookInner<T: 'static> {
243     #[cfg(feature = "call-hook")]
244     Sync(Box<dyn FnMut(StoreContextMut<'_, T>, CallHook) -> Result<()> + Send + Sync>),
245     #[cfg(all(feature = "async", feature = "call-hook"))]
246     Async(Box<dyn CallHookHandler<T> + Send + Sync>),
247     #[allow(dead_code)]
248     ForceTypeParameterToBeUsed {
249         uninhabited: Uninhabited,
250         _marker: marker::PhantomData<T>,
251     },
252 }
253 
254 /// What to do after returning from a callback when the engine epoch reaches
255 /// the deadline for a Store during execution of a function using that store.
256 #[non_exhaustive]
257 pub enum UpdateDeadline {
258     /// Extend the deadline by the specified number of ticks.
259     Continue(u64),
260     /// Extend the deadline by the specified number of ticks after yielding to
261     /// the async executor loop. This can only be used with an async [`Store`]
262     /// configured via [`Config::async_support`](crate::Config::async_support).
263     #[cfg(feature = "async")]
264     Yield(u64),
265     /// Extend the deadline by the specified number of ticks after yielding to
266     /// the async executor loop. This can only be used with an async [`Store`]
267     /// configured via [`Config::async_support`](crate::Config::async_support).
268     ///
269     /// The yield will be performed by the future provided; when using `tokio`
270     /// it is recommended to provide [`tokio::task::yield_now`](https://docs.rs/tokio/latest/tokio/task/fn.yield_now.html)
271     /// here.
272     #[cfg(feature = "async")]
273     YieldCustom(
274         u64,
275         ::core::pin::Pin<Box<dyn ::core::future::Future<Output = ()> + Send>>,
276     ),
277 }
278 
279 // Forward methods on `StoreOpaque` to also being on `StoreInner<T>`
280 impl<T> Deref for StoreInner<T> {
281     type Target = StoreOpaque;
282     fn deref(&self) -> &Self::Target {
283         &self.inner
284     }
285 }
286 
287 impl<T> DerefMut for StoreInner<T> {
288     fn deref_mut(&mut self) -> &mut Self::Target {
289         &mut self.inner
290     }
291 }
292 
293 /// Monomorphic storage for a `Store<T>`.
294 ///
295 /// This structure contains the bulk of the metadata about a `Store`. This is
296 /// used internally in Wasmtime when dependence on the `T` of `Store<T>` isn't
297 /// necessary, allowing code to be monomorphic and compiled into the `wasmtime`
298 /// crate itself.
299 pub struct StoreOpaque {
300     // This `StoreOpaque` structure has references to itself. These aren't
301     // immediately evident, however, so we need to tell the compiler that it
302     // contains self-references. This notably suppresses `noalias` annotations
303     // when this shows up in compiled code because types of this structure do
304     // indeed alias itself. An example of this is `default_callee` holds a
305     // `*mut dyn Store` to the address of this `StoreOpaque` itself, indeed
306     // aliasing!
307     //
308     // It's somewhat unclear to me at this time if this is 100% sufficient to
309     // get all the right codegen in all the right places. For example does
310     // `Store` need to internally contain a `Pin<Box<StoreInner<T>>>`? Do the
311     // contexts need to contain `Pin<&mut StoreInner<T>>`? I'm not familiar
312     // enough with `Pin` to understand if it's appropriate here (we do, for
313     // example want to allow movement in and out of `data: T`, just not movement
314     // of most of the other members). It's also not clear if using `Pin` in a
315     // few places buys us much other than a bunch of `unsafe` that we already
316     // sort of hand-wave away.
317     //
318     // In any case this seems like a good mid-ground for now where we're at
319     // least telling the compiler something about all the aliasing happening
320     // within a `Store`.
321     _marker: marker::PhantomPinned,
322 
323     engine: Engine,
324     vm_store_context: VMStoreContext,
325 
326     // Contains all continuations ever allocated throughout the lifetime of this
327     // store.
328     #[cfg(feature = "stack-switching")]
329     continuations: Vec<Box<VMContRef>>,
330 
331     instances: PrimaryMap<InstanceId, StoreInstance>,
332 
333     #[cfg(feature = "component-model")]
334     num_component_instances: usize,
335     signal_handler: Option<SignalHandler>,
336     modules: ModuleRegistry,
337     func_refs: FuncRefs,
338     host_globals: PrimaryMap<DefinedGlobalIndex, StoreBox<VMHostGlobalContext>>,
339     // GC-related fields.
340     gc_store: Option<GcStore>,
341     gc_roots: RootSet,
342     #[cfg(feature = "gc")]
343     gc_roots_list: GcRootsList,
344     // Types for which the embedder has created an allocator for.
345     #[cfg(feature = "gc")]
346     gc_host_alloc_types: crate::hash_set::HashSet<crate::type_registry::RegisteredType>,
347 
348     // Numbers of resources instantiated in this store, and their limits
349     instance_count: usize,
350     instance_limit: usize,
351     memory_count: usize,
352     memory_limit: usize,
353     table_count: usize,
354     table_limit: usize,
355     #[cfg(feature = "async")]
356     async_state: AsyncState,
357 
358     // If fuel_yield_interval is enabled, then we store the remaining fuel (that isn't in
359     // runtime_limits) here. The total amount of fuel is the runtime limits and reserve added
360     // together. Then when we run out of gas, we inject the yield amount from the reserve
361     // until the reserve is empty.
362     fuel_reserve: u64,
363     fuel_yield_interval: Option<NonZeroU64>,
364     /// Indexed data within this `Store`, used to store information about
365     /// globals, functions, memories, etc.
366     store_data: StoreData,
367     traitobj: StorePtr,
368     default_caller_vmctx: SendSyncPtr<VMContext>,
369 
370     /// Used to optimized wasm->host calls when the host function is defined with
371     /// `Func::new` to avoid allocating a new vector each time a function is
372     /// called.
373     hostcall_val_storage: Vec<Val>,
374     /// Same as `hostcall_val_storage`, but for the direction of the host
375     /// calling wasm.
376     wasm_val_raw_storage: Vec<ValRaw>,
377 
378     /// Keep track of what protection key is being used during allocation so
379     /// that the right memory pages can be enabled when entering WebAssembly
380     /// guest code.
381     pkey: Option<ProtectionKey>,
382 
383     /// Runtime state for components used in the handling of resources, borrow,
384     /// and calls. These also interact with the `ResourceAny` type and its
385     /// internal representation.
386     #[cfg(feature = "component-model")]
387     component_host_table: vm::component::ResourceTable,
388     #[cfg(feature = "component-model")]
389     component_calls: vm::component::CallContexts,
390     #[cfg(feature = "component-model")]
391     host_resource_data: crate::component::HostResourceData,
392 
393     /// State related to the executor of wasm code.
394     ///
395     /// For example if Pulley is enabled and configured then this will store a
396     /// Pulley interpreter.
397     executor: Executor,
398 }
399 
400 /// Executor state within `StoreOpaque`.
401 ///
402 /// Effectively stores Pulley interpreter state and handles conditional support
403 /// for Cranelift at compile time.
404 enum Executor {
405     Interpreter(Interpreter),
406     #[cfg(has_host_compiler_backend)]
407     Native,
408 }
409 
410 /// A borrowed reference to `Executor` above.
411 pub(crate) enum ExecutorRef<'a> {
412     Interpreter(InterpreterRef<'a>),
413     #[cfg(has_host_compiler_backend)]
414     Native,
415 }
416 
417 /// An RAII type to automatically mark a region of code as unsafe for GC.
418 #[doc(hidden)]
419 pub struct AutoAssertNoGc<'a> {
420     store: &'a mut StoreOpaque,
421     entered: bool,
422 }
423 
424 impl<'a> AutoAssertNoGc<'a> {
425     #[inline]
426     pub fn new(store: &'a mut StoreOpaque) -> Self {
427         let entered = if !cfg!(feature = "gc") {
428             false
429         } else if let Some(gc_store) = store.gc_store.as_mut() {
430             gc_store.gc_heap.enter_no_gc_scope();
431             true
432         } else {
433             false
434         };
435 
436         AutoAssertNoGc { store, entered }
437     }
438 
439     /// Creates an `AutoAssertNoGc` value which is forcibly "not entered" and
440     /// disables checks for no GC happening for the duration of this value.
441     ///
442     /// This is used when it is statically otherwise known that a GC doesn't
443     /// happen for the various types involved.
444     ///
445     /// # Unsafety
446     ///
447     /// This method is `unsafe` as it does not provide the same safety
448     /// guarantees as `AutoAssertNoGc::new`. It must be guaranteed by the
449     /// caller that a GC doesn't happen.
450     #[inline]
451     pub unsafe fn disabled(store: &'a mut StoreOpaque) -> Self {
452         if cfg!(debug_assertions) {
453             AutoAssertNoGc::new(store)
454         } else {
455             AutoAssertNoGc {
456                 store,
457                 entered: false,
458             }
459         }
460     }
461 }
462 
463 impl core::ops::Deref for AutoAssertNoGc<'_> {
464     type Target = StoreOpaque;
465 
466     #[inline]
467     fn deref(&self) -> &Self::Target {
468         &*self.store
469     }
470 }
471 
472 impl core::ops::DerefMut for AutoAssertNoGc<'_> {
473     #[inline]
474     fn deref_mut(&mut self) -> &mut Self::Target {
475         &mut *self.store
476     }
477 }
478 
479 impl Drop for AutoAssertNoGc<'_> {
480     #[inline]
481     fn drop(&mut self) {
482         if self.entered {
483             self.store.unwrap_gc_store_mut().gc_heap.exit_no_gc_scope();
484         }
485     }
486 }
487 
488 /// Used to associate instances with the store.
489 ///
490 /// This is needed to track if the instance was allocated explicitly with the on-demand
491 /// instance allocator.
492 struct StoreInstance {
493     handle: InstanceHandle,
494     kind: StoreInstanceKind,
495 }
496 
497 enum StoreInstanceKind {
498     /// An actual, non-dummy instance.
499     Real {
500         /// The id of this instance's module inside our owning store's
501         /// `ModuleRegistry`.
502         module_id: RegisteredModuleId,
503     },
504 
505     /// This is a dummy instance that is just an implementation detail for
506     /// something else. For example, host-created memories internally create a
507     /// dummy instance.
508     ///
509     /// Regardless of the configured instance allocator for the engine, dummy
510     /// instances always use the on-demand allocator to deallocate the instance.
511     Dummy,
512 }
513 
514 impl<T> Store<T> {
515     /// Creates a new [`Store`] to be associated with the given [`Engine`] and
516     /// `data` provided.
517     ///
518     /// The created [`Store`] will place no additional limits on the size of
519     /// linear memories or tables at runtime. Linear memories and tables will
520     /// be allowed to grow to any upper limit specified in their definitions.
521     /// The store will limit the number of instances, linear memories, and
522     /// tables created to 10,000. This can be overridden with the
523     /// [`Store::limiter`] configuration method.
524     pub fn new(engine: &Engine, data: T) -> Self {
525         let store_data = StoreData::new();
526         log::trace!("creating new store {:?}", store_data.id());
527 
528         let pkey = engine.allocator().next_available_pkey();
529 
530         let inner = StoreOpaque {
531             _marker: marker::PhantomPinned,
532             engine: engine.clone(),
533             vm_store_context: Default::default(),
534             #[cfg(feature = "stack-switching")]
535             continuations: Vec::new(),
536             instances: PrimaryMap::new(),
537             #[cfg(feature = "component-model")]
538             num_component_instances: 0,
539             signal_handler: None,
540             gc_store: None,
541             gc_roots: RootSet::default(),
542             #[cfg(feature = "gc")]
543             gc_roots_list: GcRootsList::default(),
544             #[cfg(feature = "gc")]
545             gc_host_alloc_types: Default::default(),
546             modules: ModuleRegistry::default(),
547             func_refs: FuncRefs::default(),
548             host_globals: PrimaryMap::new(),
549             instance_count: 0,
550             instance_limit: crate::DEFAULT_INSTANCE_LIMIT,
551             memory_count: 0,
552             memory_limit: crate::DEFAULT_MEMORY_LIMIT,
553             table_count: 0,
554             table_limit: crate::DEFAULT_TABLE_LIMIT,
555             #[cfg(feature = "async")]
556             async_state: AsyncState::default(),
557             fuel_reserve: 0,
558             fuel_yield_interval: None,
559             store_data,
560             traitobj: StorePtr::empty(),
561             default_caller_vmctx: SendSyncPtr::new(NonNull::dangling()),
562             hostcall_val_storage: Vec::new(),
563             wasm_val_raw_storage: Vec::new(),
564             pkey,
565             #[cfg(feature = "component-model")]
566             component_host_table: Default::default(),
567             #[cfg(feature = "component-model")]
568             component_calls: Default::default(),
569             #[cfg(feature = "component-model")]
570             host_resource_data: Default::default(),
571             #[cfg(has_host_compiler_backend)]
572             executor: if cfg!(feature = "pulley") && engine.target().is_pulley() {
573                 Executor::Interpreter(Interpreter::new(engine))
574             } else {
575                 Executor::Native
576             },
577             #[cfg(not(has_host_compiler_backend))]
578             executor: {
579                 debug_assert!(engine.target().is_pulley());
580                 Executor::Interpreter(Interpreter::new(engine))
581             },
582         };
583         let mut inner = Box::new(StoreInner {
584             inner,
585             limiter: None,
586             call_hook: None,
587             #[cfg(target_has_atomic = "64")]
588             epoch_deadline_behavior: None,
589             data: ManuallyDrop::new(data),
590         });
591 
592         inner.traitobj = StorePtr::new(NonNull::from(&mut *inner));
593 
594         // Wasmtime uses the callee argument to host functions to learn about
595         // the original pointer to the `Store` itself, allowing it to
596         // reconstruct a `StoreContextMut<T>`. When we initially call a `Func`,
597         // however, there's no "callee" to provide. To fix this we allocate a
598         // single "default callee" for the entire `Store`. This is then used as
599         // part of `Func::call` to guarantee that the `callee: *mut VMContext`
600         // is never null.
601         let module = Arc::new(wasmtime_environ::Module::default());
602         let shim = ModuleRuntimeInfo::bare(module);
603         let allocator = OnDemandInstanceAllocator::default();
604 
605         allocator
606             .validate_module(shim.env_module(), shim.offsets())
607             .unwrap();
608 
609         unsafe {
610             let id = inner
611                 .allocate_instance(
612                     AllocateInstanceKind::Dummy {
613                         allocator: &allocator,
614                     },
615                     &shim,
616                     Default::default(),
617                 )
618                 .expect("failed to allocate default callee");
619             let default_caller_vmctx = inner.instance(id).vmctx();
620             inner.default_caller_vmctx = default_caller_vmctx.into();
621         }
622 
623         Self {
624             inner: ManuallyDrop::new(inner),
625         }
626     }
627 
628     /// Access the underlying data owned by this `Store`.
629     #[inline]
630     pub fn data(&self) -> &T {
631         self.inner.data()
632     }
633 
634     /// Access the underlying data owned by this `Store`.
635     #[inline]
636     pub fn data_mut(&mut self) -> &mut T {
637         self.inner.data_mut()
638     }
639 
640     /// Consumes this [`Store`], destroying it, and returns the underlying data.
641     pub fn into_data(mut self) -> T {
642         self.inner.flush_fiber_stack();
643 
644         // This is an unsafe operation because we want to avoid having a runtime
645         // check or boolean for whether the data is actually contained within a
646         // `Store`. The data itself is stored as `ManuallyDrop` since we're
647         // manually managing the memory here, and there's also a `ManuallyDrop`
648         // around the `Box<StoreInner<T>>`. The way this works though is a bit
649         // tricky, so here's how things get dropped appropriately:
650         //
651         // * When a `Store<T>` is normally dropped, the custom destructor for
652         //   `Store<T>` will drop `T`, then the `self.inner` field. The
653         //   rustc-glue destructor runs for `Box<StoreInner<T>>` which drops
654         //   `StoreInner<T>`. This cleans up all internal fields and doesn't
655         //   touch `T` because it's wrapped in `ManuallyDrop`.
656         //
657         // * When calling this method we skip the top-level destructor for
658         //   `Store<T>` with `mem::forget`. This skips both the destructor for
659         //   `T` and the destructor for `StoreInner<T>`. We do, however, run the
660         //   destructor for `Box<StoreInner<T>>` which, like above, will skip
661         //   the destructor for `T` since it's `ManuallyDrop`.
662         //
663         // In both cases all the other fields of `StoreInner<T>` should all get
664         // dropped, and the manual management of destructors is basically
665         // between this method and `Drop for Store<T>`. Note that this also
666         // means that `Drop for StoreInner<T>` cannot access `self.data`, so
667         // there is a comment indicating this as well.
668         unsafe {
669             let mut inner = ManuallyDrop::take(&mut self.inner);
670             core::mem::forget(self);
671             ManuallyDrop::take(&mut inner.data)
672         }
673     }
674 
675     /// Configures the [`ResourceLimiter`] used to limit resource creation
676     /// within this [`Store`].
677     ///
678     /// Whenever resources such as linear memory, tables, or instances are
679     /// allocated the `limiter` specified here is invoked with the store's data
680     /// `T` and the returned [`ResourceLimiter`] is used to limit the operation
681     /// being allocated. The returned [`ResourceLimiter`] is intended to live
682     /// within the `T` itself, for example by storing a
683     /// [`StoreLimits`](crate::StoreLimits).
684     ///
685     /// Note that this limiter is only used to limit the creation/growth of
686     /// resources in the future, this does not retroactively attempt to apply
687     /// limits to the [`Store`].
688     ///
689     /// # Examples
690     ///
691     /// ```
692     /// use wasmtime::*;
693     ///
694     /// struct MyApplicationState {
695     ///     my_state: u32,
696     ///     limits: StoreLimits,
697     /// }
698     ///
699     /// let engine = Engine::default();
700     /// let my_state = MyApplicationState {
701     ///     my_state: 42,
702     ///     limits: StoreLimitsBuilder::new()
703     ///         .memory_size(1 << 20 /* 1 MB */)
704     ///         .instances(2)
705     ///         .build(),
706     /// };
707     /// let mut store = Store::new(&engine, my_state);
708     /// store.limiter(|state| &mut state.limits);
709     ///
710     /// // Creation of smaller memories is allowed
711     /// Memory::new(&mut store, MemoryType::new(1, None)).unwrap();
712     ///
713     /// // Creation of a larger memory, however, will exceed the 1MB limit we've
714     /// // configured
715     /// assert!(Memory::new(&mut store, MemoryType::new(1000, None)).is_err());
716     ///
717     /// // The number of instances in this store is limited to 2, so the third
718     /// // instance here should fail.
719     /// let module = Module::new(&engine, "(module)").unwrap();
720     /// assert!(Instance::new(&mut store, &module, &[]).is_ok());
721     /// assert!(Instance::new(&mut store, &module, &[]).is_ok());
722     /// assert!(Instance::new(&mut store, &module, &[]).is_err());
723     /// ```
724     ///
725     /// [`ResourceLimiter`]: crate::ResourceLimiter
726     pub fn limiter(
727         &mut self,
728         mut limiter: impl FnMut(&mut T) -> &mut (dyn crate::ResourceLimiter) + Send + Sync + 'static,
729     ) {
730         // Apply the limits on instances, tables, and memory given by the limiter:
731         let inner = &mut self.inner;
732         let (instance_limit, table_limit, memory_limit) = {
733             let l = limiter(&mut inner.data);
734             (l.instances(), l.tables(), l.memories())
735         };
736         let innermost = &mut inner.inner;
737         innermost.instance_limit = instance_limit;
738         innermost.table_limit = table_limit;
739         innermost.memory_limit = memory_limit;
740 
741         // Save the limiter accessor function:
742         inner.limiter = Some(ResourceLimiterInner::Sync(Box::new(limiter)));
743     }
744 
745     /// Configure a function that runs on calls and returns between WebAssembly
746     /// and host code.
747     ///
748     /// The function is passed a [`CallHook`] argument, which indicates which
749     /// state transition the VM is making.
750     ///
751     /// This function may return a [`Trap`]. If a trap is returned when an
752     /// import was called, it is immediately raised as-if the host import had
753     /// returned the trap. If a trap is returned after wasm returns to the host
754     /// then the wasm function's result is ignored and this trap is returned
755     /// instead.
756     ///
757     /// After this function returns a trap, it may be called for subsequent returns
758     /// to host or wasm code as the trap propagates to the root call.
759     #[cfg(feature = "call-hook")]
760     pub fn call_hook(
761         &mut self,
762         hook: impl FnMut(StoreContextMut<'_, T>, CallHook) -> Result<()> + Send + Sync + 'static,
763     ) {
764         self.inner.call_hook = Some(CallHookInner::Sync(Box::new(hook)));
765     }
766 
767     /// Returns the [`Engine`] that this store is associated with.
768     pub fn engine(&self) -> &Engine {
769         self.inner.engine()
770     }
771 
772     /// Perform garbage collection.
773     ///
774     /// Note that it is not required to actively call this function. GC will
775     /// automatically happen according to various internal heuristics. This is
776     /// provided if fine-grained control over the GC is desired.
777     ///
778     /// If you are calling this method after an attempted allocation failed, you
779     /// may pass in the [`GcHeapOutOfMemory`][crate::GcHeapOutOfMemory] error.
780     /// When you do so, this method will attempt to create enough space in the
781     /// GC heap for that allocation, so that it will succeed on the next
782     /// attempt.
783     ///
784     /// This method is only available when the `gc` Cargo feature is enabled.
785     #[cfg(feature = "gc")]
786     pub fn gc(&mut self, why: Option<&crate::GcHeapOutOfMemory<()>>) {
787         assert!(!self.inner.async_support());
788         self.inner.gc(why);
789     }
790 
791     /// Returns the amount fuel in this [`Store`]. When fuel is enabled, it must
792     /// be configured via [`Store::set_fuel`].
793     ///
794     /// # Errors
795     ///
796     /// This function will return an error if fuel consumption is not enabled
797     /// via [`Config::consume_fuel`](crate::Config::consume_fuel).
798     pub fn get_fuel(&self) -> Result<u64> {
799         self.inner.get_fuel()
800     }
801 
802     /// Set the fuel to this [`Store`] for wasm to consume while executing.
803     ///
804     /// For this method to work fuel consumption must be enabled via
805     /// [`Config::consume_fuel`](crate::Config::consume_fuel). By default a
806     /// [`Store`] starts with 0 fuel for wasm to execute with (meaning it will
807     /// immediately trap). This function must be called for the store to have
808     /// some fuel to allow WebAssembly to execute.
809     ///
810     /// Most WebAssembly instructions consume 1 unit of fuel. Some
811     /// instructions, such as `nop`, `drop`, `block`, and `loop`, consume 0
812     /// units, as any execution cost associated with them involves other
813     /// instructions which do consume fuel.
814     ///
815     /// Note that when fuel is entirely consumed it will cause wasm to trap.
816     ///
817     /// # Errors
818     ///
819     /// This function will return an error if fuel consumption is not enabled via
820     /// [`Config::consume_fuel`](crate::Config::consume_fuel).
821     pub fn set_fuel(&mut self, fuel: u64) -> Result<()> {
822         self.inner.set_fuel(fuel)
823     }
824 
825     /// Configures a [`Store`] to yield execution of async WebAssembly code
826     /// periodically.
827     ///
828     /// When a [`Store`] is configured to consume fuel with
829     /// [`Config::consume_fuel`](crate::Config::consume_fuel) this method will
830     /// configure WebAssembly to be suspended and control will be yielded back to the
831     /// caller every `interval` units of fuel consumed. This is only suitable with use of
832     /// a store associated with an [async config](crate::Config::async_support) because
833     /// only then are futures used and yields are possible.
834     ///
835     /// The purpose of this behavior is to ensure that futures which represent
836     /// execution of WebAssembly do not execute too long inside their
837     /// `Future::poll` method. This allows for some form of cooperative
838     /// multitasking where WebAssembly will voluntarily yield control
839     /// periodically (based on fuel consumption) back to the running thread.
840     ///
841     /// Note that futures returned by this crate will automatically flag
842     /// themselves to get re-polled if a yield happens. This means that
843     /// WebAssembly will continue to execute, just after giving the host an
844     /// opportunity to do something else.
845     ///
846     /// The `interval` parameter indicates how much fuel should be
847     /// consumed between yields of an async future. When fuel runs out wasm will trap.
848     ///
849     /// # Error
850     ///
851     /// This method will error if it is not called on a store associated with an [async
852     /// config](crate::Config::async_support).
853     pub fn fuel_async_yield_interval(&mut self, interval: Option<u64>) -> Result<()> {
854         self.inner.fuel_async_yield_interval(interval)
855     }
856 
857     /// Sets the epoch deadline to a certain number of ticks in the future.
858     ///
859     /// When the Wasm guest code is compiled with epoch-interruption
860     /// instrumentation
861     /// ([`Config::epoch_interruption()`](crate::Config::epoch_interruption)),
862     /// and when the `Engine`'s epoch is incremented
863     /// ([`Engine::increment_epoch()`](crate::Engine::increment_epoch))
864     /// past a deadline, execution can be configured to either trap or
865     /// yield and then continue.
866     ///
867     /// This deadline is always set relative to the current epoch:
868     /// `ticks_beyond_current` ticks in the future. The deadline can
869     /// be set explicitly via this method, or refilled automatically
870     /// on a yield if configured via
871     /// [`epoch_deadline_async_yield_and_update()`](Store::epoch_deadline_async_yield_and_update). After
872     /// this method is invoked, the deadline is reached when
873     /// [`Engine::increment_epoch()`] has been invoked at least
874     /// `ticks_beyond_current` times.
875     ///
876     /// By default a store will trap immediately with an epoch deadline of 0
877     /// (which has always "elapsed"). This method is required to be configured
878     /// for stores with epochs enabled to some future epoch deadline.
879     ///
880     /// See documentation on
881     /// [`Config::epoch_interruption()`](crate::Config::epoch_interruption)
882     /// for an introduction to epoch-based interruption.
883     #[cfg(target_has_atomic = "64")]
884     pub fn set_epoch_deadline(&mut self, ticks_beyond_current: u64) {
885         self.inner.set_epoch_deadline(ticks_beyond_current);
886     }
887 
888     /// Configures epoch-deadline expiration to trap.
889     ///
890     /// When epoch-interruption-instrumented code is executed on this
891     /// store and the epoch deadline is reached before completion,
892     /// with the store configured in this way, execution will
893     /// terminate with a trap as soon as an epoch check in the
894     /// instrumented code is reached.
895     ///
896     /// This behavior is the default if the store is not otherwise
897     /// configured via
898     /// [`epoch_deadline_trap()`](Store::epoch_deadline_trap),
899     /// [`epoch_deadline_callback()`](Store::epoch_deadline_callback) or
900     /// [`epoch_deadline_async_yield_and_update()`](Store::epoch_deadline_async_yield_and_update).
901     ///
902     /// This setting is intended to allow for coarse-grained
903     /// interruption, but not a deterministic deadline of a fixed,
904     /// finite interval. For deterministic interruption, see the
905     /// "fuel" mechanism instead.
906     ///
907     /// Note that when this is used it's required to call
908     /// [`Store::set_epoch_deadline`] or otherwise wasm will always immediately
909     /// trap.
910     ///
911     /// See documentation on
912     /// [`Config::epoch_interruption()`](crate::Config::epoch_interruption)
913     /// for an introduction to epoch-based interruption.
914     #[cfg(target_has_atomic = "64")]
915     pub fn epoch_deadline_trap(&mut self) {
916         self.inner.epoch_deadline_trap();
917     }
918 
919     /// Configures epoch-deadline expiration to invoke a custom callback
920     /// function.
921     ///
922     /// When epoch-interruption-instrumented code is executed on this
923     /// store and the epoch deadline is reached before completion, the
924     /// provided callback function is invoked.
925     ///
926     /// This callback should either return an [`UpdateDeadline`], or
927     /// return an error, which will terminate execution with a trap.
928     ///
929     /// The [`UpdateDeadline`] is a positive number of ticks to
930     /// add to the epoch deadline, as well as indicating what
931     /// to do after the callback returns. If the [`Store`] is
932     /// configured with async support, then the callback may return
933     /// [`UpdateDeadline::Yield`] or [`UpdateDeadline::YieldCustom`]
934     /// to yield to the async executor before updating the epoch deadline.
935     /// Alternatively, the callback may return [`UpdateDeadline::Continue`] to
936     /// update the epoch deadline immediately.
937     ///
938     /// This setting is intended to allow for coarse-grained
939     /// interruption, but not a deterministic deadline of a fixed,
940     /// finite interval. For deterministic interruption, see the
941     /// "fuel" mechanism instead.
942     ///
943     /// See documentation on
944     /// [`Config::epoch_interruption()`](crate::Config::epoch_interruption)
945     /// for an introduction to epoch-based interruption.
946     #[cfg(target_has_atomic = "64")]
947     pub fn epoch_deadline_callback(
948         &mut self,
949         callback: impl FnMut(StoreContextMut<T>) -> Result<UpdateDeadline> + Send + Sync + 'static,
950     ) {
951         self.inner.epoch_deadline_callback(Box::new(callback));
952     }
953 }
954 
955 impl<'a, T> StoreContext<'a, T> {
956     pub(crate) fn async_support(&self) -> bool {
957         self.0.async_support()
958     }
959 
960     /// Returns the underlying [`Engine`] this store is connected to.
961     pub fn engine(&self) -> &Engine {
962         self.0.engine()
963     }
964 
965     /// Access the underlying data owned by this `Store`.
966     ///
967     /// Same as [`Store::data`].
968     pub fn data(&self) -> &'a T {
969         self.0.data()
970     }
971 
972     /// Returns the remaining fuel in this store.
973     ///
974     /// For more information see [`Store::get_fuel`].
975     pub fn get_fuel(&self) -> Result<u64> {
976         self.0.get_fuel()
977     }
978 }
979 
980 impl<'a, T> StoreContextMut<'a, T> {
981     /// Access the underlying data owned by this `Store`.
982     ///
983     /// Same as [`Store::data`].
984     pub fn data(&self) -> &T {
985         self.0.data()
986     }
987 
988     /// Access the underlying data owned by this `Store`.
989     ///
990     /// Same as [`Store::data_mut`].
991     pub fn data_mut(&mut self) -> &mut T {
992         self.0.data_mut()
993     }
994 
995     /// Returns the underlying [`Engine`] this store is connected to.
996     pub fn engine(&self) -> &Engine {
997         self.0.engine()
998     }
999 
1000     /// Perform garbage collection of `ExternRef`s.
1001     ///
1002     /// Same as [`Store::gc`].
1003     ///
1004     /// This method is only available when the `gc` Cargo feature is enabled.
1005     #[cfg(feature = "gc")]
1006     pub fn gc(&mut self, why: Option<&crate::GcHeapOutOfMemory<()>>) {
1007         self.0.gc(why);
1008     }
1009 
1010     /// Returns remaining fuel in this store.
1011     ///
1012     /// For more information see [`Store::get_fuel`]
1013     pub fn get_fuel(&self) -> Result<u64> {
1014         self.0.get_fuel()
1015     }
1016 
1017     /// Set the amount of fuel in this store.
1018     ///
1019     /// For more information see [`Store::set_fuel`]
1020     pub fn set_fuel(&mut self, fuel: u64) -> Result<()> {
1021         self.0.set_fuel(fuel)
1022     }
1023 
1024     /// Configures this `Store` to periodically yield while executing futures.
1025     ///
1026     /// For more information see [`Store::fuel_async_yield_interval`]
1027     pub fn fuel_async_yield_interval(&mut self, interval: Option<u64>) -> Result<()> {
1028         self.0.fuel_async_yield_interval(interval)
1029     }
1030 
1031     /// Sets the epoch deadline to a certain number of ticks in the future.
1032     ///
1033     /// For more information see [`Store::set_epoch_deadline`].
1034     #[cfg(target_has_atomic = "64")]
1035     pub fn set_epoch_deadline(&mut self, ticks_beyond_current: u64) {
1036         self.0.set_epoch_deadline(ticks_beyond_current);
1037     }
1038 
1039     /// Configures epoch-deadline expiration to trap.
1040     ///
1041     /// For more information see [`Store::epoch_deadline_trap`].
1042     #[cfg(target_has_atomic = "64")]
1043     pub fn epoch_deadline_trap(&mut self) {
1044         self.0.epoch_deadline_trap();
1045     }
1046 }
1047 
1048 impl<T> StoreInner<T> {
1049     #[inline]
1050     fn data(&self) -> &T {
1051         &self.data
1052     }
1053 
1054     #[inline]
1055     fn data_mut(&mut self) -> &mut T {
1056         &mut self.data
1057     }
1058 
1059     #[inline]
1060     pub fn call_hook(&mut self, s: CallHook) -> Result<()> {
1061         if self.inner.pkey.is_none() && self.call_hook.is_none() {
1062             Ok(())
1063         } else {
1064             self.call_hook_slow_path(s)
1065         }
1066     }
1067 
1068     fn call_hook_slow_path(&mut self, s: CallHook) -> Result<()> {
1069         if let Some(pkey) = &self.inner.pkey {
1070             let allocator = self.engine().allocator();
1071             match s {
1072                 CallHook::CallingWasm | CallHook::ReturningFromHost => {
1073                     allocator.restrict_to_pkey(*pkey)
1074                 }
1075                 CallHook::ReturningFromWasm | CallHook::CallingHost => allocator.allow_all_pkeys(),
1076             }
1077         }
1078 
1079         // Temporarily take the configured behavior to avoid mutably borrowing
1080         // multiple times.
1081         #[cfg_attr(not(feature = "call-hook"), allow(unreachable_patterns))]
1082         if let Some(mut call_hook) = self.call_hook.take() {
1083             let result = self.invoke_call_hook(&mut call_hook, s);
1084             self.call_hook = Some(call_hook);
1085             return result;
1086         }
1087 
1088         Ok(())
1089     }
1090 
1091     fn invoke_call_hook(&mut self, call_hook: &mut CallHookInner<T>, s: CallHook) -> Result<()> {
1092         match call_hook {
1093             #[cfg(feature = "call-hook")]
1094             CallHookInner::Sync(hook) => hook((&mut *self).as_context_mut(), s),
1095 
1096             #[cfg(all(feature = "async", feature = "call-hook"))]
1097             CallHookInner::Async(handler) => unsafe {
1098                 self.inner
1099                     .async_cx()
1100                     .ok_or_else(|| anyhow!("couldn't grab async_cx for call hook"))?
1101                     .block_on(
1102                         handler
1103                             .handle_call_event((&mut *self).as_context_mut(), s)
1104                             .as_mut(),
1105                     )?
1106             },
1107 
1108             CallHookInner::ForceTypeParameterToBeUsed { uninhabited, .. } => {
1109                 let _ = s;
1110                 match *uninhabited {}
1111             }
1112         }
1113     }
1114 
1115     #[cfg(not(feature = "async"))]
1116     fn flush_fiber_stack(&mut self) {
1117         // noop shim so code can assume this always exists.
1118     }
1119 }
1120 
1121 fn get_fuel(injected_fuel: i64, fuel_reserve: u64) -> u64 {
1122     fuel_reserve.saturating_add_signed(-injected_fuel)
1123 }
1124 
1125 // Add remaining fuel from the reserve into the active fuel if there is any left.
1126 fn refuel(
1127     injected_fuel: &mut i64,
1128     fuel_reserve: &mut u64,
1129     yield_interval: Option<NonZeroU64>,
1130 ) -> bool {
1131     let fuel = get_fuel(*injected_fuel, *fuel_reserve);
1132     if fuel > 0 {
1133         set_fuel(injected_fuel, fuel_reserve, yield_interval, fuel);
1134         true
1135     } else {
1136         false
1137     }
1138 }
1139 
1140 fn set_fuel(
1141     injected_fuel: &mut i64,
1142     fuel_reserve: &mut u64,
1143     yield_interval: Option<NonZeroU64>,
1144     new_fuel_amount: u64,
1145 ) {
1146     let interval = yield_interval.unwrap_or(NonZeroU64::MAX).get();
1147     // If we're yielding periodically we only store the "active" amount of fuel into consumed_ptr
1148     // for the VM to use.
1149     let injected = core::cmp::min(interval, new_fuel_amount);
1150     // Fuel in the VM is stored as an i64, so we have to cap the amount of fuel we inject into the
1151     // VM at once to be i64 range.
1152     let injected = core::cmp::min(injected, i64::MAX as u64);
1153     // Add whatever is left over after injection to the reserve for later use.
1154     *fuel_reserve = new_fuel_amount - injected;
1155     // Within the VM we increment to count fuel, so inject a negative amount. The VM will halt when
1156     // this counter is positive.
1157     *injected_fuel = -(injected as i64);
1158 }
1159 
1160 #[doc(hidden)]
1161 impl StoreOpaque {
1162     pub fn id(&self) -> StoreId {
1163         self.store_data.id()
1164     }
1165 
1166     pub fn bump_resource_counts(&mut self, module: &Module) -> Result<()> {
1167         fn bump(slot: &mut usize, max: usize, amt: usize, desc: &str) -> Result<()> {
1168             let new = slot.saturating_add(amt);
1169             if new > max {
1170                 bail!(
1171                     "resource limit exceeded: {} count too high at {}",
1172                     desc,
1173                     new
1174                 );
1175             }
1176             *slot = new;
1177             Ok(())
1178         }
1179 
1180         let module = module.env_module();
1181         let memories = module.num_defined_memories();
1182         let tables = module.num_defined_tables();
1183 
1184         bump(&mut self.instance_count, self.instance_limit, 1, "instance")?;
1185         bump(
1186             &mut self.memory_count,
1187             self.memory_limit,
1188             memories,
1189             "memory",
1190         )?;
1191         bump(&mut self.table_count, self.table_limit, tables, "table")?;
1192 
1193         Ok(())
1194     }
1195 
1196     #[inline]
1197     pub fn async_support(&self) -> bool {
1198         cfg!(feature = "async") && self.engine().config().async_support
1199     }
1200 
1201     #[inline]
1202     pub fn engine(&self) -> &Engine {
1203         &self.engine
1204     }
1205 
1206     #[inline]
1207     pub fn store_data(&self) -> &StoreData {
1208         &self.store_data
1209     }
1210 
1211     #[inline]
1212     pub fn store_data_mut(&mut self) -> &mut StoreData {
1213         &mut self.store_data
1214     }
1215 
1216     #[inline]
1217     pub(crate) fn modules(&self) -> &ModuleRegistry {
1218         &self.modules
1219     }
1220 
1221     #[inline]
1222     pub(crate) fn modules_mut(&mut self) -> &mut ModuleRegistry {
1223         &mut self.modules
1224     }
1225 
1226     pub(crate) fn func_refs_and_modules(&mut self) -> (&mut FuncRefs, &ModuleRegistry) {
1227         (&mut self.func_refs, &self.modules)
1228     }
1229 
1230     pub(crate) fn host_globals(
1231         &self,
1232     ) -> &PrimaryMap<DefinedGlobalIndex, StoreBox<VMHostGlobalContext>> {
1233         &self.host_globals
1234     }
1235 
1236     pub(crate) fn host_globals_mut(
1237         &mut self,
1238     ) -> &mut PrimaryMap<DefinedGlobalIndex, StoreBox<VMHostGlobalContext>> {
1239         &mut self.host_globals
1240     }
1241 
1242     pub fn module_for_instance(&self, instance: StoreInstanceId) -> Option<&'_ Module> {
1243         instance.store_id().assert_belongs_to(self.id());
1244         match self.instances[instance.instance()].kind {
1245             StoreInstanceKind::Dummy => None,
1246             StoreInstanceKind::Real { module_id } => {
1247                 let module = self
1248                     .modules()
1249                     .lookup_module_by_id(module_id)
1250                     .expect("should always have a registered module for real instances");
1251                 Some(module)
1252             }
1253         }
1254     }
1255 
1256     /// Accessor from `InstanceId` to `&vm::Instance`.
1257     ///
1258     /// Note that if you have a `StoreInstanceId` you should use
1259     /// `StoreInstanceId::get` instead. This assumes that `id` has been
1260     /// validated to already belong to this store.
1261     pub fn instance(&self, id: InstanceId) -> &vm::Instance {
1262         self.instances[id].handle.get()
1263     }
1264 
1265     /// Accessor from `InstanceId` to `Pin<&mut vm::Instance>`.
1266     ///
1267     /// Note that if you have a `StoreInstanceId` you should use
1268     /// `StoreInstanceId::get_mut` instead. This assumes that `id` has been
1269     /// validated to already belong to this store.
1270     pub fn instance_mut(&mut self, id: InstanceId) -> Pin<&mut vm::Instance> {
1271         self.instances[id].handle.get_mut()
1272     }
1273 
1274     /// Get all instances (ignoring dummy instances) within this store.
1275     pub fn all_instances<'a>(&'a mut self) -> impl ExactSizeIterator<Item = Instance> + 'a {
1276         let instances = self
1277             .instances
1278             .iter()
1279             .filter_map(|(id, inst)| {
1280                 if let StoreInstanceKind::Dummy = inst.kind {
1281                     None
1282                 } else {
1283                     Some(id)
1284                 }
1285             })
1286             .collect::<Vec<_>>();
1287         instances
1288             .into_iter()
1289             .map(|i| Instance::from_wasmtime(i, self))
1290     }
1291 
1292     /// Get all memories (host- or Wasm-defined) within this store.
1293     pub fn all_memories<'a>(&'a mut self) -> impl Iterator<Item = Memory> + 'a {
1294         // NB: Host-created memories have dummy instances. Therefore, we can get
1295         // all memories in the store by iterating over all instances (including
1296         // dummy instances) and getting each of their defined memories.
1297         let mems = self
1298             .instances
1299             .iter_mut()
1300             .flat_map(|(_, instance)| instance.handle.get().defined_memories())
1301             .collect::<Vec<_>>();
1302         mems.into_iter()
1303             .map(|memory| unsafe { Memory::from_wasmtime_memory(memory, self) })
1304     }
1305 
1306     /// Iterate over all tables (host- or Wasm-defined) within this store.
1307     pub fn for_each_table(&mut self, mut f: impl FnMut(&mut Self, Table)) {
1308         // NB: Host-created tables have dummy instances. Therefore, we can get
1309         // all tables in the store by iterating over all instances (including
1310         // dummy instances) and getting each of their defined memories.
1311         for id in self.instances.keys() {
1312             let instance = StoreInstanceId::new(self.id(), id);
1313             for table in 0..self.instance(id).env_module().num_defined_tables() {
1314                 let table = DefinedTableIndex::new(table);
1315                 f(self, Table::from_raw(instance, table));
1316             }
1317         }
1318     }
1319 
1320     /// Iterate over all globals (host- or Wasm-defined) within this store.
1321     pub fn for_each_global(&mut self, mut f: impl FnMut(&mut Self, Global)) {
1322         // First enumerate all the host-created globals.
1323         for global in self.host_globals.keys() {
1324             let global = Global::new_host(self, global);
1325             f(self, global);
1326         }
1327 
1328         // Then enumerate all instances' defined globals.
1329         for id in self.instances.keys() {
1330             for index in 0..self.instance(id).env_module().num_defined_globals() {
1331                 let index = DefinedGlobalIndex::new(index);
1332                 let global = Global::new_instance(self, id, index);
1333                 f(self, global);
1334             }
1335         }
1336     }
1337 
1338     #[cfg_attr(not(target_os = "linux"), allow(dead_code))] // not used on all platforms
1339     pub fn set_signal_handler(&mut self, handler: Option<SignalHandler>) {
1340         self.signal_handler = handler;
1341     }
1342 
1343     #[inline]
1344     pub fn vm_store_context(&self) -> &VMStoreContext {
1345         &self.vm_store_context
1346     }
1347 
1348     #[inline(never)]
1349     pub(crate) fn allocate_gc_heap(&mut self) -> Result<()> {
1350         log::trace!("allocating GC heap for store {:?}", self.id());
1351 
1352         assert!(self.gc_store.is_none());
1353         assert_eq!(
1354             self.vm_store_context.gc_heap.base.as_non_null(),
1355             NonNull::dangling(),
1356         );
1357         assert_eq!(self.vm_store_context.gc_heap.current_length(), 0);
1358 
1359         let vmstore = self.traitobj();
1360         let gc_store = allocate_gc_store(self.engine(), vmstore, self.get_pkey())?;
1361         self.vm_store_context.gc_heap = gc_store.vmmemory_definition();
1362         self.gc_store = Some(gc_store);
1363         return Ok(());
1364 
1365         #[cfg(feature = "gc")]
1366         fn allocate_gc_store(
1367             engine: &Engine,
1368             vmstore: NonNull<dyn vm::VMStore>,
1369             pkey: Option<ProtectionKey>,
1370         ) -> Result<GcStore> {
1371             use wasmtime_environ::packed_option::ReservedValue;
1372 
1373             ensure!(
1374                 engine.features().gc_types(),
1375                 "cannot allocate a GC store when GC is disabled at configuration time"
1376             );
1377 
1378             // First, allocate the memory that will be our GC heap's storage.
1379             let mut request = InstanceAllocationRequest {
1380                 id: InstanceId::reserved_value(),
1381                 runtime_info: &ModuleRuntimeInfo::bare(Arc::new(
1382                     wasmtime_environ::Module::default(),
1383                 )),
1384                 imports: vm::Imports::default(),
1385                 store: StorePtr::new(vmstore),
1386                 wmemcheck: false,
1387                 pkey,
1388                 tunables: engine.tunables(),
1389             };
1390             let mem_ty = engine.tunables().gc_heap_memory_type();
1391             let tunables = engine.tunables();
1392 
1393             // SAFETY: We validated the GC heap's memory type during engine creation.
1394             let (mem_alloc_index, mem) = unsafe {
1395                 engine
1396                     .allocator()
1397                     .allocate_memory(&mut request, &mem_ty, tunables, None)?
1398             };
1399 
1400             // Then, allocate the actual GC heap, passing in that memory
1401             // storage.
1402             let (index, heap) = engine.allocator().allocate_gc_heap(
1403                 engine,
1404                 &**engine.gc_runtime()?,
1405                 mem_alloc_index,
1406                 mem,
1407             )?;
1408 
1409             Ok(GcStore::new(index, heap))
1410         }
1411 
1412         #[cfg(not(feature = "gc"))]
1413         fn allocate_gc_store(
1414             _engine: &Engine,
1415             _vmstore: NonNull<dyn vm::VMStore>,
1416             _pkey: Option<ProtectionKey>,
1417         ) -> Result<GcStore> {
1418             bail!("cannot allocate a GC store: the `gc` feature was disabled at compile time")
1419         }
1420     }
1421 
1422     #[inline]
1423     pub(crate) fn gc_store(&self) -> Result<&GcStore> {
1424         match &self.gc_store {
1425             Some(gc_store) => Ok(gc_store),
1426             None => bail!("GC heap not initialized yet"),
1427         }
1428     }
1429 
1430     #[inline]
1431     pub(crate) fn gc_store_mut(&mut self) -> Result<&mut GcStore> {
1432         if self.gc_store.is_none() {
1433             self.allocate_gc_heap()?;
1434         }
1435         Ok(self.unwrap_gc_store_mut())
1436     }
1437 
1438     /// If this store is configured with a GC heap, return a mutable reference
1439     /// to it. Otherwise, return `None`.
1440     #[inline]
1441     pub(crate) fn optional_gc_store_mut(&mut self) -> Option<&mut GcStore> {
1442         if cfg!(not(feature = "gc")) || !self.engine.features().gc_types() {
1443             debug_assert!(self.gc_store.is_none());
1444             None
1445         } else {
1446             self.gc_store.as_mut()
1447         }
1448     }
1449 
1450     /// If this store is configured with a GC heap, return a shared reference to
1451     /// it. Otherwise, return `None`.
1452     #[inline]
1453     #[cfg(feature = "gc")]
1454     pub(crate) fn optional_gc_store(&self) -> Option<&GcStore> {
1455         if cfg!(not(feature = "gc")) || !self.engine.features().gc_types() {
1456             debug_assert!(self.gc_store.is_none());
1457             None
1458         } else {
1459             self.gc_store.as_ref()
1460         }
1461     }
1462 
1463     #[inline]
1464     #[track_caller]
1465     #[cfg(feature = "gc")]
1466     pub(crate) fn unwrap_gc_store(&self) -> &GcStore {
1467         self.gc_store
1468             .as_ref()
1469             .expect("attempted to access the store's GC heap before it has been allocated")
1470     }
1471 
1472     #[inline]
1473     #[track_caller]
1474     pub(crate) fn unwrap_gc_store_mut(&mut self) -> &mut GcStore {
1475         self.gc_store
1476             .as_mut()
1477             .expect("attempted to access the store's GC heap before it has been allocated")
1478     }
1479 
1480     #[inline]
1481     pub(crate) fn gc_roots(&self) -> &RootSet {
1482         &self.gc_roots
1483     }
1484 
1485     #[inline]
1486     #[cfg(feature = "gc")]
1487     pub(crate) fn gc_roots_mut(&mut self) -> &mut RootSet {
1488         &mut self.gc_roots
1489     }
1490 
1491     #[inline]
1492     pub(crate) fn exit_gc_lifo_scope(&mut self, scope: usize) {
1493         self.gc_roots.exit_lifo_scope(self.gc_store.as_mut(), scope);
1494     }
1495 
1496     #[cfg(feature = "gc")]
1497     fn do_gc(&mut self) {
1498         assert!(
1499             !self.async_support(),
1500             "must use `store.gc_async()` instead of `store.gc()` for async stores"
1501         );
1502 
1503         // If the GC heap hasn't been initialized, there is nothing to collect.
1504         if self.gc_store.is_none() {
1505             return;
1506         }
1507 
1508         log::trace!("============ Begin GC ===========");
1509 
1510         // Take the GC roots out of `self` so we can borrow it mutably but still
1511         // call mutable methods on `self`.
1512         let mut roots = core::mem::take(&mut self.gc_roots_list);
1513 
1514         self.trace_roots(&mut roots);
1515         self.unwrap_gc_store_mut().gc(unsafe { roots.iter() });
1516 
1517         // Restore the GC roots for the next GC.
1518         roots.clear();
1519         self.gc_roots_list = roots;
1520 
1521         log::trace!("============ End GC ===========");
1522     }
1523 
1524     #[cfg(feature = "gc")]
1525     fn trace_roots(&mut self, gc_roots_list: &mut GcRootsList) {
1526         log::trace!("Begin trace GC roots");
1527 
1528         // We shouldn't have any leftover, stale GC roots.
1529         assert!(gc_roots_list.is_empty());
1530 
1531         self.trace_wasm_stack_roots(gc_roots_list);
1532         #[cfg(feature = "stack-switching")]
1533         self.trace_wasm_continuation_roots(gc_roots_list);
1534         self.trace_vmctx_roots(gc_roots_list);
1535         self.trace_user_roots(gc_roots_list);
1536 
1537         log::trace!("End trace GC roots")
1538     }
1539 
1540     #[cfg(feature = "gc")]
1541     fn trace_wasm_stack_frame(
1542         &self,
1543         gc_roots_list: &mut GcRootsList,
1544         frame: crate::runtime::vm::Frame,
1545     ) {
1546         use crate::runtime::vm::SendSyncPtr;
1547         use core::ptr::NonNull;
1548 
1549         let pc = frame.pc();
1550         debug_assert!(pc != 0, "we should always get a valid PC for Wasm frames");
1551 
1552         let fp = frame.fp() as *mut usize;
1553         debug_assert!(
1554             !fp.is_null(),
1555             "we should always get a valid frame pointer for Wasm frames"
1556         );
1557 
1558         let module_info = self
1559             .modules()
1560             .lookup_module_by_pc(pc)
1561             .expect("should have module info for Wasm frame");
1562 
1563         let stack_map = match module_info.lookup_stack_map(pc) {
1564             Some(sm) => sm,
1565             None => {
1566                 log::trace!("No stack map for this Wasm frame");
1567                 return;
1568             }
1569         };
1570         log::trace!(
1571             "We have a stack map that maps {} bytes in this Wasm frame",
1572             stack_map.frame_size()
1573         );
1574 
1575         let sp = unsafe { stack_map.sp(fp) };
1576         for stack_slot in unsafe { stack_map.live_gc_refs(sp) } {
1577             let raw: u32 = unsafe { core::ptr::read(stack_slot) };
1578             log::trace!("Stack slot @ {stack_slot:p} = {raw:#x}");
1579 
1580             let gc_ref = VMGcRef::from_raw_u32(raw);
1581             if gc_ref.is_some() {
1582                 unsafe {
1583                     gc_roots_list
1584                         .add_wasm_stack_root(SendSyncPtr::new(NonNull::new(stack_slot).unwrap()));
1585                 }
1586             }
1587         }
1588     }
1589 
1590     #[cfg(feature = "gc")]
1591     fn trace_wasm_stack_roots(&mut self, gc_roots_list: &mut GcRootsList) {
1592         use crate::runtime::vm::Backtrace;
1593         log::trace!("Begin trace GC roots :: Wasm stack");
1594 
1595         Backtrace::trace(self, |frame| {
1596             self.trace_wasm_stack_frame(gc_roots_list, frame);
1597             core::ops::ControlFlow::Continue(())
1598         });
1599 
1600         log::trace!("End trace GC roots :: Wasm stack");
1601     }
1602 
1603     #[cfg(all(feature = "gc", feature = "stack-switching"))]
1604     fn trace_wasm_continuation_roots(&mut self, gc_roots_list: &mut GcRootsList) {
1605         use crate::{runtime::vm::Backtrace, vm::VMStackState};
1606         log::trace!("Begin trace GC roots :: continuations");
1607 
1608         for continuation in &self.continuations {
1609             let state = continuation.common_stack_information.state;
1610 
1611             // FIXME(frank-emrich) In general, it is not enough to just trace
1612             // through the stacks of continuations; we also need to look through
1613             // their `cont.bind` arguments. However, we don't currently have
1614             // enough RTTI information to check if any of the values in the
1615             // buffers used by `cont.bind` are GC values. As a workaround, note
1616             // that we currently disallow cont.bind-ing GC values altogether.
1617             // This way, it is okay not to check them here.
1618             match state {
1619                 VMStackState::Suspended => {
1620                     Backtrace::trace_suspended_continuation(self, continuation.deref(), |frame| {
1621                         self.trace_wasm_stack_frame(gc_roots_list, frame);
1622                         core::ops::ControlFlow::Continue(())
1623                     });
1624                 }
1625                 VMStackState::Running => {
1626                     // Handled by `trace_wasm_stack_roots`.
1627                 }
1628                 VMStackState::Parent => {
1629                     // We don't know whether our child is suspended or running, but in
1630                     // either case things should be hanlded correctly when traversing
1631                     // further along in the chain, nothing required at this point.
1632                 }
1633                 VMStackState::Fresh | VMStackState::Returned => {
1634                     // Fresh/Returned continuations have no gc values on their stack.
1635                 }
1636             }
1637         }
1638 
1639         log::trace!("End trace GC roots :: continuations");
1640     }
1641 
1642     #[cfg(feature = "gc")]
1643     fn trace_vmctx_roots(&mut self, gc_roots_list: &mut GcRootsList) {
1644         log::trace!("Begin trace GC roots :: vmctx");
1645         self.for_each_global(|store, global| global.trace_root(store, gc_roots_list));
1646         self.for_each_table(|store, table| table.trace_roots(store, gc_roots_list));
1647         log::trace!("End trace GC roots :: vmctx");
1648     }
1649 
1650     #[cfg(feature = "gc")]
1651     fn trace_user_roots(&mut self, gc_roots_list: &mut GcRootsList) {
1652         log::trace!("Begin trace GC roots :: user");
1653         self.gc_roots.trace_roots(gc_roots_list);
1654         log::trace!("End trace GC roots :: user");
1655     }
1656 
1657     /// Insert a host-allocated GC type into this store.
1658     ///
1659     /// This makes it suitable for the embedder to allocate instances of this
1660     /// type in this store, and we don't have to worry about the type being
1661     /// reclaimed (since it is possible that none of the Wasm modules in this
1662     /// store are holding it alive).
1663     #[cfg(feature = "gc")]
1664     pub(crate) fn insert_gc_host_alloc_type(&mut self, ty: crate::type_registry::RegisteredType) {
1665         self.gc_host_alloc_types.insert(ty);
1666     }
1667 
1668     pub fn get_fuel(&self) -> Result<u64> {
1669         anyhow::ensure!(
1670             self.engine().tunables().consume_fuel,
1671             "fuel is not configured in this store"
1672         );
1673         let injected_fuel = unsafe { *self.vm_store_context.fuel_consumed.get() };
1674         Ok(get_fuel(injected_fuel, self.fuel_reserve))
1675     }
1676 
1677     fn refuel(&mut self) -> bool {
1678         let injected_fuel = unsafe { &mut *self.vm_store_context.fuel_consumed.get() };
1679         refuel(
1680             injected_fuel,
1681             &mut self.fuel_reserve,
1682             self.fuel_yield_interval,
1683         )
1684     }
1685 
1686     pub fn set_fuel(&mut self, fuel: u64) -> Result<()> {
1687         anyhow::ensure!(
1688             self.engine().tunables().consume_fuel,
1689             "fuel is not configured in this store"
1690         );
1691         let injected_fuel = unsafe { &mut *self.vm_store_context.fuel_consumed.get() };
1692         set_fuel(
1693             injected_fuel,
1694             &mut self.fuel_reserve,
1695             self.fuel_yield_interval,
1696             fuel,
1697         );
1698         Ok(())
1699     }
1700 
1701     pub fn fuel_async_yield_interval(&mut self, interval: Option<u64>) -> Result<()> {
1702         anyhow::ensure!(
1703             self.engine().tunables().consume_fuel,
1704             "fuel is not configured in this store"
1705         );
1706         anyhow::ensure!(
1707             self.engine().config().async_support,
1708             "async support is not configured in this store"
1709         );
1710         anyhow::ensure!(
1711             interval != Some(0),
1712             "fuel_async_yield_interval must not be 0"
1713         );
1714         self.fuel_yield_interval = interval.and_then(|i| NonZeroU64::new(i));
1715         // Reset the fuel active + reserve states by resetting the amount.
1716         self.set_fuel(self.get_fuel()?)
1717     }
1718 
1719     #[inline]
1720     pub fn signal_handler(&self) -> Option<*const SignalHandler> {
1721         let handler = self.signal_handler.as_ref()?;
1722         Some(handler)
1723     }
1724 
1725     #[inline]
1726     pub fn vm_store_context_ptr(&self) -> NonNull<VMStoreContext> {
1727         NonNull::from(&self.vm_store_context)
1728     }
1729 
1730     #[inline]
1731     pub fn default_caller(&self) -> NonNull<VMContext> {
1732         self.default_caller_vmctx.as_non_null()
1733     }
1734 
1735     #[inline]
1736     pub fn traitobj(&self) -> NonNull<dyn vm::VMStore> {
1737         self.traitobj.as_raw().unwrap()
1738     }
1739 
1740     #[inline]
1741     pub fn traitobj_mut(&mut self) -> &mut dyn vm::VMStore {
1742         unsafe { self.traitobj().as_mut() }
1743     }
1744 
1745     /// Takes the cached `Vec<Val>` stored internally across hostcalls to get
1746     /// used as part of calling the host in a `Func::new` method invocation.
1747     #[inline]
1748     pub fn take_hostcall_val_storage(&mut self) -> Vec<Val> {
1749         mem::take(&mut self.hostcall_val_storage)
1750     }
1751 
1752     /// Restores the vector previously taken by `take_hostcall_val_storage`
1753     /// above back into the store, allowing it to be used in the future for the
1754     /// next wasm->host call.
1755     #[inline]
1756     pub fn save_hostcall_val_storage(&mut self, storage: Vec<Val>) {
1757         if storage.capacity() > self.hostcall_val_storage.capacity() {
1758             self.hostcall_val_storage = storage;
1759         }
1760     }
1761 
1762     /// Same as `take_hostcall_val_storage`, but for the direction of the host
1763     /// calling wasm.
1764     #[inline]
1765     pub fn take_wasm_val_raw_storage(&mut self) -> Vec<ValRaw> {
1766         mem::take(&mut self.wasm_val_raw_storage)
1767     }
1768 
1769     /// Same as `save_hostcall_val_storage`, but for the direction of the host
1770     /// calling wasm.
1771     #[inline]
1772     pub fn save_wasm_val_raw_storage(&mut self, storage: Vec<ValRaw>) {
1773         if storage.capacity() > self.wasm_val_raw_storage.capacity() {
1774             self.wasm_val_raw_storage = storage;
1775         }
1776     }
1777 
1778     /// Translates a WebAssembly fault at the native `pc` and native `addr` to a
1779     /// WebAssembly-relative fault.
1780     ///
1781     /// This function may abort the process if `addr` is not found to actually
1782     /// reside in any linear memory. In such a situation it means that the
1783     /// segfault was erroneously caught by Wasmtime and is possibly indicative
1784     /// of a code generator bug.
1785     ///
1786     /// This function returns `None` for dynamically-bounds-checked-memories
1787     /// with spectre mitigations enabled since the hardware fault address is
1788     /// always zero in these situations which means that the trapping context
1789     /// doesn't have enough information to report the fault address.
1790     pub(crate) fn wasm_fault(&self, pc: usize, addr: usize) -> Option<vm::WasmFault> {
1791         // There are a few instances where a "close to zero" pointer is loaded
1792         // and we expect that to happen:
1793         //
1794         // * Explicitly bounds-checked memories with spectre-guards enabled will
1795         //   cause out-of-bounds accesses to get routed to address 0, so allow
1796         //   wasm instructions to fault on the null address.
1797         // * `call_indirect` when invoking a null function pointer may load data
1798         //   from the a `VMFuncRef` whose address is null, meaning any field of
1799         //   `VMFuncRef` could be the address of the fault.
1800         //
1801         // In these situations where the address is so small it won't be in any
1802         // instance, so skip the checks below.
1803         if addr <= mem::size_of::<VMFuncRef>() {
1804             const _: () = {
1805                 // static-assert that `VMFuncRef` isn't too big to ensure that
1806                 // it lives solely within the first page as we currently only
1807                 // have the guarantee that the first page of memory is unmapped,
1808                 // no more.
1809                 assert!(mem::size_of::<VMFuncRef>() <= 512);
1810             };
1811             return None;
1812         }
1813 
1814         // Search all known instances in this store for this address. Note that
1815         // this is probably not the speediest way to do this. Traps, however,
1816         // are generally not expected to be super fast and additionally stores
1817         // probably don't have all that many instances or memories.
1818         //
1819         // If this loop becomes hot in the future, however, it should be
1820         // possible to precompute maps about linear memories in a store and have
1821         // a quicker lookup.
1822         let mut fault = None;
1823         for (_, instance) in self.instances.iter() {
1824             if let Some(f) = instance.handle.get().wasm_fault(addr) {
1825                 assert!(fault.is_none());
1826                 fault = Some(f);
1827             }
1828         }
1829         if fault.is_some() {
1830             return fault;
1831         }
1832 
1833         cfg_if::cfg_if! {
1834             if #[cfg(any(feature = "std", unix, windows))] {
1835                 // With the standard library a rich error can be printed here
1836                 // to stderr and the native abort path is used.
1837                 eprintln!(
1838                     "\
1839 Wasmtime caught a segfault for a wasm program because the faulting instruction
1840 is allowed to segfault due to how linear memories are implemented. The address
1841 that was accessed, however, is not known to any linear memory in use within this
1842 Store. This may be indicative of a critical bug in Wasmtime's code generation
1843 because all addresses which are known to be reachable from wasm won't reach this
1844 message.
1845 
1846     pc:      0x{pc:x}
1847     address: 0x{addr:x}
1848 
1849 This is a possible security issue because WebAssembly has accessed something it
1850 shouldn't have been able to. Other accesses may have succeeded and this one just
1851 happened to be caught. The process will now be aborted to prevent this damage
1852 from going any further and to alert what's going on. If this is a security
1853 issue please reach out to the Wasmtime team via its security policy
1854 at https://bytecodealliance.org/security.
1855 "
1856                 );
1857                 std::process::abort();
1858             } else if #[cfg(panic = "abort")] {
1859                 // Without the standard library but with `panic=abort` then
1860                 // it's safe to panic as that's known to halt execution. For
1861                 // now avoid the above error message as well since without
1862                 // `std` it's probably best to be a bit more size-conscious.
1863                 let _ = pc;
1864                 panic!("invalid fault");
1865             } else {
1866                 // Without `std` and with `panic = "unwind"` there's no way to
1867                 // abort the process portably, so flag a compile time error.
1868                 //
1869                 // NB: if this becomes a problem in the future one option would
1870                 // be to extend the `capi.rs` module for no_std platforms, but
1871                 // it remains yet to be seen at this time if this is hit much.
1872                 compile_error!("either `std` or `panic=abort` must be enabled");
1873                 None
1874             }
1875         }
1876     }
1877 
1878     /// Retrieve the store's protection key.
1879     #[inline]
1880     pub(crate) fn get_pkey(&self) -> Option<ProtectionKey> {
1881         self.pkey
1882     }
1883 
1884     #[inline]
1885     #[cfg(feature = "component-model")]
1886     pub(crate) fn component_resource_state(
1887         &mut self,
1888     ) -> (
1889         &mut vm::component::CallContexts,
1890         &mut vm::component::ResourceTable,
1891         &mut crate::component::HostResourceData,
1892     ) {
1893         (
1894             &mut self.component_calls,
1895             &mut self.component_host_table,
1896             &mut self.host_resource_data,
1897         )
1898     }
1899 
1900     #[cfg(feature = "component-model")]
1901     pub(crate) fn push_component_instance(&mut self, instance: crate::component::Instance) {
1902         // We don't actually need the instance itself right now, but it seems
1903         // like something we will almost certainly eventually want to keep
1904         // around, so force callers to provide it.
1905         let _ = instance;
1906 
1907         self.num_component_instances += 1;
1908     }
1909 
1910     #[cfg(feature = "component-model")]
1911     pub(crate) fn component_resource_state_with_instance(
1912         &mut self,
1913         instance: crate::component::Instance,
1914     ) -> (
1915         &mut vm::component::CallContexts,
1916         &mut vm::component::ResourceTable,
1917         &mut crate::component::HostResourceData,
1918         Pin<&mut vm::component::ComponentInstance>,
1919     ) {
1920         (
1921             &mut self.component_calls,
1922             &mut self.component_host_table,
1923             &mut self.host_resource_data,
1924             instance.id().from_data_get_mut(&mut self.store_data),
1925         )
1926     }
1927 
1928     #[cfg(not(feature = "async"))]
1929     pub(crate) fn async_guard_range(&self) -> core::ops::Range<*mut u8> {
1930         core::ptr::null_mut()..core::ptr::null_mut()
1931     }
1932 
1933     pub(crate) fn executor(&mut self) -> ExecutorRef<'_> {
1934         match &mut self.executor {
1935             Executor::Interpreter(i) => ExecutorRef::Interpreter(i.as_interpreter_ref()),
1936             #[cfg(has_host_compiler_backend)]
1937             Executor::Native => ExecutorRef::Native,
1938         }
1939     }
1940 
1941     pub(crate) fn unwinder(&self) -> &'static dyn Unwind {
1942         match &self.executor {
1943             Executor::Interpreter(i) => i.unwinder(),
1944             #[cfg(has_host_compiler_backend)]
1945             Executor::Native => &vm::UnwindHost,
1946         }
1947     }
1948 
1949     /// Allocates a new continuation. Note that we currently don't support
1950     /// deallocating them. Instead, all continuations remain allocated
1951     /// throughout the store's lifetime.
1952     #[cfg(feature = "stack-switching")]
1953     pub fn allocate_continuation(&mut self) -> Result<*mut VMContRef> {
1954         // FIXME(frank-emrich) Do we need to pin this?
1955         let mut continuation = Box::new(VMContRef::empty());
1956         let stack_size = self.engine.config().async_stack_size;
1957         let stack = crate::vm::VMContinuationStack::new(stack_size)?;
1958         continuation.stack = stack;
1959         let ptr = continuation.deref_mut() as *mut VMContRef;
1960         self.continuations.push(continuation);
1961         Ok(ptr)
1962     }
1963 
1964     /// Constructs and executes an `InstanceAllocationRequest` and pushes the
1965     /// returned instance into the store.
1966     ///
1967     /// This is a helper method for invoking
1968     /// `InstanceAllocator::allocate_module` with the appropriate parameters
1969     /// from this store's own configuration. The `kind` provided is used to
1970     /// distinguish between "real" modules and dummy ones that are synthesized
1971     /// for embedder-created memories, globals, tables, etc. The `kind` will
1972     /// also use a different instance allocator by default, the one passed in,
1973     /// rather than the engine's default allocator.
1974     ///
1975     /// This method will push the instance within `StoreOpaque` onto the
1976     /// `instances` array and return the `InstanceId` which can be use to look
1977     /// it up within the store.
1978     ///
1979     /// # Safety
1980     ///
1981     /// The request's associated module, memories, tables, and vmctx must have
1982     /// already have been validated by `validate_module` for the allocator
1983     /// configured. This is typically done during module construction for
1984     /// example.
1985     pub(crate) unsafe fn allocate_instance(
1986         &mut self,
1987         kind: AllocateInstanceKind<'_>,
1988         runtime_info: &ModuleRuntimeInfo,
1989         imports: Imports<'_>,
1990     ) -> Result<InstanceId> {
1991         let id = self.instances.next_key();
1992 
1993         let allocator = match kind {
1994             AllocateInstanceKind::Module(_) => self.engine().allocator(),
1995             AllocateInstanceKind::Dummy { allocator } => allocator,
1996         };
1997         let handle = allocator.allocate_module(InstanceAllocationRequest {
1998             id,
1999             runtime_info,
2000             imports,
2001             store: StorePtr::new(self.traitobj()),
2002             wmemcheck: self.engine().config().wmemcheck,
2003             pkey: self.get_pkey(),
2004             tunables: self.engine().tunables(),
2005         })?;
2006 
2007         let actual = match kind {
2008             AllocateInstanceKind::Module(module_id) => {
2009                 log::trace!(
2010                     "Adding instance to store: store={:?}, module={module_id:?}, instance={id:?}",
2011                     self.id()
2012                 );
2013                 self.instances.push(StoreInstance {
2014                     handle,
2015                     kind: StoreInstanceKind::Real { module_id },
2016                 })
2017             }
2018             AllocateInstanceKind::Dummy { .. } => {
2019                 log::trace!(
2020                     "Adding dummy instance to store: store={:?}, instance={id:?}",
2021                     self.id()
2022                 );
2023                 self.instances.push(StoreInstance {
2024                     handle,
2025                     kind: StoreInstanceKind::Dummy,
2026                 })
2027             }
2028         };
2029 
2030         // double-check we didn't accidentally allocate two instances and our
2031         // prediction of what the id would be is indeed the id it should be.
2032         assert_eq!(id, actual);
2033 
2034         Ok(id)
2035     }
2036 
2037     /// Returns the `StoreInstanceId` that can be used to re-acquire access to
2038     /// `vmctx` from a store later on.
2039     ///
2040     /// # Safety
2041     ///
2042     /// This method is unsafe as it cannot validate that `vmctx` is a valid
2043     /// allocation that lives within this store.
2044     pub(crate) unsafe fn vmctx_id(&self, vmctx: NonNull<VMContext>) -> StoreInstanceId {
2045         let instance_id = vm::Instance::from_vmctx(vmctx, |i| i.id());
2046         StoreInstanceId::new(self.id(), instance_id)
2047     }
2048 }
2049 
2050 /// Helper parameter to [`StoreOpaque::allocate_instance`].
2051 pub(crate) enum AllocateInstanceKind<'a> {
2052     /// An embedder-provided module is being allocated meaning that the default
2053     /// engine's allocator will be used.
2054     Module(RegisteredModuleId),
2055 
2056     /// Add a dummy instance that to the store.
2057     ///
2058     /// These are instances that are just implementation details of something
2059     /// else (e.g. host-created memories that are not actually defined in any
2060     /// Wasm module) and therefore shouldn't show up in things like core dumps.
2061     ///
2062     /// A custom, typically OnDemand-flavored, allocator is provided to execute
2063     /// the allocation.
2064     Dummy {
2065         allocator: &'a dyn InstanceAllocator,
2066     },
2067 }
2068 
2069 unsafe impl<T> vm::VMStore for StoreInner<T> {
2070     #[cfg(feature = "component-model-async")]
2071     fn component_async_store(
2072         &mut self,
2073     ) -> &mut dyn crate::runtime::component::VMComponentAsyncStore {
2074         self
2075     }
2076 
2077     fn store_opaque(&self) -> &StoreOpaque {
2078         &self.inner
2079     }
2080 
2081     fn store_opaque_mut(&mut self) -> &mut StoreOpaque {
2082         &mut self.inner
2083     }
2084 
2085     fn memory_growing(
2086         &mut self,
2087         current: usize,
2088         desired: usize,
2089         maximum: Option<usize>,
2090     ) -> Result<bool, anyhow::Error> {
2091         match self.limiter {
2092             Some(ResourceLimiterInner::Sync(ref mut limiter)) => {
2093                 limiter(&mut self.data).memory_growing(current, desired, maximum)
2094             }
2095             #[cfg(feature = "async")]
2096             Some(ResourceLimiterInner::Async(ref mut limiter)) => unsafe {
2097                 self.inner
2098                     .async_cx()
2099                     .expect("ResourceLimiterAsync requires async Store")
2100                     .block_on(
2101                         limiter(&mut self.data)
2102                             .memory_growing(current, desired, maximum)
2103                             .as_mut(),
2104                     )?
2105             },
2106             None => Ok(true),
2107         }
2108     }
2109 
2110     fn memory_grow_failed(&mut self, error: anyhow::Error) -> Result<()> {
2111         match self.limiter {
2112             Some(ResourceLimiterInner::Sync(ref mut limiter)) => {
2113                 limiter(&mut self.data).memory_grow_failed(error)
2114             }
2115             #[cfg(feature = "async")]
2116             Some(ResourceLimiterInner::Async(ref mut limiter)) => {
2117                 limiter(&mut self.data).memory_grow_failed(error)
2118             }
2119             None => {
2120                 log::debug!("ignoring memory growth failure error: {error:?}");
2121                 Ok(())
2122             }
2123         }
2124     }
2125 
2126     fn table_growing(
2127         &mut self,
2128         current: usize,
2129         desired: usize,
2130         maximum: Option<usize>,
2131     ) -> Result<bool, anyhow::Error> {
2132         // Need to borrow async_cx before the mut borrow of the limiter.
2133         // self.async_cx() panicks when used with a non-async store, so
2134         // wrap this in an option.
2135         #[cfg(feature = "async")]
2136         let async_cx = if self.async_support()
2137             && matches!(self.limiter, Some(ResourceLimiterInner::Async(_)))
2138         {
2139             Some(self.async_cx().unwrap())
2140         } else {
2141             None
2142         };
2143 
2144         match self.limiter {
2145             Some(ResourceLimiterInner::Sync(ref mut limiter)) => {
2146                 limiter(&mut self.data).table_growing(current, desired, maximum)
2147             }
2148             #[cfg(feature = "async")]
2149             Some(ResourceLimiterInner::Async(ref mut limiter)) => unsafe {
2150                 async_cx
2151                     .expect("ResourceLimiterAsync requires async Store")
2152                     .block_on(limiter(&mut self.data).table_growing(current, desired, maximum))?
2153             },
2154             None => Ok(true),
2155         }
2156     }
2157 
2158     fn table_grow_failed(&mut self, error: anyhow::Error) -> Result<()> {
2159         match self.limiter {
2160             Some(ResourceLimiterInner::Sync(ref mut limiter)) => {
2161                 limiter(&mut self.data).table_grow_failed(error)
2162             }
2163             #[cfg(feature = "async")]
2164             Some(ResourceLimiterInner::Async(ref mut limiter)) => {
2165                 limiter(&mut self.data).table_grow_failed(error)
2166             }
2167             None => {
2168                 log::debug!("ignoring table growth failure: {error:?}");
2169                 Ok(())
2170             }
2171         }
2172     }
2173 
2174     fn out_of_gas(&mut self) -> Result<()> {
2175         if !self.refuel() {
2176             return Err(Trap::OutOfFuel.into());
2177         }
2178         #[cfg(feature = "async")]
2179         if self.fuel_yield_interval.is_some() {
2180             self.async_yield_impl()?;
2181         }
2182         Ok(())
2183     }
2184 
2185     #[cfg(target_has_atomic = "64")]
2186     fn new_epoch(&mut self) -> Result<u64, anyhow::Error> {
2187         // Temporarily take the configured behavior to avoid mutably borrowing
2188         // multiple times.
2189         let mut behavior = self.epoch_deadline_behavior.take();
2190         let delta_result = match &mut behavior {
2191             None => Err(Trap::Interrupt.into()),
2192             Some(callback) => callback((&mut *self).as_context_mut()).and_then(|update| {
2193                 let delta = match update {
2194                     UpdateDeadline::Continue(delta) => delta,
2195                     #[cfg(feature = "async")]
2196                     UpdateDeadline::Yield(delta) => {
2197                         assert!(
2198                             self.async_support(),
2199                             "cannot use `UpdateDeadline::Yield` without enabling async support in the config"
2200                         );
2201                         // Do the async yield. May return a trap if future was
2202                         // canceled while we're yielded.
2203                         self.async_yield_impl()?;
2204                         delta
2205                     }
2206                     #[cfg(feature = "async")]
2207                     UpdateDeadline::YieldCustom(delta, future) => {
2208                         assert!(
2209                             self.async_support(),
2210                             "cannot use `UpdateDeadline::YieldCustom` without enabling async support in the config"
2211                         );
2212 
2213                         // When control returns, we have a `Result<()>` passed
2214                         // in from the host fiber. If this finished successfully then
2215                         // we were resumed normally via a `poll`, so keep going.  If
2216                         // the future was dropped while we were yielded, then we need
2217                         // to clean up this fiber. Do so by raising a trap which will
2218                         // abort all wasm and get caught on the other side to clean
2219                         // things up.
2220                         unsafe {
2221                             self.async_cx()
2222                                 .expect("attempted to pull async context during shutdown")
2223                                 .block_on(future)?
2224                         }
2225                         delta
2226                     }
2227                 };
2228 
2229                 // Set a new deadline and return the new epoch deadline so
2230                 // the Wasm code doesn't have to reload it.
2231                 self.set_epoch_deadline(delta);
2232                 Ok(self.get_epoch_deadline())
2233             })
2234         };
2235 
2236         // Put back the original behavior which was replaced by `take`.
2237         self.epoch_deadline_behavior = behavior;
2238         delta_result
2239     }
2240 
2241     #[cfg(feature = "gc")]
2242     unsafe fn maybe_async_grow_or_collect_gc_heap(
2243         &mut self,
2244         root: Option<VMGcRef>,
2245         bytes_needed: Option<u64>,
2246     ) -> Result<Option<VMGcRef>> {
2247         self.inner.maybe_async_gc(root, bytes_needed)
2248     }
2249 
2250     #[cfg(not(feature = "gc"))]
2251     unsafe fn maybe_async_grow_or_collect_gc_heap(
2252         &mut self,
2253         root: Option<VMGcRef>,
2254         _bytes_needed: Option<u64>,
2255     ) -> Result<Option<VMGcRef>> {
2256         Ok(root)
2257     }
2258 
2259     #[cfg(feature = "component-model")]
2260     fn component_calls(&mut self) -> &mut vm::component::CallContexts {
2261         &mut self.component_calls
2262     }
2263 }
2264 
2265 impl<T> StoreInner<T> {
2266     #[cfg(target_has_atomic = "64")]
2267     pub(crate) fn set_epoch_deadline(&mut self, delta: u64) {
2268         // Set a new deadline based on the "epoch deadline delta".
2269         //
2270         // Also, note that when this update is performed while Wasm is
2271         // on the stack, the Wasm will reload the new value once we
2272         // return into it.
2273         let current_epoch = self.engine().current_epoch();
2274         let epoch_deadline = self.vm_store_context.epoch_deadline.get_mut();
2275         *epoch_deadline = current_epoch + delta;
2276     }
2277 
2278     #[cfg(target_has_atomic = "64")]
2279     fn epoch_deadline_trap(&mut self) {
2280         self.epoch_deadline_behavior = None;
2281     }
2282 
2283     #[cfg(target_has_atomic = "64")]
2284     fn epoch_deadline_callback(
2285         &mut self,
2286         callback: Box<dyn FnMut(StoreContextMut<T>) -> Result<UpdateDeadline> + Send + Sync>,
2287     ) {
2288         self.epoch_deadline_behavior = Some(callback);
2289     }
2290 
2291     fn get_epoch_deadline(&mut self) -> u64 {
2292         *self.vm_store_context.epoch_deadline.get_mut()
2293     }
2294 }
2295 
2296 impl<T: Default> Default for Store<T> {
2297     fn default() -> Store<T> {
2298         Store::new(&Engine::default(), T::default())
2299     }
2300 }
2301 
2302 impl<T: fmt::Debug> fmt::Debug for Store<T> {
2303     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2304         let inner = &**self.inner as *const StoreInner<T>;
2305         f.debug_struct("Store")
2306             .field("inner", &inner)
2307             .field("data", &self.inner.data)
2308             .finish()
2309     }
2310 }
2311 
2312 impl<T> Drop for Store<T> {
2313     fn drop(&mut self) {
2314         self.inner.flush_fiber_stack();
2315 
2316         // for documentation on this `unsafe`, see `into_data`.
2317         unsafe {
2318             ManuallyDrop::drop(&mut self.inner.data);
2319             ManuallyDrop::drop(&mut self.inner);
2320         }
2321     }
2322 }
2323 
2324 impl Drop for StoreOpaque {
2325     fn drop(&mut self) {
2326         // NB it's important that this destructor does not access `self.data`.
2327         // That is deallocated by `Drop for Store<T>` above.
2328 
2329         unsafe {
2330             let allocator = self.engine.allocator();
2331             let ondemand = OnDemandInstanceAllocator::default();
2332             let store_id = self.id();
2333 
2334             #[cfg(feature = "gc")]
2335             if let Some(gc_store) = self.gc_store.take() {
2336                 let gc_alloc_index = gc_store.allocation_index;
2337                 log::trace!("store {store_id:?} is deallocating GC heap {gc_alloc_index:?}");
2338                 debug_assert!(self.engine.features().gc_types());
2339                 let (mem_alloc_index, mem) =
2340                     allocator.deallocate_gc_heap(gc_alloc_index, gc_store.gc_heap);
2341                 allocator.deallocate_memory(None, mem_alloc_index, mem);
2342             }
2343 
2344             for (id, instance) in self.instances.iter_mut() {
2345                 log::trace!("store {store_id:?} is deallocating {id:?}");
2346                 if let StoreInstanceKind::Dummy = instance.kind {
2347                     ondemand.deallocate_module(&mut instance.handle);
2348                 } else {
2349                     allocator.deallocate_module(&mut instance.handle);
2350                 }
2351             }
2352 
2353             #[cfg(feature = "component-model")]
2354             {
2355                 for _ in 0..self.num_component_instances {
2356                     allocator.decrement_component_instance_count();
2357                 }
2358             }
2359         }
2360     }
2361 }
2362 
2363 #[cfg(test)]
2364 mod tests {
2365     use super::{get_fuel, refuel, set_fuel};
2366     use std::num::NonZeroU64;
2367 
2368     struct FuelTank {
2369         pub consumed_fuel: i64,
2370         pub reserve_fuel: u64,
2371         pub yield_interval: Option<NonZeroU64>,
2372     }
2373 
2374     impl FuelTank {
2375         fn new() -> Self {
2376             FuelTank {
2377                 consumed_fuel: 0,
2378                 reserve_fuel: 0,
2379                 yield_interval: None,
2380             }
2381         }
2382         fn get_fuel(&self) -> u64 {
2383             get_fuel(self.consumed_fuel, self.reserve_fuel)
2384         }
2385         fn refuel(&mut self) -> bool {
2386             refuel(
2387                 &mut self.consumed_fuel,
2388                 &mut self.reserve_fuel,
2389                 self.yield_interval,
2390             )
2391         }
2392         fn set_fuel(&mut self, fuel: u64) {
2393             set_fuel(
2394                 &mut self.consumed_fuel,
2395                 &mut self.reserve_fuel,
2396                 self.yield_interval,
2397                 fuel,
2398             );
2399         }
2400     }
2401 
2402     #[test]
2403     fn smoke() {
2404         let mut tank = FuelTank::new();
2405         tank.set_fuel(10);
2406         assert_eq!(tank.consumed_fuel, -10);
2407         assert_eq!(tank.reserve_fuel, 0);
2408 
2409         tank.yield_interval = NonZeroU64::new(10);
2410         tank.set_fuel(25);
2411         assert_eq!(tank.consumed_fuel, -10);
2412         assert_eq!(tank.reserve_fuel, 15);
2413     }
2414 
2415     #[test]
2416     fn does_not_lose_precision() {
2417         let mut tank = FuelTank::new();
2418         tank.set_fuel(u64::MAX);
2419         assert_eq!(tank.get_fuel(), u64::MAX);
2420 
2421         tank.set_fuel(i64::MAX as u64);
2422         assert_eq!(tank.get_fuel(), i64::MAX as u64);
2423 
2424         tank.set_fuel(i64::MAX as u64 + 1);
2425         assert_eq!(tank.get_fuel(), i64::MAX as u64 + 1);
2426     }
2427 
2428     #[test]
2429     fn yielding_does_not_lose_precision() {
2430         let mut tank = FuelTank::new();
2431 
2432         tank.yield_interval = NonZeroU64::new(10);
2433         tank.set_fuel(u64::MAX);
2434         assert_eq!(tank.get_fuel(), u64::MAX);
2435         assert_eq!(tank.consumed_fuel, -10);
2436         assert_eq!(tank.reserve_fuel, u64::MAX - 10);
2437 
2438         tank.yield_interval = NonZeroU64::new(u64::MAX);
2439         tank.set_fuel(u64::MAX);
2440         assert_eq!(tank.get_fuel(), u64::MAX);
2441         assert_eq!(tank.consumed_fuel, -i64::MAX);
2442         assert_eq!(tank.reserve_fuel, u64::MAX - (i64::MAX as u64));
2443 
2444         tank.yield_interval = NonZeroU64::new((i64::MAX as u64) + 1);
2445         tank.set_fuel(u64::MAX);
2446         assert_eq!(tank.get_fuel(), u64::MAX);
2447         assert_eq!(tank.consumed_fuel, -i64::MAX);
2448         assert_eq!(tank.reserve_fuel, u64::MAX - (i64::MAX as u64));
2449     }
2450 
2451     #[test]
2452     fn refueling() {
2453         // It's possible to fuel to have consumed over the limit as some instructions can consume
2454         // multiple units of fuel at once. Refueling should be strict in it's consumption and not
2455         // add more fuel than there is.
2456         let mut tank = FuelTank::new();
2457 
2458         tank.yield_interval = NonZeroU64::new(10);
2459         tank.reserve_fuel = 42;
2460         tank.consumed_fuel = 4;
2461         assert!(tank.refuel());
2462         assert_eq!(tank.reserve_fuel, 28);
2463         assert_eq!(tank.consumed_fuel, -10);
2464 
2465         tank.yield_interval = NonZeroU64::new(1);
2466         tank.reserve_fuel = 8;
2467         tank.consumed_fuel = 4;
2468         assert_eq!(tank.get_fuel(), 4);
2469         assert!(tank.refuel());
2470         assert_eq!(tank.reserve_fuel, 3);
2471         assert_eq!(tank.consumed_fuel, -1);
2472         assert_eq!(tank.get_fuel(), 4);
2473 
2474         tank.yield_interval = NonZeroU64::new(10);
2475         tank.reserve_fuel = 3;
2476         tank.consumed_fuel = 4;
2477         assert_eq!(tank.get_fuel(), 0);
2478         assert!(!tank.refuel());
2479         assert_eq!(tank.reserve_fuel, 3);
2480         assert_eq!(tank.consumed_fuel, 4);
2481         assert_eq!(tank.get_fuel(), 0);
2482     }
2483 }
2484