wasmi/engine/
mod.rs

1//! The Wasmi interpreter.
2
3mod block_type;
4pub mod bytecode;
5mod cache;
6mod code_map;
7mod config;
8mod executor;
9mod func_args;
10mod func_types;
11mod limits;
12mod resumable;
13mod traits;
14mod translator;
15
16#[cfg(test)]
17mod tests;
18
19#[cfg(test)]
20use self::bytecode::RegisterSpan;
21
22pub(crate) use self::{
23    block_type::BlockType,
24    config::FuelCosts,
25    executor::Stack,
26    func_args::{FuncFinished, FuncParams, FuncResults},
27    func_types::DedupFuncType,
28    translator::{
29        FuncTranslationDriver,
30        FuncTranslator,
31        FuncTranslatorAllocations,
32        LazyFuncTranslator,
33        ValidatingFuncTranslator,
34        WasmTranslator,
35    },
36};
37pub use self::{
38    code_map::CompiledFunc,
39    config::{CompilationMode, Config},
40    executor::ResumableHostError,
41    limits::{EnforcedLimits, EnforcedLimitsError, StackLimits},
42    resumable::{ResumableCall, ResumableInvocation, TypedResumableCall, TypedResumableInvocation},
43    traits::{CallParams, CallResults},
44    translator::{Instr, TranslationError},
45};
46use self::{
47    code_map::{CodeMap, CompiledFuncEntity},
48    func_types::FuncTypeRegistry,
49    resumable::ResumableCallBase,
50};
51use crate::{
52    collections::arena::{ArenaIndex, GuardedEntity},
53    module::{FuncIdx, ModuleHeader},
54    Error,
55    Func,
56    FuncType,
57    StoreContextMut,
58};
59use core::sync::atomic::{AtomicU32, Ordering};
60use spin::{Mutex, RwLock};
61use std::{
62    sync::{Arc, Weak},
63    vec::Vec,
64};
65use wasmparser::{FuncToValidate, FuncValidatorAllocations, ValidatorResources};
66
67#[cfg(test)]
68use self::bytecode::Instruction;
69
70#[cfg(test)]
71use crate::core::UntypedVal;
72
73#[cfg(doc)]
74use crate::Store;
75
76/// A unique engine index.
77///
78/// # Note
79///
80/// Used to protect against invalid entity indices.
81#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
82pub struct EngineIdx(u32);
83
84impl ArenaIndex for EngineIdx {
85    fn into_usize(self) -> usize {
86        self.0 as _
87    }
88
89    fn from_usize(value: usize) -> Self {
90        let value = value.try_into().unwrap_or_else(|error| {
91            panic!("index {value} is out of bounds as engine index: {error}")
92        });
93        Self(value)
94    }
95}
96
97impl EngineIdx {
98    /// Returns a new unique [`EngineIdx`].
99    fn new() -> Self {
100        /// A static store index counter.
101        static CURRENT_STORE_IDX: AtomicU32 = AtomicU32::new(0);
102        let next_idx = CURRENT_STORE_IDX.fetch_add(1, Ordering::AcqRel);
103        Self(next_idx)
104    }
105}
106
107/// An entity owned by the [`Engine`].
108type Guarded<Idx> = GuardedEntity<EngineIdx, Idx>;
109
110/// The Wasmi interpreter.
111///
112/// # Note
113///
114/// - The current Wasmi engine implements a bytecode interpreter.
115/// - This structure is intentionally cheap to copy.
116///   Most of its API has a `&self` receiver, so can be shared easily.
117#[derive(Debug, Clone)]
118pub struct Engine {
119    inner: Arc<EngineInner>,
120}
121
122/// A weak reference to an [`Engine`].
123#[derive(Debug, Clone)]
124pub struct EngineWeak {
125    inner: Weak<EngineInner>,
126}
127
128impl EngineWeak {
129    /// Upgrades the [`EngineWeak`] to an [`Engine`].
130    ///
131    /// Returns `None` if strong references (the [`Engine`] itself) no longer exist.
132    pub fn upgrade(&self) -> Option<Engine> {
133        let inner = self.inner.upgrade()?;
134        Some(Engine { inner })
135    }
136}
137
138impl Default for Engine {
139    fn default() -> Self {
140        Self::new(&Config::default())
141    }
142}
143
144impl Engine {
145    /// Creates a new [`Engine`] with default configuration.
146    ///
147    /// # Note
148    ///
149    /// Users should ues [`Engine::default`] to construct a default [`Engine`].
150    pub fn new(config: &Config) -> Self {
151        Self {
152            inner: Arc::new(EngineInner::new(config)),
153        }
154    }
155
156    /// Creates an [`EngineWeak`] from the given [`Engine`].
157    pub fn weak(&self) -> EngineWeak {
158        EngineWeak {
159            inner: Arc::downgrade(&self.inner),
160        }
161    }
162
163    /// Returns a shared reference to the [`Config`] of the [`Engine`].
164    pub fn config(&self) -> &Config {
165        self.inner.config()
166    }
167
168    /// Returns `true` if both [`Engine`] references `a` and `b` refer to the same [`Engine`].
169    pub fn same(a: &Engine, b: &Engine) -> bool {
170        Arc::ptr_eq(&a.inner, &b.inner)
171    }
172
173    /// Allocates a new function type to the [`Engine`].
174    pub(super) fn alloc_func_type(&self, func_type: FuncType) -> DedupFuncType {
175        self.inner.alloc_func_type(func_type)
176    }
177
178    /// Resolves a deduplicated function type into a [`FuncType`] entity.
179    ///
180    /// # Panics
181    ///
182    /// - If the deduplicated function type is not owned by the engine.
183    /// - If the deduplicated function type cannot be resolved to its entity.
184    pub(super) fn resolve_func_type<F, R>(&self, func_type: &DedupFuncType, f: F) -> R
185    where
186        F: FnOnce(&FuncType) -> R,
187    {
188        self.inner.resolve_func_type(func_type, f)
189    }
190
191    /// Allocates a new uninitialized [`CompiledFunc`] to the [`Engine`].
192    ///
193    /// Returns a [`CompiledFunc`] reference to allow accessing the allocated [`CompiledFunc`].
194    pub(super) fn alloc_func(&self) -> CompiledFunc {
195        self.inner.alloc_func()
196    }
197
198    /// Translates the Wasm function using the [`Engine`].
199    ///
200    /// - Uses the internal [`Config`] to drive the function translation as mandated.
201    /// - Reuses translation and validation allocations to be more efficient when used for many translation units.
202    ///
203    /// # Parameters
204    ///
205    /// - `func_index`: The index of the translated function within its Wasm module.
206    /// - `compiled_func`: The index of the translated function in the [`Engine`].
207    /// - `offset`: The global offset of the Wasm function body within the Wasm binary.
208    /// - `bytes`: The bytes that make up the Wasm encoded function body of the translated function.
209    /// - `module`: The module header information of the Wasm module of the translated function.
210    /// - `func_to_validate`: Optionally validates the translated function.
211    ///
212    /// # Errors
213    ///
214    /// - If function translation fails.
215    /// - If function validation fails.
216    pub(crate) fn translate_func(
217        &self,
218        func_index: FuncIdx,
219        compiled_func: CompiledFunc,
220        offset: usize,
221        bytes: &[u8],
222        module: ModuleHeader,
223        func_to_validate: Option<FuncToValidate<ValidatorResources>>,
224    ) -> Result<(), Error> {
225        match (self.config().get_compilation_mode(), func_to_validate) {
226            (CompilationMode::Eager, Some(func_to_validate)) => {
227                let (translation_allocs, validation_allocs) = self.inner.get_allocs();
228                let validator = func_to_validate.into_validator(validation_allocs);
229                let translator = FuncTranslator::new(func_index, module, translation_allocs)?;
230                let translator = ValidatingFuncTranslator::new(validator, translator)?;
231                let allocs = FuncTranslationDriver::new(offset, bytes, translator)?
232                    .translate(|func_entity| self.inner.init_func(compiled_func, func_entity))?;
233                self.inner
234                    .recycle_allocs(allocs.translation, allocs.validation);
235            }
236            (CompilationMode::Eager, None) => {
237                let allocs = self.inner.get_translation_allocs();
238                let translator = FuncTranslator::new(func_index, module, allocs)?;
239                let allocs = FuncTranslationDriver::new(offset, bytes, translator)?
240                    .translate(|func_entity| self.inner.init_func(compiled_func, func_entity))?;
241                self.inner.recycle_translation_allocs(allocs);
242            }
243            (CompilationMode::LazyTranslation, Some(func_to_validate)) => {
244                let allocs = self.inner.get_validation_allocs();
245                let translator = LazyFuncTranslator::new(func_index, compiled_func, module, None);
246                let validator = func_to_validate.into_validator(allocs);
247                let translator = ValidatingFuncTranslator::new(validator, translator)?;
248                let allocs = FuncTranslationDriver::new(offset, bytes, translator)?
249                    .translate(|func_entity| self.inner.init_func(compiled_func, func_entity))?;
250                self.inner.recycle_validation_allocs(allocs.validation);
251            }
252            (CompilationMode::Lazy | CompilationMode::LazyTranslation, func_to_validate) => {
253                let translator =
254                    LazyFuncTranslator::new(func_index, compiled_func, module, func_to_validate);
255                FuncTranslationDriver::new(offset, bytes, translator)?
256                    .translate(|func_entity| self.inner.init_func(compiled_func, func_entity))?;
257            }
258        }
259        Ok(())
260    }
261
262    /// Returns reusable [`FuncTranslatorAllocations`] from the [`Engine`].
263    pub(crate) fn get_translation_allocs(&self) -> FuncTranslatorAllocations {
264        self.inner.get_translation_allocs()
265    }
266
267    /// Returns reusable [`FuncTranslatorAllocations`] and [`FuncValidatorAllocations`] from the [`Engine`].
268    pub(crate) fn get_allocs(&self) -> (FuncTranslatorAllocations, FuncValidatorAllocations) {
269        self.inner.get_allocs()
270    }
271
272    /// Recycles the given [`FuncTranslatorAllocations`] in the [`Engine`].
273    pub(crate) fn recycle_translation_allocs(&self, allocs: FuncTranslatorAllocations) {
274        self.inner.recycle_translation_allocs(allocs)
275    }
276
277    /// Recycles the given [`FuncTranslatorAllocations`] and [`FuncValidatorAllocations`] in the [`Engine`].
278    pub(crate) fn recycle_allocs(
279        &self,
280        translation: FuncTranslatorAllocations,
281        validation: FuncValidatorAllocations,
282    ) {
283        self.inner.recycle_allocs(translation, validation)
284    }
285
286    /// Initializes the uninitialized [`CompiledFunc`] for the [`Engine`].
287    ///
288    /// # Note
289    ///
290    /// The initialized function will not be compiled after this call and instead
291    /// be prepared to be compiled on the fly when it is called the first time.
292    ///
293    /// # Panics
294    ///
295    /// - If `func` is an invalid [`CompiledFunc`] reference for this [`CodeMap`].
296    /// - If `func` refers to an already initialized [`CompiledFunc`].
297    fn init_lazy_func(
298        &self,
299        func_idx: FuncIdx,
300        func: CompiledFunc,
301        bytes: &[u8],
302        module: &ModuleHeader,
303        func_to_validate: Option<FuncToValidate<ValidatorResources>>,
304    ) {
305        self.inner
306            .init_lazy_func(func_idx, func, bytes, module, func_to_validate)
307    }
308
309    /// Resolves the [`CompiledFunc`] to the underlying Wasmi bytecode instructions.
310    ///
311    /// # Note
312    ///
313    /// - This is a variant of [`Engine::resolve_instr`] that returns register
314    ///   machine based bytecode instructions.
315    /// - This API is mainly intended for unit testing purposes and shall not be used
316    ///   outside of this context. The function bodies are intended to be data private
317    ///   to the Wasmi interpreter.
318    ///
319    /// # Errors
320    ///
321    /// If the `func` fails Wasm to Wasmi bytecode translation after it was lazily initialized.
322    ///
323    /// # Panics
324    ///
325    /// - If the [`CompiledFunc`] is invalid for the [`Engine`].
326    /// - If register machine bytecode translation is disabled.
327    #[cfg(test)]
328    pub(crate) fn resolve_instr(
329        &self,
330        func: CompiledFunc,
331        index: usize,
332    ) -> Result<Option<Instruction>, Error> {
333        self.inner.resolve_instr(func, index)
334    }
335
336    /// Resolves the function local constant of [`CompiledFunc`] at `index` if any.
337    ///
338    /// # Note
339    ///
340    /// This API is intended for unit testing purposes and shall not be used
341    /// outside of this context. The function bodies are intended to be data
342    /// private to the Wasmi interpreter.
343    ///
344    /// # Errors
345    ///
346    /// If the `func` fails Wasm to Wasmi bytecode translation after it was lazily initialized.
347    ///
348    /// # Panics
349    ///
350    /// - If the [`CompiledFunc`] is invalid for the [`Engine`].
351    /// - If register machine bytecode translation is disabled.
352    #[cfg(test)]
353    fn get_func_const(
354        &self,
355        func: CompiledFunc,
356        index: usize,
357    ) -> Result<Option<UntypedVal>, Error> {
358        self.inner.get_func_const(func, index)
359    }
360
361    /// Executes the given [`Func`] with parameters `params`.
362    ///
363    /// Stores the execution result into `results` upon a successful execution.
364    ///
365    /// # Note
366    ///
367    /// - Assumes that the `params` and `results` are well typed.
368    ///   Type checks are done at the [`Func::call`] API or when creating
369    ///   a new [`TypedFunc`] instance via [`Func::typed`].
370    /// - The `params` out parameter is in a valid but unspecified state if this
371    ///   function returns with an error.
372    ///
373    /// # Errors
374    ///
375    /// - If `params` are overflowing or underflowing the expected amount of parameters.
376    /// - If the given `results` do not match the the length of the expected results of `func`.
377    /// - When encountering a Wasm or host trap during the execution of `func`.
378    ///
379    /// [`TypedFunc`]: [`crate::TypedFunc`]
380    #[inline]
381    pub(crate) fn execute_func<T, Results>(
382        &self,
383        ctx: StoreContextMut<T>,
384        func: &Func,
385        params: impl CallParams,
386        results: Results,
387    ) -> Result<<Results as CallResults>::Results, Error>
388    where
389        Results: CallResults,
390    {
391        self.inner.execute_func(ctx, func, params, results)
392    }
393
394    /// Executes the given [`Func`] resumably with parameters `params` and returns.
395    ///
396    /// Stores the execution result into `results` upon a successful execution.
397    /// If the execution encounters a host trap it will return a handle to the user
398    /// that allows to resume the execution at that point.
399    ///
400    /// # Note
401    ///
402    /// - Assumes that the `params` and `results` are well typed.
403    ///   Type checks are done at the [`Func::call`] API or when creating
404    ///   a new [`TypedFunc`] instance via [`Func::typed`].
405    /// - The `params` out parameter is in a valid but unspecified state if this
406    ///   function returns with an error.
407    ///
408    /// # Errors
409    ///
410    /// - If `params` are overflowing or underflowing the expected amount of parameters.
411    /// - If the given `results` do not match the the length of the expected results of `func`.
412    /// - When encountering a Wasm trap during the execution of `func`.
413    /// - When `func` is a host function that traps.
414    ///
415    /// [`TypedFunc`]: [`crate::TypedFunc`]
416    #[inline]
417    pub(crate) fn execute_func_resumable<T, Results>(
418        &self,
419        ctx: StoreContextMut<T>,
420        func: &Func,
421        params: impl CallParams,
422        results: Results,
423    ) -> Result<ResumableCallBase<<Results as CallResults>::Results>, Error>
424    where
425        Results: CallResults,
426    {
427        self.inner
428            .execute_func_resumable(ctx, func, params, results)
429    }
430
431    /// Resumes the given `invocation` given the `params`.
432    ///
433    /// Stores the execution result into `results` upon a successful execution.
434    /// If the execution encounters a host trap it will return a handle to the user
435    /// that allows to resume the execution at that point.
436    ///
437    /// # Note
438    ///
439    /// - Assumes that the `params` and `results` are well typed.
440    ///   Type checks are done at the [`Func::call`] API or when creating
441    ///   a new [`TypedFunc`] instance via [`Func::typed`].
442    /// - The `params` out parameter is in a valid but unspecified state if this
443    ///   function returns with an error.
444    ///
445    /// # Errors
446    ///
447    /// - If `params` are overflowing or underflowing the expected amount of parameters.
448    /// - If the given `results` do not match the the length of the expected results of `func`.
449    /// - When encountering a Wasm trap during the execution of `func`.
450    /// - When `func` is a host function that traps.
451    ///
452    /// [`TypedFunc`]: [`crate::TypedFunc`]
453    #[inline]
454    pub(crate) fn resume_func<T, Results>(
455        &self,
456        ctx: StoreContextMut<T>,
457        invocation: ResumableInvocation,
458        params: impl CallParams,
459        results: Results,
460    ) -> Result<ResumableCallBase<<Results as CallResults>::Results>, Error>
461    where
462        Results: CallResults,
463    {
464        self.inner.resume_func(ctx, invocation, params, results)
465    }
466
467    /// Recycles the given [`Stack`] for reuse in the [`Engine`].
468    pub(crate) fn recycle_stack(&self, stack: Stack) {
469        self.inner.recycle_stack(stack)
470    }
471}
472
473/// The internal state of the Wasmi [`Engine`].
474#[derive(Debug)]
475pub struct EngineInner {
476    /// The [`Config`] of the engine.
477    config: Config,
478    /// Engine resources shared across multiple engine executors.
479    res: RwLock<EngineResources>,
480    /// Reusable allocation stacks.
481    allocs: Mutex<ReusableAllocationStack>,
482    /// Reusable engine stacks for Wasm execution.
483    ///
484    /// Concurrently executing Wasm executions each require their own stack to
485    /// operate on. Therefore a Wasm engine is required to provide stacks and
486    /// ideally recycles old ones since creation of a new stack is rather expensive.
487    stacks: Mutex<EngineStacks>,
488}
489
490/// Stacks to hold and distribute reusable allocations.
491pub struct ReusableAllocationStack {
492    /// The maximum height of each of the allocations stacks.
493    max_height: usize,
494    /// Allocations required by Wasm function translators.
495    translation: Vec<FuncTranslatorAllocations>,
496    /// Allocations required by Wasm function validators.
497    validation: Vec<FuncValidatorAllocations>,
498}
499
500impl Default for ReusableAllocationStack {
501    fn default() -> Self {
502        Self {
503            max_height: 1,
504            translation: Vec::new(),
505            validation: Vec::new(),
506        }
507    }
508}
509
510impl core::fmt::Debug for ReusableAllocationStack {
511    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
512        f.debug_struct("ReusableAllocationStack")
513            .field("translation", &self.translation)
514            // Note: FuncValidatorAllocations is missing Debug impl at the time of writing this commit.
515            //       We should derive Debug as soon as FuncValidatorAllocations has a Debug impl in future
516            //       wasmparser versions.
517            .field("validation", &self.validation.len())
518            .finish()
519    }
520}
521
522impl ReusableAllocationStack {
523    /// Returns reusable [`FuncTranslatorAllocations`] from the [`Engine`].
524    pub fn get_translation_allocs(&mut self) -> FuncTranslatorAllocations {
525        self.translation.pop().unwrap_or_default()
526    }
527
528    /// Returns reusable [`FuncValidatorAllocations`] from the [`Engine`].
529    pub fn get_validation_allocs(&mut self) -> FuncValidatorAllocations {
530        self.validation.pop().unwrap_or_default()
531    }
532
533    /// Recycles the given [`FuncTranslatorAllocations`] in the [`Engine`].
534    pub fn recycle_translation_allocs(&mut self, recycled: FuncTranslatorAllocations) {
535        debug_assert!(self.translation.len() <= self.max_height);
536        if self.translation.len() >= self.max_height {
537            return;
538        }
539        self.translation.push(recycled);
540    }
541
542    /// Recycles the given [`FuncValidatorAllocations`] in the [`Engine`].
543    pub fn recycle_validation_allocs(&mut self, recycled: FuncValidatorAllocations) {
544        debug_assert!(self.validation.len() <= self.max_height);
545        if self.validation.len() >= self.max_height {
546            return;
547        }
548        self.validation.push(recycled);
549    }
550}
551
552/// The engine's stacks for reuse.
553///
554/// Rquired for efficient concurrent Wasm executions.
555#[derive(Debug)]
556pub struct EngineStacks {
557    /// Stacks to be (re)used.
558    stacks: Vec<Stack>,
559    /// Stack limits for newly constructed engine stacks.
560    limits: StackLimits,
561    /// How many stacks should be kept for reuse at most.
562    keep: usize,
563}
564
565impl EngineStacks {
566    /// Creates new [`EngineStacks`] with the given [`StackLimits`].
567    pub fn new(config: &Config) -> Self {
568        Self {
569            stacks: Vec::new(),
570            limits: config.stack_limits(),
571            keep: config.cached_stacks(),
572        }
573    }
574
575    /// Reuse or create a new [`Stack`] if none was available.
576    pub fn reuse_or_new(&mut self) -> Stack {
577        match self.stacks.pop() {
578            Some(stack) => stack,
579            None => Stack::new(self.limits),
580        }
581    }
582
583    /// Disose and recycle the `stack`.
584    pub fn recycle(&mut self, stack: Stack) {
585        if stack.capacity() > 0 && self.stacks.len() < self.keep {
586            self.stacks.push(stack);
587        }
588    }
589}
590
591impl EngineInner {
592    /// Creates a new [`EngineInner`] with the given [`Config`].
593    fn new(config: &Config) -> Self {
594        Self {
595            config: *config,
596            res: RwLock::new(EngineResources::new(config)),
597            allocs: Mutex::new(ReusableAllocationStack::default()),
598            stacks: Mutex::new(EngineStacks::new(config)),
599        }
600    }
601
602    /// Returns a shared reference to the [`Config`] of the [`EngineInner`].
603    fn config(&self) -> &Config {
604        &self.config
605    }
606
607    /// Allocates a new function type to the [`EngineInner`].
608    fn alloc_func_type(&self, func_type: FuncType) -> DedupFuncType {
609        self.res.write().func_types.alloc_func_type(func_type)
610    }
611
612    /// Resolves a deduplicated function type into a [`FuncType`] entity.
613    ///
614    /// # Panics
615    ///
616    /// - If the deduplicated function type is not owned by the engine.
617    /// - If the deduplicated function type cannot be resolved to its entity.
618    fn resolve_func_type<F, R>(&self, func_type: &DedupFuncType, f: F) -> R
619    where
620        F: FnOnce(&FuncType) -> R,
621    {
622        f(self.res.read().func_types.resolve_func_type(func_type))
623    }
624
625    /// Allocates a new uninitialized [`CompiledFunc`] to the [`EngineInner`].
626    ///
627    /// Returns a [`CompiledFunc`] reference to allow accessing the allocated [`CompiledFunc`].
628    fn alloc_func(&self) -> CompiledFunc {
629        self.res.write().code_map.alloc_func()
630    }
631
632    /// Returns reusable [`FuncTranslatorAllocations`] from the [`Engine`].
633    fn get_translation_allocs(&self) -> FuncTranslatorAllocations {
634        self.allocs.lock().get_translation_allocs()
635    }
636
637    /// Returns reusable [`FuncValidatorAllocations`] from the [`Engine`].
638    fn get_validation_allocs(&self) -> FuncValidatorAllocations {
639        self.allocs.lock().get_validation_allocs()
640    }
641
642    /// Returns reusable [`FuncTranslatorAllocations`] and [`FuncValidatorAllocations`] from the [`Engine`].
643    ///
644    /// # Note
645    ///
646    /// This method is a bit more efficient than calling both
647    /// - [`EngineInner::get_translation_allocs`]
648    /// - [`EngineInner::get_validation_allocs`]
649    fn get_allocs(&self) -> (FuncTranslatorAllocations, FuncValidatorAllocations) {
650        let mut allocs = self.allocs.lock();
651        let translation = allocs.get_translation_allocs();
652        let validation = allocs.get_validation_allocs();
653        (translation, validation)
654    }
655
656    /// Recycles the given [`FuncTranslatorAllocations`] in the [`Engine`].
657    fn recycle_translation_allocs(&self, allocs: FuncTranslatorAllocations) {
658        self.allocs.lock().recycle_translation_allocs(allocs)
659    }
660
661    /// Recycles the given [`FuncValidatorAllocations`] in the [`Engine`].
662    fn recycle_validation_allocs(&self, allocs: FuncValidatorAllocations) {
663        self.allocs.lock().recycle_validation_allocs(allocs)
664    }
665
666    /// Recycles the given [`FuncTranslatorAllocations`] and [`FuncValidatorAllocations`] in the [`Engine`].
667    ///
668    /// # Note
669    ///
670    /// This method is a bit more efficient than calling both
671    /// - [`EngineInner::recycle_translation_allocs`]
672    /// - [`EngineInner::recycle_validation_allocs`]
673    fn recycle_allocs(
674        &self,
675        translation: FuncTranslatorAllocations,
676        validation: FuncValidatorAllocations,
677    ) {
678        let mut allocs = self.allocs.lock();
679        allocs.recycle_translation_allocs(translation);
680        allocs.recycle_validation_allocs(validation);
681    }
682
683    /// Initializes the uninitialized [`CompiledFunc`] for the [`EngineInner`].
684    ///
685    /// # Note
686    ///
687    /// The initialized function will be compiled and ready to be executed after this call.
688    ///
689    /// # Panics
690    ///
691    /// - If `func` is an invalid [`CompiledFunc`] reference for this [`CodeMap`].
692    /// - If `func` refers to an already initialized [`CompiledFunc`].
693    fn init_func(&self, compiled_func: CompiledFunc, func_entity: CompiledFuncEntity) {
694        self.res
695            .write()
696            .code_map
697            .init_func(compiled_func, func_entity)
698    }
699
700    /// Initializes the uninitialized [`CompiledFunc`] for the [`Engine`].
701    ///
702    /// # Note
703    ///
704    /// The initialized function will not be compiled after this call and instead
705    /// be prepared to be compiled on the fly when it is called the first time.
706    ///
707    /// # Panics
708    ///
709    /// - If `func` is an invalid [`CompiledFunc`] reference for this [`CodeMap`].
710    /// - If `func` refers to an already initialized [`CompiledFunc`].
711    fn init_lazy_func(
712        &self,
713        func_idx: FuncIdx,
714        func: CompiledFunc,
715        bytes: &[u8],
716        module: &ModuleHeader,
717        func_to_validate: Option<FuncToValidate<ValidatorResources>>,
718    ) {
719        self.res
720            .write()
721            .code_map
722            .init_lazy_func(func, func_idx, bytes, module, func_to_validate)
723    }
724
725    /// Resolves the [`InternalFuncEntity`] for [`CompiledFunc`] and applies `f` to it.
726    ///
727    /// # Panics
728    ///
729    /// If [`CompiledFunc`] is invalid for [`Engine`].
730    #[cfg(test)]
731    pub(super) fn resolve_func<F, R>(&self, func: CompiledFunc, f: F) -> Result<R, Error>
732    where
733        F: FnOnce(&CompiledFuncEntity) -> R,
734    {
735        // Note: We use `None` so this test-only function will never charge for compilation fuel.
736        Ok(f(self.res.read().code_map.get(None, func)?))
737    }
738
739    /// Returns the [`Instruction`] of `func` at `index`.
740    ///
741    /// Returns `None` if the function has no instruction at `index`.
742    ///
743    /// # Errors
744    ///
745    /// If the `func` fails Wasm to Wasmi bytecode translation after it was lazily initialized.
746    ///
747    /// # Pancis
748    ///
749    /// If `func` cannot be resolved to a function for the [`EngineInner`].
750    #[cfg(test)]
751    pub(crate) fn resolve_instr(
752        &self,
753        func: CompiledFunc,
754        index: usize,
755    ) -> Result<Option<Instruction>, Error> {
756        self.resolve_func(func, |func| func.instrs().get(index).copied())
757    }
758
759    /// Returns the function local constant value of `func` at `index`.
760    ///
761    /// Returns `None` if the function has no function local constant at `index`.
762    ///
763    /// # Errors
764    ///
765    /// If the `func` fails Wasm to Wasmi bytecode translation after it was lazily initialized.
766    ///
767    /// # Pancis
768    ///
769    /// If `func` cannot be resolved to a function for the [`EngineInner`].
770    #[cfg(test)]
771    fn get_func_const(
772        &self,
773        func: CompiledFunc,
774        index: usize,
775    ) -> Result<Option<UntypedVal>, Error> {
776        // Function local constants are stored in reverse order of their indices since
777        // they are allocated in reverse order to their absolute indices during function
778        // translation. That is why we need to access them in reverse order.
779        self.resolve_func(func, |func| func.consts().iter().rev().nth(index).copied())
780    }
781
782    /// Recycles the given [`Stack`].
783    fn recycle_stack(&self, stack: Stack) {
784        self.stacks.lock().recycle(stack)
785    }
786}
787
788/// Engine resources that are immutable during function execution.
789///
790/// Can be shared by multiple engine executors.
791#[derive(Debug)]
792pub struct EngineResources {
793    /// Stores information about all compiled functions.
794    code_map: CodeMap,
795    /// Deduplicated function types.
796    ///
797    /// # Note
798    ///
799    /// The engine deduplicates function types to make the equality
800    /// comparison very fast. This helps to speed up indirect calls.
801    func_types: FuncTypeRegistry,
802}
803
804impl EngineResources {
805    /// Creates a new [`EngineResources`].
806    fn new(config: &Config) -> Self {
807        let engine_idx = EngineIdx::new();
808        Self {
809            code_map: CodeMap::new(config),
810            func_types: FuncTypeRegistry::new(engine_idx),
811        }
812    }
813}