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