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