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