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}