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}