Skip to main content

wasmtime_environ/
module.rs

1//! Data structures for representing decoded wasm modules.
2
3use crate::prelude::*;
4use crate::*;
5use core::ops::Range;
6use cranelift_entity::{EntityRef, packed_option::ReservedValue};
7use serde_derive::{Deserialize, Serialize};
8
9/// A WebAssembly linear memory initializer.
10#[derive(Clone, Debug)]
11pub struct MemoryInitializer<'a> {
12    /// The index of a linear memory to initialize.
13    pub memory_index: MemoryIndex,
14    /// The base offset to start this segment at.
15    pub offset: ConstExpr,
16    /// The range of the data to write within the linear memory.
17    ///
18    /// This range indexes into a separately stored data section which will be
19    /// provided with the compiled module's code as well.
20    pub data: &'a [u8],
21}
22
23/// The type of WebAssembly linear memory initialization to use for a module.
24#[derive(Debug, Serialize, Deserialize)]
25pub enum MemoryInitialization {
26    /// Memory initialization is segmented.
27    ///
28    /// Segmented initialization can be used for any module, but it is required
29    /// if:
30    ///
31    /// * A data segment referenced an imported memory.
32    /// * A data segment uses a global base.
33    ///
34    /// Segmented initialization is performed by processing the complete set of
35    /// data segments when the module is instantiated.
36    ///
37    /// This is the default memory initialization type.
38    Segmented,
39
40    /// Memory initialization is statically known and involves a single `memcpy`
41    /// or otherwise simply making the defined data visible.
42    ///
43    /// To be statically initialized everything must reference a defined memory
44    /// and all data segments have a statically known in-bounds base (no
45    /// globals).
46    ///
47    /// This form of memory initialization is a more optimized version of
48    /// `Segmented` where memory can be initialized with one of a few methods:
49    ///
50    /// * First it could be initialized with a single `memcpy` of data from the
51    ///   module to the linear memory.
52    /// * Otherwise techniques like `mmap` are also possible to make this data,
53    ///   which might reside in a compiled module on disk, available immediately
54    ///   in a linear memory's address space.
55    ///
56    /// To facilitate the latter of these techniques the `try_static_init`
57    /// function below, which creates this variant, takes a host page size
58    /// argument which can page-align everything to make mmap-ing possible.
59    Static {
60        /// The initialization contents for each linear memory.
61        ///
62        /// This array has, for each module's own linear memory, the contents
63        /// necessary to initialize it. If the memory has a `None` value then no
64        /// initialization is necessary (it's zero-filled). Otherwise with
65        /// `Some` the first element of the tuple is the offset in memory to
66        /// start the initialization and the `Range` is the range within the
67        /// final data section of the compiled module of bytes to copy into the
68        /// memory.
69        ///
70        /// The offset, range base, and range end are all guaranteed to be page
71        /// aligned to the page size passed in to `try_static_init`.
72        map: TryPrimaryMap<MemoryIndex, Option<(u64, RuntimeDataIndex)>>,
73    },
74}
75
76impl Default for MemoryInitialization {
77    fn default() -> Self {
78        Self::Segmented
79    }
80}
81
82impl MemoryInitialization {
83    /// Returns whether this initialization is of the form
84    /// `MemoryInitialization::Segmented`.
85    pub fn is_segmented(&self) -> bool {
86        match self {
87            MemoryInitialization::Segmented => true,
88            _ => false,
89        }
90    }
91}
92
93/// Table initialization data for all tables in the module.
94#[derive(Debug, Default, Serialize, Deserialize)]
95pub struct TableInitialization {
96    /// Initial values for tables defined within the module itself.
97    ///
98    /// This contains the initial values and initializers for tables defined
99    /// within a wasm, so excluding imported tables. This initializer can
100    /// represent null-initialized tables, element-initialized tables (e.g. with
101    /// the function-references proposal), or precomputed images of table
102    /// initialization. For example table initializers to a table that are all
103    /// in-bounds will get removed from `segment` and moved into
104    /// `initial_values` here.
105    pub initial_values: TryPrimaryMap<DefinedTableIndex, TableInitialValue>,
106
107    /// Element segments present in the initial wasm module which are executed
108    /// at instantiation time.
109    ///
110    /// These element segments are iterated over during instantiation to apply
111    /// any segments that weren't already moved into `initial_values` above.
112    pub segments: TryVec<TableSegment>,
113}
114
115/// Initial value for all elements in a table.
116#[derive(Debug, Serialize, Deserialize)]
117pub enum TableInitialValue {
118    /// Initialize each table element to null, optionally setting some elements
119    /// to non-null given the precomputed image.
120    Null,
121    /// An arbitrary const expression.
122    Expr(ConstExpr),
123}
124
125/// A WebAssembly table initializer segment.
126#[derive(Clone, Debug, Serialize, Deserialize)]
127pub struct TableSegment {
128    /// The index of a table to initialize.
129    pub table_index: TableIndex,
130    /// The base offset to start this segment at.
131    pub offset: ConstExpr,
132    /// The values to write into the table elements.
133    pub elements: TableSegmentElements,
134}
135
136/// Elements of a table segment, either a list of functions or list of arbitrary
137/// expressions.
138#[derive(Clone, Debug, Serialize, Deserialize)]
139pub enum TableSegmentElements {
140    /// A sequential list of functions where `FuncIndex::reserved_value()`
141    /// indicates a null function.
142    Functions(
143        #[serde(deserialize_with = "crate::types::deserialize_boxed_slice")] Box<[FuncIndex]>,
144    ),
145    /// Arbitrary expressions, aka either functions, null or a load of a global.
146    Expressions {
147        /// The type of each element in `exprs`.
148        ty: WasmRefType,
149        /// The const expressions for this segment's elements.
150        #[serde(deserialize_with = "crate::types::deserialize_boxed_slice")]
151        exprs: Box<[ConstExpr]>,
152    },
153}
154
155impl TableSegmentElements {
156    /// Returns the type of this segment.
157    pub fn ty(&self) -> WasmRefType {
158        match self {
159            Self::Functions(_) => WasmRefType::FUNCREF,
160            Self::Expressions { ty, .. } => *ty,
161        }
162    }
163
164    /// Returns the number of elements in this segment.
165    pub fn len(&self) -> u64 {
166        match self {
167            Self::Functions(s) => u64::try_from(s.len()).unwrap(),
168            Self::Expressions { exprs, .. } => u64::try_from(exprs.len()).unwrap(),
169        }
170    }
171}
172
173/// A translated WebAssembly module, excluding the function bodies and
174/// memory initializers.
175#[derive(Debug, Serialize, Deserialize)]
176pub struct Module {
177    /// This module's index.
178    pub module_index: StaticModuleIndex,
179
180    /// A pool of strings used in this module.
181    pub strings: StringPool,
182
183    /// The name of this wasm module, often found in the wasm file.
184    pub name: Option<Atom>,
185
186    /// All import records, in the order they are declared in the module.
187    pub initializers: TryVec<Initializer>,
188
189    /// Exported entities.
190    pub exports: TryIndexMap<Atom, EntityIndex>,
191
192    /// Whether or not this module has a start function,
193    pub startup: ModuleStartup,
194
195    /// Precompute per-table static images, if applicable.
196    ///
197    /// This map tracks, for each defined table in this module, the initial
198    /// precomputed contents of the table. This is only applicable for funcref
199    /// tables and the `TryVec` here uses `FuncIndex::reserved_value()` for null
200    /// entries. This structure is filled in if table initialization is detected
201    /// to be infallible as part of [`ModuleTranslation::finalize_table_init`].
202    pub table_initialization: TryPrimaryMap<DefinedTableIndex, TryVec<FuncIndex>>,
203
204    /// WebAssembly linear memory initializer.
205    ///
206    /// This will track how memory is initialized, either exclusively via
207    /// segments or if some memories can be initialized with static images. This
208    /// is computed during [`ModuleTranslation::finalize_memory_init`].
209    pub memory_initialization: MemoryInitialization,
210
211    /// WebAssembly passive elements.
212    ///
213    /// This is a map of all passive element segments to their type and the
214    /// initial size of the segment. Note that the contents of the segment are
215    /// initialized by compiled code.
216    pub passive_elements: TryPrimaryMap<PassiveElemIndex, (WasmRefType, u64)>,
217
218    /// Where runtime data segments are located in the module's image.
219    ///
220    /// Note that this does not directly correspond to either active or passive
221    /// data segments. Those are massaged during
222    /// [`ModuleTranslation::finalize_memory_init`] into the form used here.
223    pub runtime_data: TryPrimaryMap<RuntimeDataIndex, Range<u32>>,
224
225    /// Types declared in the wasm module.
226    pub types: TryPrimaryMap<TypeIndex, EngineOrModuleTypeIndex>,
227
228    /// Number of imported or aliased functions in the module.
229    pub num_imported_funcs: usize,
230
231    /// Number of imported or aliased tables in the module.
232    pub num_imported_tables: usize,
233
234    /// Number of imported or aliased memories in the module.
235    pub num_imported_memories: usize,
236
237    /// Number of imported or aliased globals in the module.
238    pub num_imported_globals: usize,
239
240    /// Number of imported or aliased tags in the module.
241    pub num_imported_tags: usize,
242
243    /// Does this module need a GC heap to run?
244    pub needs_gc_heap: bool,
245
246    /// Does this module's compiled code check its memories' shadows for
247    /// watchpoints (`Tunables::memory_watchpoints`), and so need a pointer to
248    /// each memory's shadow `VMMemoryDefinition` in its `VMContext`?
249    pub has_shadow_memories: bool,
250
251    /// Number of functions that "escape" from this module may need to have a
252    /// `VMFuncRef` constructed for them.
253    ///
254    /// This is also the number of functions in the `functions` array below with
255    /// an `func_ref` index (and is the maximum func_ref index).
256    pub num_escaped_funcs: usize,
257
258    /// Types of functions, imported and local.
259    pub functions: TryPrimaryMap<FuncIndex, FunctionType>,
260
261    /// WebAssembly tables.
262    pub tables: TryPrimaryMap<TableIndex, Table>,
263
264    /// WebAssembly linear memory plans.
265    pub memories: TryPrimaryMap<MemoryIndex, Memory>,
266
267    /// WebAssembly global variables.
268    pub globals: TryPrimaryMap<GlobalIndex, Global>,
269
270    /// "Simple" WebAssembly global initializers for locally-defined globals.
271    ///
272    /// This map does not track initialization of all globals in this module,
273    /// but only those considered "simple" which can be easily evaluated at
274    /// compile-time. For example an initialization expression of `i32.const N`
275    /// is considered simple. These globals are manually initialized in the
276    /// host.
277    ///
278    /// This is all in contrast to [`ModuleTranslation::global_initializers`]
279    /// which is processed in compiled code and initialized after the instance
280    /// has been created.
281    pub global_initializers: TryVec<(DefinedGlobalIndex, GlobalConstValue)>,
282
283    /// WebAssembly exception and control tags.
284    pub tags: TryPrimaryMap<TagIndex, Tag>,
285}
286
287/// Initialization routines for creating an instance, encompassing imports,
288/// modules, instances, aliases, etc.
289#[derive(Debug, Serialize, Deserialize)]
290pub enum Initializer {
291    /// An imported item is required to be provided.
292    Import {
293        /// Name of this import
294        name: Atom,
295        /// The field name projection of this import
296        field: Atom,
297        /// Where this import will be placed, which also has type information
298        /// about the import.
299        index: EntityIndex,
300    },
301}
302
303/// The position of each of a module's imports, suitable for indexing an
304/// instantiation's argument list.
305#[derive(Debug, Default)]
306pub struct ImportPositions {
307    functions: Vec<u32>,
308    tables: Vec<u32>,
309    memories: Vec<u32>,
310    globals: Vec<u32>,
311    tags: Vec<u32>,
312}
313
314impl ImportPositions {
315    /// Get the position of the import that defines the given entity.
316    ///
317    /// Returns `None` when the module defines the entity itself, rather than
318    /// importing it.
319    pub fn get(&self, entity: EntityIndex) -> Option<usize> {
320        let (positions, i) = match entity {
321            EntityIndex::Function(i) => (&self.functions, i.index()),
322            EntityIndex::Table(i) => (&self.tables, i.index()),
323            EntityIndex::Memory(i) => (&self.memories, i.index()),
324            EntityIndex::Global(i) => (&self.globals, i.index()),
325            EntityIndex::Tag(i) => (&self.tags, i.index()),
326        };
327        let position = *positions.get(i)?;
328        Some(usize::try_from(position).unwrap())
329    }
330}
331
332impl Module {
333    /// Allocates the module data structures.
334    pub fn new(module_index: StaticModuleIndex) -> Self {
335        Self {
336            module_index,
337            strings: Default::default(),
338            name: Default::default(),
339            initializers: Default::default(),
340            exports: Default::default(),
341            startup: ModuleStartup::None,
342            table_initialization: Default::default(),
343            memory_initialization: Default::default(),
344            passive_elements: Default::default(),
345            runtime_data: Default::default(),
346            types: Default::default(),
347            num_imported_funcs: Default::default(),
348            num_imported_tables: Default::default(),
349            num_imported_memories: Default::default(),
350            num_imported_globals: Default::default(),
351            num_imported_tags: Default::default(),
352            needs_gc_heap: Default::default(),
353            has_shadow_memories: Default::default(),
354            num_escaped_funcs: Default::default(),
355            functions: Default::default(),
356            tables: Default::default(),
357            memories: Default::default(),
358            globals: Default::default(),
359            global_initializers: Default::default(),
360            tags: Default::default(),
361        }
362    }
363
364    /// Convert a `DefinedFuncIndex` into a `FuncIndex`.
365    #[inline]
366    pub fn func_index(&self, defined_func: DefinedFuncIndex) -> FuncIndex {
367        FuncIndex::new(self.num_imported_funcs + defined_func.index())
368    }
369
370    /// Convert a `FuncIndex` into a `DefinedFuncIndex`. Returns None if the
371    /// index is an imported function.
372    #[inline]
373    pub fn defined_func_index(&self, func: FuncIndex) -> Option<DefinedFuncIndex> {
374        if func.index() < self.num_imported_funcs {
375            None
376        } else {
377            Some(DefinedFuncIndex::new(
378                func.index() - self.num_imported_funcs,
379            ))
380        }
381    }
382
383    /// Test whether the given function index is for an imported function.
384    #[inline]
385    pub fn is_imported_function(&self, index: FuncIndex) -> bool {
386        index.index() < self.num_imported_funcs
387    }
388
389    /// Convert a `DefinedTableIndex` into a `TableIndex`.
390    #[inline]
391    pub fn table_index(&self, defined_table: DefinedTableIndex) -> TableIndex {
392        TableIndex::new(self.num_imported_tables + defined_table.index())
393    }
394
395    /// Convert a `TableIndex` into a `DefinedTableIndex`. Returns None if the
396    /// index is an imported table.
397    #[inline]
398    pub fn defined_table_index(&self, table: TableIndex) -> Option<DefinedTableIndex> {
399        if table.index() < self.num_imported_tables {
400            None
401        } else {
402            Some(DefinedTableIndex::new(
403                table.index() - self.num_imported_tables,
404            ))
405        }
406    }
407
408    /// Test whether the given table index is for an exported table.
409    #[inline]
410    pub fn is_exported_table(&self, index: TableIndex) -> bool {
411        self.exports.values().any(|entity| *entity == index.into())
412    }
413
414    /// Test whether the given table index is for an imported table.
415    #[inline]
416    pub fn is_imported_table(&self, index: TableIndex) -> bool {
417        index.index() < self.num_imported_tables
418    }
419
420    /// Convert a `DefinedMemoryIndex` into a `MemoryIndex`.
421    #[inline]
422    pub fn memory_index(&self, defined_memory: DefinedMemoryIndex) -> MemoryIndex {
423        MemoryIndex::new(self.num_imported_memories + defined_memory.index())
424    }
425
426    /// Convert a `MemoryIndex` into a `DefinedMemoryIndex`. Returns None if the
427    /// index is an imported memory.
428    #[inline]
429    pub fn defined_memory_index(&self, memory: MemoryIndex) -> Option<DefinedMemoryIndex> {
430        if memory.index() < self.num_imported_memories {
431            None
432        } else {
433            Some(DefinedMemoryIndex::new(
434                memory.index() - self.num_imported_memories,
435            ))
436        }
437    }
438
439    /// Convert a `DefinedMemoryIndex` into an `OwnedMemoryIndex`. Returns None
440    /// if the index is an imported memory.
441    #[inline]
442    pub fn owned_memory_index(&self, memory: DefinedMemoryIndex) -> OwnedMemoryIndex {
443        assert!(
444            memory.index() < self.memories.len(),
445            "non-shared memory must have an owned index"
446        );
447
448        // Once we know that the memory index is not greater than the number of
449        // plans, we can iterate through the plans up to the memory index and
450        // count how many are not shared (i.e., owned).
451        let owned_memory_index = self
452            .memories
453            .iter()
454            .skip(self.num_imported_memories)
455            .take(memory.index())
456            .filter(|(_, mp)| !mp.shared)
457            .count();
458        OwnedMemoryIndex::new(owned_memory_index)
459    }
460
461    /// Test whether the given memory index is for an exported memory.
462    #[inline]
463    pub fn is_exported_memory(&self, index: MemoryIndex) -> bool {
464        self.exports.values().any(|entity| *entity == index.into())
465    }
466
467    /// Test whether the given memory index is for an imported memory.
468    #[inline]
469    pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
470        index.index() < self.num_imported_memories
471    }
472
473    /// Convert a `DefinedGlobalIndex` into a `GlobalIndex`.
474    #[inline]
475    pub fn global_index(&self, defined_global: DefinedGlobalIndex) -> GlobalIndex {
476        GlobalIndex::new(self.num_imported_globals + defined_global.index())
477    }
478
479    /// Convert a `GlobalIndex` into a `DefinedGlobalIndex`. Returns None if the
480    /// index is an imported global.
481    #[inline]
482    pub fn defined_global_index(&self, global: GlobalIndex) -> Option<DefinedGlobalIndex> {
483        if global.index() < self.num_imported_globals {
484            None
485        } else {
486            Some(DefinedGlobalIndex::new(
487                global.index() - self.num_imported_globals,
488            ))
489        }
490    }
491
492    /// Test whether the given global index is for an exported global.
493    #[inline]
494    pub fn is_exported_global(&self, index: GlobalIndex) -> bool {
495        self.exports.values().any(|entity| *entity == index.into())
496    }
497
498    /// Test whether the given global index is for an imported global.
499    #[inline]
500    pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
501        index.index() < self.num_imported_globals
502    }
503
504    /// Test whether the given tag index is for an imported tag.
505    #[inline]
506    pub fn is_imported_tag(&self, index: TagIndex) -> bool {
507        index.index() < self.num_imported_tags
508    }
509
510    /// Convert a `DefinedTagIndex` into a `TagIndex`.
511    #[inline]
512    pub fn tag_index(&self, defined_tag: DefinedTagIndex) -> TagIndex {
513        TagIndex::new(self.num_imported_tags + defined_tag.index())
514    }
515
516    /// Convert a `TagIndex` into a `DefinedTagIndex`. Returns None if the
517    /// index is an imported tag.
518    #[inline]
519    pub fn defined_tag_index(&self, tag: TagIndex) -> Option<DefinedTagIndex> {
520        if tag.index() < self.num_imported_tags {
521            None
522        } else {
523            Some(DefinedTagIndex::new(tag.index() - self.num_imported_tags))
524        }
525    }
526
527    /// Returns an iterator of all the imports in this module, along with their
528    /// module name, field name, and type that's being imported.
529    pub fn imports(&self) -> impl ExactSizeIterator<Item = (&str, &str, EntityType)> {
530        let pool = &self.strings;
531        self.initializers.iter().map(move |i| match i {
532            Initializer::Import { name, field, index } => {
533                (&pool[name], &pool[field], self.type_of(*index))
534            }
535        })
536    }
537
538    /// Get this module's `i`th import.
539    pub fn import(&self, i: usize) -> Option<(&str, &str, EntityType)> {
540        match self.initializers.get(i)? {
541            Initializer::Import { name, field, index } => Some((
542                &self.strings[name],
543                &self.strings[field],
544                self.type_of(*index),
545            )),
546        }
547    }
548
549    /// Get the entity index for this module's `i`th import.
550    pub fn import_index(&self, i: usize) -> Option<EntityIndex> {
551        match self.initializers.get(i)? {
552            Initializer::Import { index, .. } => Some(*index),
553        }
554    }
555
556    /// Test whether the given entity index refers to one of this module's
557    /// imports, rather than to something it defines itself.
558    pub fn is_imported(&self, entity: EntityIndex) -> bool {
559        match entity {
560            EntityIndex::Function(i) => self.is_imported_function(i),
561            EntityIndex::Table(i) => self.is_imported_table(i),
562            EntityIndex::Memory(i) => self.is_imported_memory(i),
563            EntityIndex::Global(i) => self.is_imported_global(i),
564            EntityIndex::Tag(i) => self.is_imported_tag(i),
565        }
566    }
567
568    /// Compute the position of every import, suitable for indexing an
569    /// instantiation's argument list.
570    pub fn import_positions(&self) -> ImportPositions {
571        let mut positions = ImportPositions::default();
572        for (position, initializer) in self.initializers.iter().enumerate() {
573            let Initializer::Import { index, .. } = initializer;
574            let position = u32::try_from(position).unwrap();
575            let (vec, i) = match *index {
576                EntityIndex::Function(i) => (&mut positions.functions, i.index()),
577                EntityIndex::Table(i) => (&mut positions.tables, i.index()),
578                EntityIndex::Memory(i) => (&mut positions.memories, i.index()),
579                EntityIndex::Global(i) => (&mut positions.globals, i.index()),
580                EntityIndex::Tag(i) => (&mut positions.tags, i.index()),
581            };
582            debug_assert_eq!(vec.len(), i);
583            vec.push(position);
584        }
585        positions
586    }
587
588    /// Returns the type of an item based on its index
589    pub fn type_of(&self, index: EntityIndex) -> EntityType {
590        match index {
591            EntityIndex::Global(i) => EntityType::Global(self.globals[i]),
592            EntityIndex::Table(i) => EntityType::Table(self.tables[i]),
593            EntityIndex::Memory(i) => EntityType::Memory(self.memories[i]),
594            EntityIndex::Function(i) => EntityType::Function(self.functions[i].signature),
595            EntityIndex::Tag(i) => EntityType::Tag(self.tags[i]),
596        }
597    }
598
599    /// Appends a new tag to this module with the given type information.
600    pub fn push_tag(
601        &mut self,
602        signature: impl Into<EngineOrModuleTypeIndex>,
603        exception: impl Into<EngineOrModuleTypeIndex>,
604    ) -> TagIndex {
605        let signature = signature.into();
606        let exception = exception.into();
607        self.tags
608            .push(Tag {
609                signature,
610                exception,
611            })
612            .panic_on_oom()
613    }
614
615    /// Appends a new function to this module with the given type information,
616    /// used for functions that either don't escape or aren't certain whether
617    /// they escape yet.
618    pub fn push_function(&mut self, signature: impl Into<EngineOrModuleTypeIndex>) -> FuncIndex {
619        let signature = signature.into();
620        self.functions
621            .push(FunctionType {
622                signature,
623                func_ref: FuncRefIndex::reserved_value(),
624            })
625            .panic_on_oom()
626    }
627
628    /// Returns an iterator over all of the defined function indices in this
629    /// module.
630    pub fn defined_func_indices(&self) -> impl ExactSizeIterator<Item = DefinedFuncIndex> + use<> {
631        (0..self.functions.len() - self.num_imported_funcs).map(|i| DefinedFuncIndex::new(i))
632    }
633
634    /// Returns the number of functions defined by this module itself: all
635    /// functions minus imported functions.
636    pub fn num_defined_funcs(&self) -> usize {
637        self.functions.len() - self.num_imported_funcs
638    }
639
640    /// Returns the number of tables defined by this module itself: all tables
641    /// minus imported tables.
642    pub fn num_defined_tables(&self) -> usize {
643        self.tables.len() - self.num_imported_tables
644    }
645
646    /// Returns the number of memories defined by this module itself: all
647    /// memories minus imported memories.
648    pub fn num_defined_memories(&self) -> usize {
649        self.memories.len() - self.num_imported_memories
650    }
651
652    /// Returns the number of globals defined by this module itself: all
653    /// globals minus imported globals.
654    pub fn num_defined_globals(&self) -> usize {
655        self.globals.len() - self.num_imported_globals
656    }
657
658    /// Returns the number of tags defined by this module itself: all tags
659    /// minus imported tags.
660    pub fn num_defined_tags(&self) -> usize {
661        self.tags.len() - self.num_imported_tags
662    }
663
664    /// Tests whether `index` is valid for this module.
665    pub fn is_valid(&self, index: EntityIndex) -> bool {
666        match index {
667            EntityIndex::Function(i) => self.functions.is_valid(i),
668            EntityIndex::Table(i) => self.tables.is_valid(i),
669            EntityIndex::Memory(i) => self.memories.is_valid(i),
670            EntityIndex::Global(i) => self.globals.is_valid(i),
671            EntityIndex::Tag(i) => self.tags.is_valid(i),
672        }
673    }
674}
675
676impl TypeTrace for Module {
677    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
678    where
679        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
680    {
681        // NB: Do not `..` elide unmodified fields so that we get compile errors
682        // when adding new fields that might need re-canonicalization.
683        let Self {
684            module_index: _,
685            strings: _,
686            name: _,
687            initializers: _,
688            exports: _,
689            startup,
690            table_initialization: _,
691            memory_initialization: _,
692            passive_elements: _,
693            runtime_data: _,
694            types,
695            num_imported_funcs: _,
696            num_imported_tables: _,
697            num_imported_memories: _,
698            num_imported_globals: _,
699            num_imported_tags: _,
700            num_escaped_funcs: _,
701            needs_gc_heap: _,
702            has_shadow_memories: _,
703            functions,
704            tables,
705            memories: _,
706            globals,
707            global_initializers: _,
708            tags,
709        } = self;
710
711        for t in types.values().copied() {
712            func(t)?;
713        }
714        for f in functions.values() {
715            f.trace(func)?;
716        }
717        for t in tables.values() {
718            t.trace(func)?;
719        }
720        for g in globals.values() {
721            g.trace(func)?;
722        }
723        for t in tags.values() {
724            t.trace(func)?;
725        }
726        startup.trace(func)?;
727        Ok(())
728    }
729
730    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
731    where
732        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
733    {
734        // NB: Do not `..` elide unmodified fields so that we get compile errors
735        // when adding new fields that might need re-canonicalization.
736        let Self {
737            module_index: _,
738            strings: _,
739            name: _,
740            initializers: _,
741            exports: _,
742            startup,
743            table_initialization: _,
744            memory_initialization: _,
745            passive_elements: _,
746            runtime_data: _,
747            types,
748            num_imported_funcs: _,
749            num_imported_tables: _,
750            num_imported_memories: _,
751            num_imported_globals: _,
752            num_imported_tags: _,
753            num_escaped_funcs: _,
754            needs_gc_heap: _,
755            has_shadow_memories: _,
756            functions,
757            tables,
758            memories: _,
759            globals,
760            global_initializers: _,
761            tags,
762        } = self;
763
764        for t in types.values_mut() {
765            func(t)?;
766        }
767        for f in functions.values_mut() {
768            f.trace_mut(func)?;
769        }
770        for t in tables.values_mut() {
771            t.trace_mut(func)?;
772        }
773        for g in globals.values_mut() {
774            g.trace_mut(func)?;
775        }
776        for t in tags.values_mut() {
777            t.trace_mut(func)?;
778        }
779        startup.trace_mut(func)?;
780        Ok(())
781    }
782}
783
784impl TypeTrace for ModuleStartup {
785    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
786    where
787        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
788    {
789        match self {
790            ModuleStartup::None => Ok(()),
791            ModuleStartup::Always(t) | ModuleStartup::IfMemoriesNeedInit(t) => func(*t),
792        }
793    }
794
795    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
796    where
797        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
798    {
799        match self {
800            ModuleStartup::None => Ok(()),
801            ModuleStartup::Always(t) | ModuleStartup::IfMemoriesNeedInit(t) => func(t),
802        }
803    }
804}
805
806/// Type information about functions in a wasm module.
807#[derive(Debug, Serialize, Deserialize)]
808pub struct FunctionType {
809    /// The type of this function, indexed into the module-wide type tables for
810    /// a module compilation.
811    pub signature: EngineOrModuleTypeIndex,
812    /// The index into the funcref table, if present. Note that this is
813    /// `reserved_value()` if the function does not escape from a module.
814    pub func_ref: FuncRefIndex,
815}
816
817impl TypeTrace for FunctionType {
818    fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
819    where
820        F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
821    {
822        func(self.signature)
823    }
824
825    fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
826    where
827        F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
828    {
829        func(&mut self.signature)
830    }
831}
832
833impl FunctionType {
834    /// Returns whether this function's type is one that "escapes" the current
835    /// module, meaning that the function is exported, used in `ref.func`, used
836    /// in a table, etc.
837    pub fn is_escaping(&self) -> bool {
838        !self.func_ref.is_reserved_value()
839    }
840}
841
842/// Index into the funcref table within a VMContext for a function.
843#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
844pub struct FuncRefIndex(u32);
845cranelift_entity::entity_impl!(FuncRefIndex);
846
847/// Different means of startup for a wasm module.
848#[derive(Debug, Serialize, Deserialize)]
849pub enum ModuleStartup {
850    /// No startup is necessary.
851    None,
852
853    /// Startup is always required, for example to apply active table segments.
854    ///
855    /// The type of the startup function, of wasm signature `[] -> []`, is
856    /// provided here.
857    Always(EngineOrModuleTypeIndex),
858
859    /// Startup is only required if some linear memory within this module, at
860    /// runtime, says `needs_init() == true`.
861    ///
862    /// This special mode of startup indicates that the startup function has no
863    /// purpose other than to initialize the initial contents of
864    /// `MemoryInitialization::Static` linear memories. In this situation if all
865    /// memories say `needs_init() == false` then the startup function won't
866    /// actually do anything meaning that it can be optimized slightly by
867    /// skipping it entirely.
868    IfMemoriesNeedInit(EngineOrModuleTypeIndex),
869}
870
871impl ModuleStartup {
872    /// Returns if this is `ModuleStartup::None`.
873    pub fn is_none(&self) -> bool {
874        matches!(self, Self::None)
875    }
876}