Skip to main content

wasmi/engine/
mod.rs

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