wasmi/
store.rs

1use crate::{
2    collections::arena::{Arena, ArenaIndex, GuardedEntity},
3    core::TrapCode,
4    engine::{DedupFuncType, FuelCosts},
5    externref::{ExternObject, ExternObjectEntity, ExternObjectIdx},
6    func::{Trampoline, TrampolineEntity, TrampolineIdx},
7    memory::{DataSegment, MemoryError},
8    module::InstantiationError,
9    table::TableError,
10    Config,
11    DataSegmentEntity,
12    DataSegmentIdx,
13    ElementSegment,
14    ElementSegmentEntity,
15    ElementSegmentIdx,
16    Engine,
17    Func,
18    FuncEntity,
19    FuncIdx,
20    FuncType,
21    Global,
22    GlobalEntity,
23    GlobalIdx,
24    Instance,
25    InstanceEntity,
26    InstanceIdx,
27    Memory,
28    MemoryEntity,
29    MemoryIdx,
30    ResourceLimiter,
31    Table,
32    TableEntity,
33    TableIdx,
34};
35use core::{
36    fmt::{self, Debug},
37    sync::atomic::{AtomicU32, Ordering},
38};
39use std::boxed::Box;
40
41/// A unique store index.
42///
43/// # Note
44///
45/// Used to protect against invalid entity indices.
46#[derive(Debug, Copy, Clone, PartialEq, Eq)]
47pub struct StoreIdx(u32);
48
49impl ArenaIndex for StoreIdx {
50    fn into_usize(self) -> usize {
51        self.0 as usize
52    }
53
54    fn from_usize(value: usize) -> Self {
55        let value = value.try_into().unwrap_or_else(|error| {
56            panic!("index {value} is out of bounds as store index: {error}")
57        });
58        Self(value)
59    }
60}
61
62impl StoreIdx {
63    /// Returns a new unique [`StoreIdx`].
64    fn new() -> Self {
65        /// A static store index counter.
66        static CURRENT_STORE_IDX: AtomicU32 = AtomicU32::new(0);
67        let next_idx = CURRENT_STORE_IDX.fetch_add(1, Ordering::AcqRel);
68        Self(next_idx)
69    }
70}
71
72/// A stored entity.
73pub type Stored<Idx> = GuardedEntity<StoreIdx, Idx>;
74
75/// A wrapper around an optional `&mut dyn` [`ResourceLimiter`], that exists
76/// both to make types a little easier to read and to provide a `Debug` impl so
77/// that `#[derive(Debug)]` works on structs that contain it.
78pub struct ResourceLimiterRef<'a>(Option<&'a mut (dyn ResourceLimiter)>);
79impl<'a> Debug for ResourceLimiterRef<'a> {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        write!(f, "ResourceLimiterRef(...)")
82    }
83}
84
85impl<'a> ResourceLimiterRef<'a> {
86    pub fn as_resource_limiter(&mut self) -> &mut Option<&'a mut dyn ResourceLimiter> {
87        &mut self.0
88    }
89}
90
91/// A wrapper around a boxed `dyn FnMut(&mut T)` returning a `&mut dyn`
92/// [`ResourceLimiter`]; in other words a function that one can call to retrieve
93/// a [`ResourceLimiter`] from the [`Store`] object's user data type `T`.
94///
95/// This wrapper exists both to make types a little easier to read and to
96/// provide a `Debug` impl so that `#[derive(Debug)]` works on structs that
97/// contain it.
98struct ResourceLimiterQuery<T>(Box<dyn FnMut(&mut T) -> &mut (dyn ResourceLimiter) + Send + Sync>);
99impl<T> Debug for ResourceLimiterQuery<T> {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        write!(f, "ResourceLimiterQuery(...)")
102    }
103}
104
105/// The store that owns all data associated to Wasm modules.
106#[derive(Debug)]
107pub struct Store<T> {
108    /// All data that is not associated to `T`.
109    ///
110    /// # Note
111    ///
112    /// This is re-exported to the rest of the crate since
113    /// it is used directly by the engine's executor.
114    pub(crate) inner: StoreInner,
115    /// Stored host function trampolines.
116    trampolines: Arena<TrampolineIdx, TrampolineEntity<T>>,
117    /// User provided host data owned by the [`Store`].
118    data: T,
119    /// User provided hook to retrieve a [`ResourceLimiter`].
120    limiter: Option<ResourceLimiterQuery<T>>,
121}
122
123/// The inner store that owns all data not associated to the host state.
124#[derive(Debug)]
125pub struct StoreInner {
126    /// The unique store index.
127    ///
128    /// Used to protect against invalid entity indices.
129    store_idx: StoreIdx,
130    /// Stored Wasm or host functions.
131    funcs: Arena<FuncIdx, FuncEntity>,
132    /// Stored linear memories.
133    memories: Arena<MemoryIdx, MemoryEntity>,
134    /// Stored tables.
135    tables: Arena<TableIdx, TableEntity>,
136    /// Stored global variables.
137    globals: Arena<GlobalIdx, GlobalEntity>,
138    /// Stored module instances.
139    instances: Arena<InstanceIdx, InstanceEntity>,
140    /// Stored data segments.
141    datas: Arena<DataSegmentIdx, DataSegmentEntity>,
142    /// Stored data segments.
143    elems: Arena<ElementSegmentIdx, ElementSegmentEntity>,
144    /// Stored external objects for [`ExternRef`] types.
145    ///
146    /// [`ExternRef`]: [`crate::ExternRef`]
147    extern_objects: Arena<ExternObjectIdx, ExternObjectEntity>,
148    /// The [`Engine`] in use by the [`Store`].
149    ///
150    /// Amongst others the [`Engine`] stores the Wasm function definitions.
151    engine: Engine,
152    /// The fuel of the [`Store`].
153    fuel: Fuel,
154}
155
156#[test]
157fn test_store_is_send_sync() {
158    const _: () = {
159        #[allow(clippy::extra_unused_type_parameters)]
160        fn assert_send<T: Send>() {}
161        #[allow(clippy::extra_unused_type_parameters)]
162        fn assert_sync<T: Sync>() {}
163        let _ = assert_send::<Store<()>>;
164        let _ = assert_sync::<Store<()>>;
165    };
166}
167
168/// An error that may be encountered when operating on the [`Store`].
169#[derive(Debug, Clone)]
170pub enum FuelError {
171    /// Raised when trying to use any of the `fuel` methods while fuel metering is disabled.
172    FuelMeteringDisabled,
173    /// Raised when trying to consume more fuel than is available in the [`Store`].
174    OutOfFuel,
175}
176
177impl fmt::Display for FuelError {
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        match self {
180            Self::FuelMeteringDisabled => write!(f, "fuel metering is disabled"),
181            Self::OutOfFuel => write!(f, "all fuel consumed"),
182        }
183    }
184}
185
186impl FuelError {
187    /// Returns an error indicating that fuel metering has been disabled.
188    ///
189    /// # Note
190    ///
191    /// This method exists to indicate that this execution path is cold.
192    #[cold]
193    pub fn fuel_metering_disabled() -> Self {
194        Self::FuelMeteringDisabled
195    }
196
197    /// Returns an error indicating that too much fuel has been consumed.
198    ///
199    /// # Note
200    ///
201    /// This method exists to indicate that this execution path is cold.
202    #[cold]
203    pub fn out_of_fuel() -> Self {
204        Self::OutOfFuel
205    }
206}
207
208/// The remaining and consumed fuel counters.
209#[derive(Debug, Copy, Clone)]
210pub struct Fuel {
211    /// The remaining fuel.
212    remaining: u64,
213    /// This is `true` if fuel metering is enabled for the [`Engine`].
214    enabled: bool,
215    /// The fuel costs provided by the [`Engine`]'s [`Config`].
216    ///
217    /// [`Config`]: crate::Config
218    costs: FuelCosts,
219}
220
221impl Fuel {
222    /// Creates a new [`Fuel`] for the [`Engine`].
223    pub fn new(config: &Config) -> Self {
224        let enabled = config.get_consume_fuel();
225        let costs = *config.fuel_costs();
226        Self {
227            remaining: 0,
228            enabled,
229            costs,
230        }
231    }
232
233    /// Returns `true` if fuel metering is enabled.
234    fn is_fuel_metering_enabled(&self) -> bool {
235        self.enabled
236    }
237
238    /// Returns `Ok` if fuel metering is enabled.
239    ///
240    /// Returns descriptive [`FuelError`] otherwise.
241    ///
242    /// # Errors
243    ///
244    /// If fuel metering is disabled.
245    fn check_fuel_metering_enabled(&self) -> Result<(), FuelError> {
246        if !self.is_fuel_metering_enabled() {
247            return Err(FuelError::fuel_metering_disabled());
248        }
249        Ok(())
250    }
251
252    /// Sets the remaining fuel to `fuel`.
253    ///
254    /// # Errors
255    ///
256    /// If fuel metering is disabled.
257    pub fn set_fuel(&mut self, fuel: u64) -> Result<(), FuelError> {
258        self.check_fuel_metering_enabled()?;
259        self.remaining = fuel;
260        Ok(())
261    }
262
263    /// Returns the remaining fuel.
264    ///
265    /// # Errors
266    ///
267    /// If fuel metering is disabled.
268    pub fn get_fuel(&self) -> Result<u64, FuelError> {
269        self.check_fuel_metering_enabled()?;
270        Ok(self.remaining)
271    }
272
273    /// Synthetically consumes an amount of [`Fuel`] from the [`Store`].
274    ///
275    /// Returns the remaining amount of [`Fuel`] after this operation.
276    ///
277    /// # Note
278    ///
279    /// - This does not check if fuel metering is enabled.
280    /// - This API is intended for use cases where it is clear that fuel metering is
281    ///   enabled and where a check would incur unnecessary overhead in a hot path.
282    ///   An example of this is the execution of consume fuel instructions since
283    ///   those only exist if fuel metering is enabled.
284    ///
285    /// # Errors
286    ///
287    /// If out of fuel.
288    pub(crate) fn consume_fuel_unchecked(&mut self, delta: u64) -> Result<u64, TrapCode> {
289        self.remaining = self
290            .remaining
291            .checked_sub(delta)
292            .ok_or(TrapCode::OutOfFuel)?;
293        Ok(self.remaining)
294    }
295
296    /// Synthetically consumes an amount of [`Fuel`] for the [`Store`].
297    ///
298    /// Returns the remaining amount of [`Fuel`] after this operation.
299    ///
300    /// # Errors
301    ///
302    /// - If fuel metering is disabled.
303    /// - If out of fuel.
304    pub(crate) fn consume_fuel(
305        &mut self,
306        f: impl FnOnce(&FuelCosts) -> u64,
307    ) -> Result<u64, FuelError> {
308        self.check_fuel_metering_enabled()?;
309        self.consume_fuel_unchecked(f(&self.costs))
310            .map_err(|_| FuelError::OutOfFuel)
311    }
312
313    /// Synthetically consumes an amount of [`Fuel`] from the [`Store`] if fuel metering is enabled.
314    ///
315    /// # Note
316    ///
317    /// This does nothing if fuel metering is disabled.
318    ///
319    /// # Errors
320    ///
321    /// - If out of fuel.
322    pub(crate) fn consume_fuel_if(
323        &mut self,
324        f: impl FnOnce(&FuelCosts) -> u64,
325    ) -> Result<(), TrapCode> {
326        match self.consume_fuel(f) {
327            Err(FuelError::OutOfFuel) => Err(TrapCode::OutOfFuel),
328            Err(FuelError::FuelMeteringDisabled) | Ok(_) => Ok(()),
329        }
330    }
331}
332
333impl StoreInner {
334    /// Creates a new [`StoreInner`] for the given [`Engine`].
335    pub fn new(engine: &Engine) -> Self {
336        let fuel = Fuel::new(engine.config());
337        StoreInner {
338            engine: engine.clone(),
339            store_idx: StoreIdx::new(),
340            funcs: Arena::new(),
341            memories: Arena::new(),
342            tables: Arena::new(),
343            globals: Arena::new(),
344            instances: Arena::new(),
345            datas: Arena::new(),
346            elems: Arena::new(),
347            extern_objects: Arena::new(),
348            fuel,
349        }
350    }
351
352    /// Returns the [`Engine`] that this store is associated with.
353    pub fn engine(&self) -> &Engine {
354        &self.engine
355    }
356
357    /// Returns an exclusive reference to the [`Fuel`] counters.
358    pub fn fuel_mut(&mut self) -> &mut Fuel {
359        &mut self.fuel
360    }
361
362    /// Wraps an entity `Idx` (index type) as a [`Stored<Idx>`] type.
363    ///
364    /// # Note
365    ///
366    /// [`Stored<Idx>`] associates an `Idx` type with the internal store index.
367    /// This way wrapped indices cannot be misused with incorrect [`Store`] instances.
368    fn wrap_stored<Idx>(&self, entity_idx: Idx) -> Stored<Idx> {
369        Stored::new(self.store_idx, entity_idx)
370    }
371
372    /// Unwraps the given [`Stored<Idx>`] reference and returns the `Idx`.
373    ///
374    /// # Panics
375    ///
376    /// If the [`Stored<Idx>`] does not originate from this [`Store`].
377    fn unwrap_stored<Idx>(&self, stored: &Stored<Idx>) -> Idx
378    where
379        Idx: ArenaIndex + Debug,
380    {
381        stored.entity_index(self.store_idx).unwrap_or_else(|| {
382            panic!(
383                "entity reference ({:?}) does not belong to store {:?}",
384                stored, self.store_idx,
385            )
386        })
387    }
388
389    /// Allocates a new [`GlobalEntity`] and returns a [`Global`] reference to it.
390    pub fn alloc_global(&mut self, global: GlobalEntity) -> Global {
391        let global = self.globals.alloc(global);
392        Global::from_inner(self.wrap_stored(global))
393    }
394
395    /// Allocates a new [`TableEntity`] and returns a [`Table`] reference to it.
396    pub fn alloc_table(&mut self, table: TableEntity) -> Table {
397        let table = self.tables.alloc(table);
398        Table::from_inner(self.wrap_stored(table))
399    }
400
401    /// Allocates a new [`MemoryEntity`] and returns a [`Memory`] reference to it.
402    pub fn alloc_memory(&mut self, memory: MemoryEntity) -> Memory {
403        let memory = self.memories.alloc(memory);
404        Memory::from_inner(self.wrap_stored(memory))
405    }
406
407    /// Allocates a new [`DataSegmentEntity`] and returns a [`DataSegment`] reference to it.
408    pub fn alloc_data_segment(&mut self, segment: DataSegmentEntity) -> DataSegment {
409        let segment = self.datas.alloc(segment);
410        DataSegment::from_inner(self.wrap_stored(segment))
411    }
412
413    /// Allocates a new [`ElementSegmentEntity`] and returns a [`ElementSegment`] reference to it.
414    pub(super) fn alloc_element_segment(
415        &mut self,
416        segment: ElementSegmentEntity,
417    ) -> ElementSegment {
418        let segment = self.elems.alloc(segment);
419        ElementSegment::from_inner(self.wrap_stored(segment))
420    }
421
422    /// Allocates a new [`ExternObjectEntity`] and returns a [`ExternObject`] reference to it.
423    pub(super) fn alloc_extern_object(&mut self, object: ExternObjectEntity) -> ExternObject {
424        let object = self.extern_objects.alloc(object);
425        ExternObject::from_inner(self.wrap_stored(object))
426    }
427
428    /// Allocates a new uninitialized [`InstanceEntity`] and returns an [`Instance`] reference to it.
429    ///
430    /// # Note
431    ///
432    /// - This will create an uninitialized dummy [`InstanceEntity`] as a place holder
433    ///   for the returned [`Instance`]. Using this uninitialized [`Instance`] will result
434    ///   in a runtime panic.
435    /// - The returned [`Instance`] must later be initialized via the [`StoreInner::initialize_instance`]
436    ///   method. Afterwards the [`Instance`] may be used.
437    pub fn alloc_instance(&mut self) -> Instance {
438        let instance = self.instances.alloc(InstanceEntity::uninitialized());
439        Instance::from_inner(self.wrap_stored(instance))
440    }
441
442    /// Initializes the [`Instance`] using the given [`InstanceEntity`].
443    ///
444    /// # Note
445    ///
446    /// After this operation the [`Instance`] is initialized and can be used.
447    ///
448    /// # Panics
449    ///
450    /// - If the [`Instance`] does not belong to the [`Store`].
451    /// - If the [`Instance`] is unknown to the [`Store`].
452    /// - If the [`Instance`] has already been initialized.
453    /// - If the given [`InstanceEntity`] is itself not initialized, yet.
454    pub fn initialize_instance(&mut self, instance: Instance, init: InstanceEntity) {
455        assert!(
456            init.is_initialized(),
457            "encountered an uninitialized new instance entity: {init:?}",
458        );
459        let idx = self.unwrap_stored(instance.as_inner());
460        let uninit = self
461            .instances
462            .get_mut(idx)
463            .unwrap_or_else(|| panic!("missing entity for the given instance: {instance:?}"));
464        assert!(
465            !uninit.is_initialized(),
466            "encountered an already initialized instance: {uninit:?}",
467        );
468        *uninit = init;
469    }
470
471    /// Returns a shared reference to the entity indexed by the given `idx`.
472    ///
473    /// # Panics
474    ///
475    /// - If the indexed entity does not originate from this [`Store`].
476    /// - If the entity index cannot be resolved to its entity.
477    fn resolve<'a, Idx, Entity>(
478        &self,
479        idx: &Stored<Idx>,
480        entities: &'a Arena<Idx, Entity>,
481    ) -> &'a Entity
482    where
483        Idx: ArenaIndex + Debug,
484    {
485        let idx = self.unwrap_stored(idx);
486        entities
487            .get(idx)
488            .unwrap_or_else(|| panic!("failed to resolve stored entity: {idx:?}"))
489    }
490
491    /// Returns an exclusive reference to the entity indexed by the given `idx`.
492    ///
493    /// # Note
494    ///
495    /// Due to borrow checking issues this method takes an already unwrapped
496    /// `Idx` unlike the [`StoreInner::resolve`] method.
497    ///
498    /// # Panics
499    ///
500    /// - If the entity index cannot be resolved to its entity.
501    fn resolve_mut<Idx, Entity>(idx: Idx, entities: &mut Arena<Idx, Entity>) -> &mut Entity
502    where
503        Idx: ArenaIndex + Debug,
504    {
505        entities
506            .get_mut(idx)
507            .unwrap_or_else(|| panic!("failed to resolve stored entity: {idx:?}"))
508    }
509
510    /// Returns the [`FuncType`] associated to the given [`DedupFuncType`].
511    ///
512    /// # Panics
513    ///
514    /// - If the [`DedupFuncType`] does not originate from this [`Store`].
515    /// - If the [`DedupFuncType`] cannot be resolved to its entity.
516    pub fn resolve_func_type(&self, func_type: &DedupFuncType) -> FuncType {
517        self.resolve_func_type_with(func_type, FuncType::clone)
518    }
519
520    /// Calls `f` on the [`FuncType`] associated to the given [`DedupFuncType`] and returns the result.
521    ///
522    /// # Panics
523    ///
524    /// - If the [`DedupFuncType`] does not originate from this [`Store`].
525    /// - If the [`DedupFuncType`] cannot be resolved to its entity.
526    pub fn resolve_func_type_with<R>(
527        &self,
528        func_type: &DedupFuncType,
529        f: impl FnOnce(&FuncType) -> R,
530    ) -> R {
531        self.engine.resolve_func_type(func_type, f)
532    }
533
534    /// Returns a shared reference to the [`GlobalEntity`] associated to the given [`Global`].
535    ///
536    /// # Panics
537    ///
538    /// - If the [`Global`] does not originate from this [`Store`].
539    /// - If the [`Global`] cannot be resolved to its entity.
540    pub fn resolve_global(&self, global: &Global) -> &GlobalEntity {
541        self.resolve(global.as_inner(), &self.globals)
542    }
543
544    /// Returns an exclusive reference to the [`GlobalEntity`] associated to the given [`Global`].
545    ///
546    /// # Panics
547    ///
548    /// - If the [`Global`] does not originate from this [`Store`].
549    /// - If the [`Global`] cannot be resolved to its entity.
550    pub fn resolve_global_mut(&mut self, global: &Global) -> &mut GlobalEntity {
551        let idx = self.unwrap_stored(global.as_inner());
552        Self::resolve_mut(idx, &mut self.globals)
553    }
554
555    /// Returns a shared reference to the [`TableEntity`] associated to the given [`Table`].
556    ///
557    /// # Panics
558    ///
559    /// - If the [`Table`] does not originate from this [`Store`].
560    /// - If the [`Table`] cannot be resolved to its entity.
561    pub fn resolve_table(&self, table: &Table) -> &TableEntity {
562        self.resolve(table.as_inner(), &self.tables)
563    }
564
565    /// Returns an exclusive reference to the [`TableEntity`] associated to the given [`Table`].
566    ///
567    /// # Panics
568    ///
569    /// - If the [`Table`] does not originate from this [`Store`].
570    /// - If the [`Table`] cannot be resolved to its entity.
571    pub fn resolve_table_mut(&mut self, table: &Table) -> &mut TableEntity {
572        let idx = self.unwrap_stored(table.as_inner());
573        Self::resolve_mut(idx, &mut self.tables)
574    }
575
576    /// Returns both
577    ///
578    /// - an exclusive reference to the [`TableEntity`] associated to the given [`Table`]
579    /// - an exclusive reference to the [`Fuel`] of the [`StoreInner`].
580    ///
581    /// # Panics
582    ///
583    /// - If the [`Table`] does not originate from this [`Store`].
584    /// - If the [`Table`] cannot be resolved to its entity.
585    pub fn resolve_table_and_fuel_mut(&mut self, table: &Table) -> (&mut TableEntity, &mut Fuel) {
586        let idx = self.unwrap_stored(table.as_inner());
587        let table = Self::resolve_mut(idx, &mut self.tables);
588        let fuel = &mut self.fuel;
589        (table, fuel)
590    }
591
592    /// Returns an exclusive reference to the [`TableEntity`] associated to the given [`Table`].
593    ///
594    /// # Panics
595    ///
596    /// - If the [`Table`] does not originate from this [`Store`].
597    /// - If the [`Table`] cannot be resolved to its entity.
598    pub fn resolve_table_pair_and_fuel(
599        &mut self,
600        fst: &Table,
601        snd: &Table,
602    ) -> (&mut TableEntity, &mut TableEntity, &mut Fuel) {
603        let fst = self.unwrap_stored(fst.as_inner());
604        let snd = self.unwrap_stored(snd.as_inner());
605        let (fst, snd) = self.tables.get_pair_mut(fst, snd).unwrap_or_else(|| {
606            panic!("failed to resolve stored pair of entities: {fst:?} and {snd:?}")
607        });
608        let fuel = &mut self.fuel;
609        (fst, snd, fuel)
610    }
611
612    /// Returns a triple of:
613    ///
614    /// - An exclusive reference to the [`TableEntity`] associated to the given [`Table`].
615    /// - A shared reference to the [`ElementSegmentEntity`] associated to the given [`ElementSegment`].
616    ///
617    /// # Note
618    ///
619    /// This method exists to properly handle use cases where
620    /// otherwise the Rust borrow-checker would not accept.
621    ///
622    /// # Panics
623    ///
624    /// - If the [`Table`] does not originate from this [`Store`].
625    /// - If the [`Table`] cannot be resolved to its entity.
626    /// - If the [`ElementSegment`] does not originate from this [`Store`].
627    /// - If the [`ElementSegment`] cannot be resolved to its entity.
628    pub(super) fn resolve_table_element(
629        &mut self,
630        table: &Table,
631        segment: &ElementSegment,
632    ) -> (&mut TableEntity, &ElementSegmentEntity) {
633        let table_idx = self.unwrap_stored(table.as_inner());
634        let elem_idx = segment.as_inner();
635        let elem = self.resolve(elem_idx, &self.elems);
636        let table = Self::resolve_mut(table_idx, &mut self.tables);
637        (table, elem)
638    }
639
640    /// Returns the following data:
641    ///
642    /// - A shared reference to the [`InstanceEntity`] associated to the given [`Instance`].
643    /// - An exclusive reference to the [`TableEntity`] associated to the given [`Table`].
644    /// - A shared reference to the [`ElementSegmentEntity`] associated to the given [`ElementSegment`].
645    /// - An exclusive reference to the [`Fuel`] of the [`StoreInner`].
646    ///
647    /// # Note
648    ///
649    /// This method exists to properly handle use cases where
650    /// otherwise the Rust borrow-checker would not accept.
651    ///
652    /// # Panics
653    ///
654    /// - If the [`Instance`] does not originate from this [`Store`].
655    /// - If the [`Instance`] cannot be resolved to its entity.
656    /// - If the [`Table`] does not originate from this [`Store`].
657    /// - If the [`Table`] cannot be resolved to its entity.
658    /// - If the [`ElementSegment`] does not originate from this [`Store`].
659    /// - If the [`ElementSegment`] cannot be resolved to its entity.
660    pub(super) fn resolve_table_init_params(
661        &mut self,
662        instance: &Instance,
663        table: &Table,
664        segment: &ElementSegment,
665    ) -> (
666        &InstanceEntity,
667        &mut TableEntity,
668        &ElementSegmentEntity,
669        &mut Fuel,
670    ) {
671        let mem_idx = self.unwrap_stored(table.as_inner());
672        let data_idx = segment.as_inner();
673        let instance_idx = instance.as_inner();
674        let instance = self.resolve(instance_idx, &self.instances);
675        let data = self.resolve(data_idx, &self.elems);
676        let mem = Self::resolve_mut(mem_idx, &mut self.tables);
677        let fuel = &mut self.fuel;
678        (instance, mem, data, fuel)
679    }
680
681    /// Returns a shared reference to the [`ElementSegmentEntity`] associated to the given [`ElementSegment`].
682    ///
683    /// # Panics
684    ///
685    /// - If the [`ElementSegment`] does not originate from this [`Store`].
686    /// - If the [`ElementSegment`] cannot be resolved to its entity.
687    #[allow(unused)] // Note: We allow this unused API to exist to uphold code symmetry.
688    pub fn resolve_element_segment(&self, segment: &ElementSegment) -> &ElementSegmentEntity {
689        self.resolve(segment.as_inner(), &self.elems)
690    }
691
692    /// Returns an exclusive reference to the [`ElementSegmentEntity`] associated to the given [`ElementSegment`].
693    ///
694    /// # Panics
695    ///
696    /// - If the [`ElementSegment`] does not originate from this [`Store`].
697    /// - If the [`ElementSegment`] cannot be resolved to its entity.
698    pub fn resolve_element_segment_mut(
699        &mut self,
700        segment: &ElementSegment,
701    ) -> &mut ElementSegmentEntity {
702        let idx = self.unwrap_stored(segment.as_inner());
703        Self::resolve_mut(idx, &mut self.elems)
704    }
705
706    /// Returns a shared reference to the [`MemoryEntity`] associated to the given [`Memory`].
707    ///
708    /// # Panics
709    ///
710    /// - If the [`Memory`] does not originate from this [`Store`].
711    /// - If the [`Memory`] cannot be resolved to its entity.
712    pub fn resolve_memory(&self, memory: &Memory) -> &MemoryEntity {
713        self.resolve(memory.as_inner(), &self.memories)
714    }
715
716    /// Returns an exclusive reference to the [`MemoryEntity`] associated to the given [`Memory`].
717    ///
718    /// # Panics
719    ///
720    /// - If the [`Memory`] does not originate from this [`Store`].
721    /// - If the [`Memory`] cannot be resolved to its entity.
722    pub fn resolve_memory_mut(&mut self, memory: &Memory) -> &mut MemoryEntity {
723        let idx = self.unwrap_stored(memory.as_inner());
724        Self::resolve_mut(idx, &mut self.memories)
725    }
726
727    /// Returns an exclusive reference to the [`MemoryEntity`] associated to the given [`Memory`].
728    ///
729    /// # Panics
730    ///
731    /// - If the [`Memory`] does not originate from this [`Store`].
732    /// - If the [`Memory`] cannot be resolved to its entity.
733    pub fn resolve_memory_and_fuel_mut(
734        &mut self,
735        memory: &Memory,
736    ) -> (&mut MemoryEntity, &mut Fuel) {
737        let idx = self.unwrap_stored(memory.as_inner());
738        let memory = Self::resolve_mut(idx, &mut self.memories);
739        let fuel = &mut self.fuel;
740        (memory, fuel)
741    }
742
743    /// Returns the triple of:
744    ///
745    /// - An exclusive reference to the [`MemoryEntity`] associated to the given [`Memory`].
746    /// - A shared reference to the [`DataSegmentEntity`] associated to the given [`DataSegment`].
747    /// - An exclusive reference to the [`Fuel`] for fuel metering.
748    ///
749    ///
750    /// # Note
751    ///
752    /// This method exists to properly handle use cases where
753    /// otherwise the Rust borrow-checker would not accept.
754    ///
755    /// # Panics
756    ///
757    /// - If the [`Memory`] does not originate from this [`Store`].
758    /// - If the [`Memory`] cannot be resolved to its entity.
759    /// - If the [`DataSegment`] does not originate from this [`Store`].
760    /// - If the [`DataSegment`] cannot be resolved to its entity.
761    pub(super) fn resolve_memory_init_triplet(
762        &mut self,
763        memory: &Memory,
764        segment: &DataSegment,
765    ) -> (&mut MemoryEntity, &DataSegmentEntity, &mut Fuel) {
766        let mem_idx = self.unwrap_stored(memory.as_inner());
767        let data_idx = segment.as_inner();
768        let data = self.resolve(data_idx, &self.datas);
769        let mem = Self::resolve_mut(mem_idx, &mut self.memories);
770        let fuel = &mut self.fuel;
771        (mem, data, fuel)
772    }
773
774    /// Returns an exclusive reference to the [`DataSegmentEntity`] associated to the given [`DataSegment`].
775    ///
776    /// # Panics
777    ///
778    /// - If the [`DataSegment`] does not originate from this [`Store`].
779    /// - If the [`DataSegment`] cannot be resolved to its entity.
780    pub fn resolve_data_segment_mut(&mut self, segment: &DataSegment) -> &mut DataSegmentEntity {
781        let idx = self.unwrap_stored(segment.as_inner());
782        Self::resolve_mut(idx, &mut self.datas)
783    }
784
785    /// Returns a shared reference to the [`InstanceEntity`] associated to the given [`Instance`].
786    ///
787    /// # Panics
788    ///
789    /// - If the [`Instance`] does not originate from this [`Store`].
790    /// - If the [`Instance`] cannot be resolved to its entity.
791    pub fn resolve_instance(&self, instance: &Instance) -> &InstanceEntity {
792        self.resolve(instance.as_inner(), &self.instances)
793    }
794
795    /// Returns a shared reference to the [`ExternObjectEntity`] associated to the given [`ExternObject`].
796    ///
797    /// # Panics
798    ///
799    /// - If the [`ExternObject`] does not originate from this [`Store`].
800    /// - If the [`ExternObject`] cannot be resolved to its entity.
801    pub fn resolve_external_object(&self, object: &ExternObject) -> &ExternObjectEntity {
802        self.resolve(object.as_inner(), &self.extern_objects)
803    }
804
805    /// Allocates a new Wasm or host [`FuncEntity`] and returns a [`Func`] reference to it.
806    pub fn alloc_func(&mut self, func: FuncEntity) -> Func {
807        let idx = self.funcs.alloc(func);
808        Func::from_inner(self.wrap_stored(idx))
809    }
810
811    /// Returns a shared reference to the associated entity of the Wasm or host function.
812    ///
813    /// # Panics
814    ///
815    /// - If the [`Func`] does not originate from this [`Store`].
816    /// - If the [`Func`] cannot be resolved to its entity.
817    pub fn resolve_func(&self, func: &Func) -> &FuncEntity {
818        let entity_index = self.unwrap_stored(func.as_inner());
819        self.funcs.get(entity_index).unwrap_or_else(|| {
820            panic!("failed to resolve stored Wasm or host function: {entity_index:?}")
821        })
822    }
823}
824
825impl<T> Default for Store<T>
826where
827    T: Default,
828{
829    fn default() -> Self {
830        let engine = Engine::default();
831        Self {
832            inner: StoreInner::new(&engine),
833            trampolines: Arena::new(),
834            data: T::default(),
835            limiter: None,
836        }
837    }
838}
839
840impl<T> Store<T> {
841    /// Creates a new store.
842    pub fn new(engine: &Engine, data: T) -> Self {
843        Self {
844            inner: StoreInner::new(engine),
845            trampolines: Arena::new(),
846            data,
847            limiter: None,
848        }
849    }
850
851    /// Returns the [`Engine`] that this store is associated with.
852    pub fn engine(&self) -> &Engine {
853        self.inner.engine()
854    }
855
856    /// Returns a shared reference to the user provided data owned by this [`Store`].
857    pub fn data(&self) -> &T {
858        &self.data
859    }
860
861    /// Returns an exclusive reference to the user provided data owned by this [`Store`].
862    pub fn data_mut(&mut self) -> &mut T {
863        &mut self.data
864    }
865
866    /// Consumes `self` and returns its user provided data.
867    pub fn into_data(self) -> T {
868        self.data
869    }
870
871    /// Installs a function into the [`Store`] that will be called with the user
872    /// data type `T` to retrieve a [`ResourceLimiter`] any time a limited,
873    /// growable resource such as a linear memory or table is grown.
874    pub fn limiter(
875        &mut self,
876        limiter: impl FnMut(&mut T) -> &mut (dyn ResourceLimiter) + Send + Sync + 'static,
877    ) {
878        self.limiter = Some(ResourceLimiterQuery(Box::new(limiter)))
879    }
880
881    pub(crate) fn check_new_instances_limit(
882        &mut self,
883        num_new_instances: usize,
884    ) -> Result<(), InstantiationError> {
885        let (inner, mut limiter) = self.store_inner_and_resource_limiter_ref();
886        if let Some(limiter) = limiter.as_resource_limiter() {
887            if inner.instances.len().saturating_add(num_new_instances) > limiter.instances() {
888                return Err(InstantiationError::TooManyInstances);
889            }
890        }
891        Ok(())
892    }
893
894    pub(crate) fn check_new_memories_limit(
895        &mut self,
896        num_new_memories: usize,
897    ) -> Result<(), MemoryError> {
898        let (inner, mut limiter) = self.store_inner_and_resource_limiter_ref();
899        if let Some(limiter) = limiter.as_resource_limiter() {
900            if inner.memories.len().saturating_add(num_new_memories) > limiter.memories() {
901                return Err(MemoryError::TooManyMemories);
902            }
903        }
904        Ok(())
905    }
906
907    pub(crate) fn check_new_tables_limit(
908        &mut self,
909        num_new_tables: usize,
910    ) -> Result<(), TableError> {
911        let (inner, mut limiter) = self.store_inner_and_resource_limiter_ref();
912        if let Some(limiter) = limiter.as_resource_limiter() {
913            if inner.tables.len().saturating_add(num_new_tables) > limiter.tables() {
914                return Err(TableError::TooManyTables);
915            }
916        }
917        Ok(())
918    }
919
920    pub(crate) fn store_inner_and_resource_limiter_ref(
921        &mut self,
922    ) -> (&mut StoreInner, ResourceLimiterRef) {
923        let resource_limiter = ResourceLimiterRef(match &mut self.limiter {
924            Some(q) => Some(q.0(&mut self.data)),
925            None => None,
926        });
927        (&mut self.inner, resource_limiter)
928    }
929
930    /// Returns the remaining fuel of the [`Store`] if fuel metering is enabled.
931    ///
932    /// # Note
933    ///
934    /// Enable fuel metering via [`Config::consume_fuel`](crate::Config::consume_fuel).
935    ///
936    /// # Errors
937    ///
938    /// If fuel metering is disabled.
939    pub fn get_fuel(&self) -> Result<u64, FuelError> {
940        self.inner.fuel.get_fuel()
941    }
942
943    /// Sets the remaining fuel of the [`Store`] to `value` if fuel metering is enabled.
944    ///
945    /// # Note
946    ///
947    /// Enable fuel metering via [`Config::consume_fuel`](crate::Config::consume_fuel).
948    ///
949    /// # Errors
950    ///
951    /// If fuel metering is disabled.
952    pub fn set_fuel(&mut self, fuel: u64) -> Result<(), FuelError> {
953        self.inner.fuel.set_fuel(fuel)
954    }
955
956    /// Allocates a new [`TrampolineEntity`] and returns a [`Trampoline`] reference to it.
957    pub(super) fn alloc_trampoline(&mut self, func: TrampolineEntity<T>) -> Trampoline {
958        let idx = self.trampolines.alloc(func);
959        Trampoline::from_inner(self.inner.wrap_stored(idx))
960    }
961
962    /// Returns an exclusive reference to the [`MemoryEntity`] associated to the given [`Memory`]
963    /// and an exclusive reference to the user provided host state.
964    ///
965    /// # Note
966    ///
967    /// This method exists to properly handle use cases where
968    /// otherwise the Rust borrow-checker would not accept.
969    ///
970    /// # Panics
971    ///
972    /// - If the [`Memory`] does not originate from this [`Store`].
973    /// - If the [`Memory`] cannot be resolved to its entity.
974    pub(super) fn resolve_memory_and_state_mut(
975        &mut self,
976        memory: &Memory,
977    ) -> (&mut MemoryEntity, &mut T) {
978        (self.inner.resolve_memory_mut(memory), &mut self.data)
979    }
980
981    /// Returns a shared reference to the associated entity of the host function trampoline.
982    ///
983    /// # Panics
984    ///
985    /// - If the [`Trampoline`] does not originate from this [`Store`].
986    /// - If the [`Trampoline`] cannot be resolved to its entity.
987    pub(super) fn resolve_trampoline(&self, func: &Trampoline) -> &TrampolineEntity<T> {
988        let entity_index = self.inner.unwrap_stored(func.as_inner());
989        self.trampolines
990            .get(entity_index)
991            .unwrap_or_else(|| panic!("failed to resolve stored host function: {entity_index:?}"))
992    }
993}
994
995/// A trait used to get shared access to a [`Store`] in Wasmi.
996pub trait AsContext {
997    /// The user state associated with the [`Store`], aka the `T` in `Store<T>`.
998    type Data;
999
1000    /// Returns the store context that this type provides access to.
1001    fn as_context(&self) -> StoreContext<Self::Data>;
1002}
1003
1004/// A trait used to get exclusive access to a [`Store`] in Wasmi.
1005pub trait AsContextMut: AsContext {
1006    /// Returns the store context that this type provides access to.
1007    fn as_context_mut(&mut self) -> StoreContextMut<Self::Data>;
1008}
1009
1010/// A temporary handle to a [`&Store<T>`][`Store`].
1011///
1012/// This type is suitable for [`AsContext`] trait bounds on methods if desired.
1013/// For more information, see [`Store`].
1014#[derive(Debug, Copy, Clone)]
1015#[repr(transparent)]
1016pub struct StoreContext<'a, T> {
1017    pub(crate) store: &'a Store<T>,
1018}
1019
1020impl<'a, T> StoreContext<'a, T> {
1021    /// Returns the underlying [`Engine`] this store is connected to.
1022    pub fn engine(&self) -> &Engine {
1023        self.store.engine()
1024    }
1025
1026    /// Access the underlying data owned by this store.
1027    ///
1028    /// Same as [`Store::data`].
1029    pub fn data(&self) -> &T {
1030        self.store.data()
1031    }
1032
1033    /// Returns the remaining fuel of the [`Store`] if fuel metering is enabled.
1034    ///
1035    /// For more information see [`Store::get_fuel`](crate::Store::get_fuel).
1036    ///
1037    /// # Errors
1038    ///
1039    /// If fuel metering is disabled.
1040    pub fn get_fuel(&self) -> Result<u64, FuelError> {
1041        self.store.get_fuel()
1042    }
1043}
1044
1045impl<'a, T: AsContext> From<&'a T> for StoreContext<'a, T::Data> {
1046    #[inline]
1047    fn from(ctx: &'a T) -> Self {
1048        ctx.as_context()
1049    }
1050}
1051
1052impl<'a, T: AsContext> From<&'a mut T> for StoreContext<'a, T::Data> {
1053    #[inline]
1054    fn from(ctx: &'a mut T) -> Self {
1055        T::as_context(ctx)
1056    }
1057}
1058
1059impl<'a, T: AsContextMut> From<&'a mut T> for StoreContextMut<'a, T::Data> {
1060    #[inline]
1061    fn from(ctx: &'a mut T) -> Self {
1062        ctx.as_context_mut()
1063    }
1064}
1065
1066/// A temporary handle to a [`&mut Store<T>`][`Store`].
1067///
1068/// This type is suitable for [`AsContextMut`] or [`AsContext`] trait bounds on methods if desired.
1069/// For more information, see [`Store`].
1070#[derive(Debug)]
1071#[repr(transparent)]
1072pub struct StoreContextMut<'a, T> {
1073    pub(crate) store: &'a mut Store<T>,
1074}
1075
1076impl<'a, T> StoreContextMut<'a, T> {
1077    /// Returns the underlying [`Engine`] this store is connected to.
1078    pub fn engine(&self) -> &Engine {
1079        self.store.engine()
1080    }
1081
1082    /// Access the underlying data owned by this store.
1083    ///
1084    /// Same as [`Store::data`].
1085    pub fn data(&self) -> &T {
1086        self.store.data()
1087    }
1088
1089    /// Access the underlying data owned by this store.
1090    ///
1091    /// Same as [`Store::data_mut`].
1092    pub fn data_mut(&mut self) -> &mut T {
1093        self.store.data_mut()
1094    }
1095
1096    /// Returns the remaining fuel of the [`Store`] if fuel metering is enabled.
1097    ///
1098    /// For more information see [`Store::get_fuel`](crate::Store::get_fuel).
1099    ///
1100    /// # Errors
1101    ///
1102    /// If fuel metering is disabled.
1103    pub fn get_fuel(&self) -> Result<u64, FuelError> {
1104        self.store.get_fuel()
1105    }
1106
1107    /// Sets the remaining fuel of the [`Store`] to `value` if fuel metering is enabled.
1108    ///
1109    /// For more information see [`Store::get_fuel`](crate::Store::set_fuel).
1110    ///
1111    /// # Errors
1112    ///
1113    /// If fuel metering is disabled.
1114    pub fn set_fuel(&mut self, fuel: u64) -> Result<(), FuelError> {
1115        self.store.set_fuel(fuel)
1116    }
1117}
1118
1119impl<T> AsContext for &'_ T
1120where
1121    T: AsContext,
1122{
1123    type Data = T::Data;
1124
1125    #[inline]
1126    fn as_context(&self) -> StoreContext<'_, T::Data> {
1127        T::as_context(*self)
1128    }
1129}
1130
1131impl<T> AsContext for &'_ mut T
1132where
1133    T: AsContext,
1134{
1135    type Data = T::Data;
1136
1137    #[inline]
1138    fn as_context(&self) -> StoreContext<'_, T::Data> {
1139        T::as_context(*self)
1140    }
1141}
1142
1143impl<T> AsContextMut for &'_ mut T
1144where
1145    T: AsContextMut,
1146{
1147    #[inline]
1148    fn as_context_mut(&mut self) -> StoreContextMut<'_, T::Data> {
1149        T::as_context_mut(*self)
1150    }
1151}
1152
1153impl<T> AsContext for StoreContext<'_, T> {
1154    type Data = T;
1155
1156    #[inline]
1157    fn as_context(&self) -> StoreContext<'_, Self::Data> {
1158        StoreContext { store: self.store }
1159    }
1160}
1161
1162impl<T> AsContext for StoreContextMut<'_, T> {
1163    type Data = T;
1164
1165    #[inline]
1166    fn as_context(&self) -> StoreContext<'_, Self::Data> {
1167        StoreContext { store: self.store }
1168    }
1169}
1170
1171impl<T> AsContextMut for StoreContextMut<'_, T> {
1172    #[inline]
1173    fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::Data> {
1174        StoreContextMut {
1175            store: &mut *self.store,
1176        }
1177    }
1178}
1179
1180impl<T> AsContext for Store<T> {
1181    type Data = T;
1182
1183    #[inline]
1184    fn as_context(&self) -> StoreContext<'_, Self::Data> {
1185        StoreContext { store: self }
1186    }
1187}
1188
1189impl<T> AsContextMut for Store<T> {
1190    #[inline]
1191    fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::Data> {
1192        StoreContextMut { store: self }
1193    }
1194}