1 //! Data structures for representing decoded wasm modules.
2 
3 use crate::prelude::*;
4 use crate::*;
5 use alloc::collections::BTreeMap;
6 use core::ops::Range;
7 use cranelift_entity::{EntityRef, packed_option::ReservedValue};
8 use serde_derive::{Deserialize, Serialize};
9 
10 /// A WebAssembly linear memory initializer.
11 #[derive(Clone, Debug, Serialize, Deserialize)]
12 pub struct MemoryInitializer {
13     /// The index of a linear memory to initialize.
14     pub memory_index: MemoryIndex,
15     /// The base offset to start this segment at.
16     pub offset: ConstExpr,
17     /// The range of the data to write within the linear memory.
18     ///
19     /// This range indexes into a separately stored data section which will be
20     /// provided with the compiled module's code as well.
21     pub data: Range<u32>,
22 }
23 
24 /// Similar to the above `MemoryInitializer` but only used when memory
25 /// initializers are statically known to be valid.
26 #[derive(Clone, Debug, Serialize, Deserialize)]
27 pub struct StaticMemoryInitializer {
28     /// The 64-bit offset, in bytes, of where this initializer starts.
29     pub offset: u64,
30 
31     /// The range of data to write at `offset`, where these indices are indexes
32     /// into the compiled wasm module's data section.
33     pub data: Range<u32>,
34 }
35 
36 /// The type of WebAssembly linear memory initialization to use for a module.
37 #[derive(Debug, Serialize, Deserialize)]
38 pub enum MemoryInitialization {
39     /// Memory initialization is segmented.
40     ///
41     /// Segmented initialization can be used for any module, but it is required
42     /// if:
43     ///
44     /// * A data segment referenced an imported memory.
45     /// * A data segment uses a global base.
46     ///
47     /// Segmented initialization is performed by processing the complete set of
48     /// data segments when the module is instantiated.
49     ///
50     /// This is the default memory initialization type.
51     Segmented(TryVec<MemoryInitializer>),
52 
53     /// Memory initialization is statically known and involves a single `memcpy`
54     /// or otherwise simply making the defined data visible.
55     ///
56     /// To be statically initialized everything must reference a defined memory
57     /// and all data segments have a statically known in-bounds base (no
58     /// globals).
59     ///
60     /// This form of memory initialization is a more optimized version of
61     /// `Segmented` where memory can be initialized with one of a few methods:
62     ///
63     /// * First it could be initialized with a single `memcpy` of data from the
64     ///   module to the linear memory.
65     /// * Otherwise techniques like `mmap` are also possible to make this data,
66     ///   which might reside in a compiled module on disk, available immediately
67     ///   in a linear memory's address space.
68     ///
69     /// To facilitate the latter of these techniques the `try_static_init`
70     /// function below, which creates this variant, takes a host page size
71     /// argument which can page-align everything to make mmap-ing possible.
72     Static {
73         /// The initialization contents for each linear memory.
74         ///
75         /// This array has, for each module's own linear memory, the contents
76         /// necessary to initialize it. If the memory has a `None` value then no
77         /// initialization is necessary (it's zero-filled). Otherwise with
78         /// `Some` the first element of the tuple is the offset in memory to
79         /// start the initialization and the `Range` is the range within the
80         /// final data section of the compiled module of bytes to copy into the
81         /// memory.
82         ///
83         /// The offset, range base, and range end are all guaranteed to be page
84         /// aligned to the page size passed in to `try_static_init`.
85         map: TryPrimaryMap<MemoryIndex, Option<StaticMemoryInitializer>>,
86     },
87 }
88 
89 impl Default for MemoryInitialization {
default() -> Self90     fn default() -> Self {
91         Self::Segmented(TryVec::new())
92     }
93 }
94 
95 impl MemoryInitialization {
96     /// Returns whether this initialization is of the form
97     /// `MemoryInitialization::Segmented`.
is_segmented(&self) -> bool98     pub fn is_segmented(&self) -> bool {
99         match self {
100             MemoryInitialization::Segmented(_) => true,
101             _ => false,
102         }
103     }
104 
105     /// Performs the memory initialization steps for this set of initializers.
106     ///
107     /// This will perform wasm initialization in compliance with the wasm spec
108     /// and how data segments are processed. This doesn't need to necessarily
109     /// only be called as part of initialization, however, as it's structured to
110     /// allow learning about memory ahead-of-time at compile time possibly.
111     ///
112     /// This function will return true if all memory initializers are processed
113     /// successfully. If any initializer hits an error or, for example, a
114     /// global value is needed but `None` is returned, then false will be
115     /// returned. At compile-time this typically means that the "error" in
116     /// question needs to be deferred to runtime, and at runtime this means
117     /// that an invalid initializer has been found and a trap should be
118     /// generated.
init_memory(&self, state: &mut dyn InitMemory) -> bool119     pub fn init_memory(&self, state: &mut dyn InitMemory) -> bool {
120         let initializers = match self {
121             // Fall through below to the segmented memory one-by-one
122             // initialization.
123             MemoryInitialization::Segmented(list) => list,
124 
125             // If previously switched to static initialization then pass through
126             // all those parameters here to the `write` callback.
127             //
128             // Note that existence of `Static` already guarantees that all
129             // indices are in-bounds.
130             MemoryInitialization::Static { map } => {
131                 for (index, init) in map {
132                     if let Some(init) = init {
133                         let result = state.write(index, init);
134                         if !result {
135                             return result;
136                         }
137                     }
138                 }
139                 return true;
140             }
141         };
142 
143         for initializer in initializers {
144             let &MemoryInitializer {
145                 memory_index,
146                 ref offset,
147                 ref data,
148             } = initializer;
149 
150             // First up determine the start/end range and verify that they're
151             // in-bounds for the initial size of the memory at `memory_index`.
152             // Note that this can bail if we don't have access to globals yet
153             // (e.g. this is a task happening before instantiation at
154             // compile-time).
155             let start = match state.eval_offset(memory_index, offset) {
156                 Some(start) => start,
157                 None => return false,
158             };
159             let len = u64::try_from(data.len()).unwrap();
160             let end = match start.checked_add(len) {
161                 Some(end) => end,
162                 None => return false,
163             };
164 
165             match state.memory_size_in_bytes(memory_index) {
166                 Ok(max) => {
167                     if end > max {
168                         return false;
169                     }
170                 }
171 
172                 // Note that computing the minimum can overflow if the page size
173                 // is the default 64KiB and the memory's minimum size in pages
174                 // is `1 << 48`, the maximum number of minimum pages for 64-bit
175                 // memories. We don't return `false` to signal an error here and
176                 // instead defer the error to runtime, when it will be
177                 // impossible to allocate that much memory anyways.
178                 Err(_) => {}
179             }
180 
181             // The limits of the data segment have been validated at this point
182             // so the `write` callback is called with the range of data being
183             // written. Any erroneous result is propagated upwards.
184             let init = StaticMemoryInitializer {
185                 offset: start,
186                 data: data.clone(),
187             };
188             let result = state.write(memory_index, &init);
189             if !result {
190                 return result;
191             }
192         }
193 
194         return true;
195     }
196 }
197 
198 /// The various callbacks provided here are used to drive the smaller bits of
199 /// memory initialization.
200 pub trait InitMemory {
201     /// Returns the size, in bytes, of the memory specified. For compile-time
202     /// purposes this would be the memory type's minimum size.
memory_size_in_bytes(&mut self, memory_index: MemoryIndex) -> Result<u64, SizeOverflow>203     fn memory_size_in_bytes(&mut self, memory_index: MemoryIndex) -> Result<u64, SizeOverflow>;
204 
205     /// Returns the value of the constant expression, as a `u64`. Note that
206     /// this may involve zero-extending a 32-bit global to a 64-bit number. May
207     /// return `None` to indicate that the expression involves a value which is
208     /// not available yet.
eval_offset(&mut self, memory_index: MemoryIndex, expr: &ConstExpr) -> Option<u64>209     fn eval_offset(&mut self, memory_index: MemoryIndex, expr: &ConstExpr) -> Option<u64>;
210 
211     /// A callback used to actually write data. This indicates that the
212     /// specified memory must receive the specified range of data at the
213     /// specified offset. This can return false on failure.
write(&mut self, memory_index: MemoryIndex, init: &StaticMemoryInitializer) -> bool214     fn write(&mut self, memory_index: MemoryIndex, init: &StaticMemoryInitializer) -> bool;
215 }
216 
217 /// Table initialization data for all tables in the module.
218 #[derive(Debug, Default, Serialize, Deserialize)]
219 pub struct TableInitialization {
220     /// Initial values for tables defined within the module itself.
221     ///
222     /// This contains the initial values and initializers for tables defined
223     /// within a wasm, so excluding imported tables. This initializer can
224     /// represent null-initialized tables, element-initialized tables (e.g. with
225     /// the function-references proposal), or precomputed images of table
226     /// initialization. For example table initializers to a table that are all
227     /// in-bounds will get removed from `segment` and moved into
228     /// `initial_values` here.
229     pub initial_values: TryPrimaryMap<DefinedTableIndex, TableInitialValue>,
230 
231     /// Element segments present in the initial wasm module which are executed
232     /// at instantiation time.
233     ///
234     /// These element segments are iterated over during instantiation to apply
235     /// any segments that weren't already moved into `initial_values` above.
236     pub segments: TryVec<TableSegment>,
237 }
238 
239 /// Initial value for all elements in a table.
240 #[derive(Debug, Serialize, Deserialize)]
241 pub enum TableInitialValue {
242     /// Initialize each table element to null, optionally setting some elements
243     /// to non-null given the precomputed image.
244     Null {
245         /// A precomputed image of table initializers for this table.
246         ///
247         /// This image is constructed during `try_func_table_init` and
248         /// null-initialized elements are represented with
249         /// `FuncIndex::reserved_value()`. Note that this image is empty by
250         /// default and may not encompass the entire span of the table in which
251         /// case the elements are initialized to null.
252         precomputed: TryVec<FuncIndex>,
253     },
254     /// An arbitrary const expression.
255     Expr(ConstExpr),
256 }
257 
258 /// A WebAssembly table initializer segment.
259 #[derive(Clone, Debug, Serialize, Deserialize)]
260 pub struct TableSegment {
261     /// The index of a table to initialize.
262     pub table_index: TableIndex,
263     /// The base offset to start this segment at.
264     pub offset: ConstExpr,
265     /// The values to write into the table elements.
266     pub elements: TableSegmentElements,
267 }
268 
269 /// Elements of a table segment, either a list of functions or list of arbitrary
270 /// expressions.
271 #[derive(Clone, Debug, Serialize, Deserialize)]
272 pub enum TableSegmentElements {
273     /// A sequential list of functions where `FuncIndex::reserved_value()`
274     /// indicates a null function.
275     Functions(Box<[FuncIndex]>),
276     /// Arbitrary expressions, aka either functions, null or a load of a global.
277     Expressions(Box<[ConstExpr]>),
278 }
279 
280 impl TableSegmentElements {
281     /// Returns the number of elements in this segment.
len(&self) -> u64282     pub fn len(&self) -> u64 {
283         match self {
284             Self::Functions(s) => u64::try_from(s.len()).unwrap(),
285             Self::Expressions(s) => u64::try_from(s.len()).unwrap(),
286         }
287     }
288 }
289 
290 /// A translated WebAssembly module, excluding the function bodies and
291 /// memory initializers.
292 #[derive(Debug, Serialize, Deserialize)]
293 pub struct Module {
294     /// This module's index.
295     pub module_index: StaticModuleIndex,
296 
297     /// A pool of strings used in this module.
298     pub strings: StringPool,
299 
300     /// The name of this wasm module, often found in the wasm file.
301     pub name: Option<Atom>,
302 
303     /// All import records, in the order they are declared in the module.
304     pub initializers: TryVec<Initializer>,
305 
306     /// Exported entities.
307     pub exports: TryIndexMap<Atom, EntityIndex>,
308 
309     /// The module "start" function, if present.
310     pub start_func: Option<FuncIndex>,
311 
312     /// WebAssembly table initialization data, per table.
313     pub table_initialization: TableInitialization,
314 
315     /// WebAssembly linear memory initializer.
316     pub memory_initialization: MemoryInitialization,
317 
318     /// WebAssembly passive elements.
319     pub passive_elements: TryVec<TableSegmentElements>,
320 
321     /// The map from passive element index (element segment index space) to index in `passive_elements`.
322     pub passive_elements_map: BTreeMap<ElemIndex, usize>,
323 
324     /// The map from passive data index (data segment index space) to index in `passive_data`.
325     pub passive_data_map: BTreeMap<DataIndex, Range<u32>>,
326 
327     /// Types declared in the wasm module.
328     pub types: TryPrimaryMap<TypeIndex, EngineOrModuleTypeIndex>,
329 
330     /// Number of imported or aliased functions in the module.
331     pub num_imported_funcs: usize,
332 
333     /// Number of imported or aliased tables in the module.
334     pub num_imported_tables: usize,
335 
336     /// Number of imported or aliased memories in the module.
337     pub num_imported_memories: usize,
338 
339     /// Number of imported or aliased globals in the module.
340     pub num_imported_globals: usize,
341 
342     /// Number of imported or aliased tags in the module.
343     pub num_imported_tags: usize,
344 
345     /// Does this module need a GC heap to run?
346     pub needs_gc_heap: bool,
347 
348     /// Number of functions that "escape" from this module may need to have a
349     /// `VMFuncRef` constructed for them.
350     ///
351     /// This is also the number of functions in the `functions` array below with
352     /// an `func_ref` index (and is the maximum func_ref index).
353     pub num_escaped_funcs: usize,
354 
355     /// Types of functions, imported and local.
356     pub functions: TryPrimaryMap<FuncIndex, FunctionType>,
357 
358     /// WebAssembly tables.
359     pub tables: TryPrimaryMap<TableIndex, Table>,
360 
361     /// WebAssembly linear memory plans.
362     pub memories: TryPrimaryMap<MemoryIndex, Memory>,
363 
364     /// WebAssembly global variables.
365     pub globals: TryPrimaryMap<GlobalIndex, Global>,
366 
367     /// WebAssembly global initializers for locally-defined globals.
368     pub global_initializers: TryPrimaryMap<DefinedGlobalIndex, ConstExpr>,
369 
370     /// WebAssembly exception and control tags.
371     pub tags: TryPrimaryMap<TagIndex, Tag>,
372 }
373 
374 /// Initialization routines for creating an instance, encompassing imports,
375 /// modules, instances, aliases, etc.
376 #[derive(Debug, Serialize, Deserialize)]
377 pub enum Initializer {
378     /// An imported item is required to be provided.
379     Import {
380         /// Name of this import
381         name: Atom,
382         /// The field name projection of this import
383         field: Atom,
384         /// Where this import will be placed, which also has type information
385         /// about the import.
386         index: EntityIndex,
387     },
388 }
389 
390 impl Module {
391     /// Allocates the module data structures.
new(module_index: StaticModuleIndex) -> Self392     pub fn new(module_index: StaticModuleIndex) -> Self {
393         Self {
394             module_index,
395             strings: Default::default(),
396             name: Default::default(),
397             initializers: Default::default(),
398             exports: Default::default(),
399             start_func: Default::default(),
400             table_initialization: Default::default(),
401             memory_initialization: Default::default(),
402             passive_elements: Default::default(),
403             passive_elements_map: Default::default(),
404             passive_data_map: Default::default(),
405             types: Default::default(),
406             num_imported_funcs: Default::default(),
407             num_imported_tables: Default::default(),
408             num_imported_memories: Default::default(),
409             num_imported_globals: Default::default(),
410             num_imported_tags: Default::default(),
411             needs_gc_heap: Default::default(),
412             num_escaped_funcs: Default::default(),
413             functions: Default::default(),
414             tables: Default::default(),
415             memories: Default::default(),
416             globals: Default::default(),
417             global_initializers: Default::default(),
418             tags: Default::default(),
419         }
420     }
421 
422     /// Convert a `DefinedFuncIndex` into a `FuncIndex`.
423     #[inline]
func_index(&self, defined_func: DefinedFuncIndex) -> FuncIndex424     pub fn func_index(&self, defined_func: DefinedFuncIndex) -> FuncIndex {
425         FuncIndex::new(self.num_imported_funcs + defined_func.index())
426     }
427 
428     /// Convert a `FuncIndex` into a `DefinedFuncIndex`. Returns None if the
429     /// index is an imported function.
430     #[inline]
defined_func_index(&self, func: FuncIndex) -> Option<DefinedFuncIndex>431     pub fn defined_func_index(&self, func: FuncIndex) -> Option<DefinedFuncIndex> {
432         if func.index() < self.num_imported_funcs {
433             None
434         } else {
435             Some(DefinedFuncIndex::new(
436                 func.index() - self.num_imported_funcs,
437             ))
438         }
439     }
440 
441     /// Test whether the given function index is for an imported function.
442     #[inline]
is_imported_function(&self, index: FuncIndex) -> bool443     pub fn is_imported_function(&self, index: FuncIndex) -> bool {
444         index.index() < self.num_imported_funcs
445     }
446 
447     /// Convert a `DefinedTableIndex` into a `TableIndex`.
448     #[inline]
table_index(&self, defined_table: DefinedTableIndex) -> TableIndex449     pub fn table_index(&self, defined_table: DefinedTableIndex) -> TableIndex {
450         TableIndex::new(self.num_imported_tables + defined_table.index())
451     }
452 
453     /// Convert a `TableIndex` into a `DefinedTableIndex`. Returns None if the
454     /// index is an imported table.
455     #[inline]
defined_table_index(&self, table: TableIndex) -> Option<DefinedTableIndex>456     pub fn defined_table_index(&self, table: TableIndex) -> Option<DefinedTableIndex> {
457         if table.index() < self.num_imported_tables {
458             None
459         } else {
460             Some(DefinedTableIndex::new(
461                 table.index() - self.num_imported_tables,
462             ))
463         }
464     }
465 
466     /// Test whether the given table index is for an imported table.
467     #[inline]
is_imported_table(&self, index: TableIndex) -> bool468     pub fn is_imported_table(&self, index: TableIndex) -> bool {
469         index.index() < self.num_imported_tables
470     }
471 
472     /// Convert a `DefinedMemoryIndex` into a `MemoryIndex`.
473     #[inline]
memory_index(&self, defined_memory: DefinedMemoryIndex) -> MemoryIndex474     pub fn memory_index(&self, defined_memory: DefinedMemoryIndex) -> MemoryIndex {
475         MemoryIndex::new(self.num_imported_memories + defined_memory.index())
476     }
477 
478     /// Convert a `MemoryIndex` into a `DefinedMemoryIndex`. Returns None if the
479     /// index is an imported memory.
480     #[inline]
defined_memory_index(&self, memory: MemoryIndex) -> Option<DefinedMemoryIndex>481     pub fn defined_memory_index(&self, memory: MemoryIndex) -> Option<DefinedMemoryIndex> {
482         if memory.index() < self.num_imported_memories {
483             None
484         } else {
485             Some(DefinedMemoryIndex::new(
486                 memory.index() - self.num_imported_memories,
487             ))
488         }
489     }
490 
491     /// Convert a `DefinedMemoryIndex` into an `OwnedMemoryIndex`. Returns None
492     /// if the index is an imported memory.
493     #[inline]
owned_memory_index(&self, memory: DefinedMemoryIndex) -> OwnedMemoryIndex494     pub fn owned_memory_index(&self, memory: DefinedMemoryIndex) -> OwnedMemoryIndex {
495         assert!(
496             memory.index() < self.memories.len(),
497             "non-shared memory must have an owned index"
498         );
499 
500         // Once we know that the memory index is not greater than the number of
501         // plans, we can iterate through the plans up to the memory index and
502         // count how many are not shared (i.e., owned).
503         let owned_memory_index = self
504             .memories
505             .iter()
506             .skip(self.num_imported_memories)
507             .take(memory.index())
508             .filter(|(_, mp)| !mp.shared)
509             .count();
510         OwnedMemoryIndex::new(owned_memory_index)
511     }
512 
513     /// Test whether the given memory index is for an imported memory.
514     #[inline]
is_imported_memory(&self, index: MemoryIndex) -> bool515     pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
516         index.index() < self.num_imported_memories
517     }
518 
519     /// Convert a `DefinedGlobalIndex` into a `GlobalIndex`.
520     #[inline]
global_index(&self, defined_global: DefinedGlobalIndex) -> GlobalIndex521     pub fn global_index(&self, defined_global: DefinedGlobalIndex) -> GlobalIndex {
522         GlobalIndex::new(self.num_imported_globals + defined_global.index())
523     }
524 
525     /// Convert a `GlobalIndex` into a `DefinedGlobalIndex`. Returns None if the
526     /// index is an imported global.
527     #[inline]
defined_global_index(&self, global: GlobalIndex) -> Option<DefinedGlobalIndex>528     pub fn defined_global_index(&self, global: GlobalIndex) -> Option<DefinedGlobalIndex> {
529         if global.index() < self.num_imported_globals {
530             None
531         } else {
532             Some(DefinedGlobalIndex::new(
533                 global.index() - self.num_imported_globals,
534             ))
535         }
536     }
537 
538     /// Test whether the given global index is for an imported global.
539     #[inline]
is_imported_global(&self, index: GlobalIndex) -> bool540     pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
541         index.index() < self.num_imported_globals
542     }
543 
544     /// Test whether the given tag index is for an imported tag.
545     #[inline]
is_imported_tag(&self, index: TagIndex) -> bool546     pub fn is_imported_tag(&self, index: TagIndex) -> bool {
547         index.index() < self.num_imported_tags
548     }
549 
550     /// Convert a `DefinedTagIndex` into a `TagIndex`.
551     #[inline]
tag_index(&self, defined_tag: DefinedTagIndex) -> TagIndex552     pub fn tag_index(&self, defined_tag: DefinedTagIndex) -> TagIndex {
553         TagIndex::new(self.num_imported_tags + defined_tag.index())
554     }
555 
556     /// Convert a `TagIndex` into a `DefinedTagIndex`. Returns None if the
557     /// index is an imported tag.
558     #[inline]
defined_tag_index(&self, tag: TagIndex) -> Option<DefinedTagIndex>559     pub fn defined_tag_index(&self, tag: TagIndex) -> Option<DefinedTagIndex> {
560         if tag.index() < self.num_imported_tags {
561             None
562         } else {
563             Some(DefinedTagIndex::new(tag.index() - self.num_imported_tags))
564         }
565     }
566 
567     /// Returns an iterator of all the imports in this module, along with their
568     /// module name, field name, and type that's being imported.
imports(&self) -> impl ExactSizeIterator<Item = (&str, &str, EntityType)>569     pub fn imports(&self) -> impl ExactSizeIterator<Item = (&str, &str, EntityType)> {
570         let pool = &self.strings;
571         self.initializers.iter().map(move |i| match i {
572             Initializer::Import { name, field, index } => {
573                 (&pool[name], &pool[field], self.type_of(*index))
574             }
575         })
576     }
577 
578     /// Get this module's `i`th import.
import(&self, i: usize) -> Option<(&str, &str, EntityType)>579     pub fn import(&self, i: usize) -> Option<(&str, &str, EntityType)> {
580         match self.initializers.get(i)? {
581             Initializer::Import { name, field, index } => Some((
582                 &self.strings[name],
583                 &self.strings[field],
584                 self.type_of(*index),
585             )),
586         }
587     }
588 
589     /// Returns the type of an item based on its index
type_of(&self, index: EntityIndex) -> EntityType590     pub fn type_of(&self, index: EntityIndex) -> EntityType {
591         match index {
592             EntityIndex::Global(i) => EntityType::Global(self.globals[i]),
593             EntityIndex::Table(i) => EntityType::Table(self.tables[i]),
594             EntityIndex::Memory(i) => EntityType::Memory(self.memories[i]),
595             EntityIndex::Function(i) => EntityType::Function(self.functions[i].signature),
596             EntityIndex::Tag(i) => EntityType::Tag(self.tags[i]),
597         }
598     }
599 
600     /// Appends a new tag to this module with the given type information.
push_tag( &mut self, signature: impl Into<EngineOrModuleTypeIndex>, exception: impl Into<EngineOrModuleTypeIndex>, ) -> TagIndex601     pub fn push_tag(
602         &mut self,
603         signature: impl Into<EngineOrModuleTypeIndex>,
604         exception: impl Into<EngineOrModuleTypeIndex>,
605     ) -> TagIndex {
606         let signature = signature.into();
607         let exception = exception.into();
608         self.tags
609             .push(Tag {
610                 signature,
611                 exception,
612             })
613             .panic_on_oom()
614     }
615 
616     /// Appends a new function to this module with the given type information,
617     /// used for functions that either don't escape or aren't certain whether
618     /// they escape yet.
push_function(&mut self, signature: impl Into<EngineOrModuleTypeIndex>) -> FuncIndex619     pub fn push_function(&mut self, signature: impl Into<EngineOrModuleTypeIndex>) -> FuncIndex {
620         let signature = signature.into();
621         self.functions
622             .push(FunctionType {
623                 signature,
624                 func_ref: FuncRefIndex::reserved_value(),
625             })
626             .panic_on_oom()
627     }
628 
629     /// Returns an iterator over all of the defined function indices in this
630     /// module.
defined_func_indices(&self) -> impl ExactSizeIterator<Item = DefinedFuncIndex> + use<>631     pub fn defined_func_indices(&self) -> impl ExactSizeIterator<Item = DefinedFuncIndex> + use<> {
632         (0..self.functions.len() - self.num_imported_funcs).map(|i| DefinedFuncIndex::new(i))
633     }
634 
635     /// Returns the number of functions defined by this module itself: all
636     /// functions minus imported functions.
num_defined_funcs(&self) -> usize637     pub fn num_defined_funcs(&self) -> usize {
638         self.functions.len() - self.num_imported_funcs
639     }
640 
641     /// Returns the number of tables defined by this module itself: all tables
642     /// minus imported tables.
num_defined_tables(&self) -> usize643     pub fn num_defined_tables(&self) -> usize {
644         self.tables.len() - self.num_imported_tables
645     }
646 
647     /// Returns the number of memories defined by this module itself: all
648     /// memories minus imported memories.
num_defined_memories(&self) -> usize649     pub fn num_defined_memories(&self) -> usize {
650         self.memories.len() - self.num_imported_memories
651     }
652 
653     /// Returns the number of globals defined by this module itself: all
654     /// globals minus imported globals.
num_defined_globals(&self) -> usize655     pub fn num_defined_globals(&self) -> usize {
656         self.globals.len() - self.num_imported_globals
657     }
658 
659     /// Returns the number of tags defined by this module itself: all tags
660     /// minus imported tags.
num_defined_tags(&self) -> usize661     pub fn num_defined_tags(&self) -> usize {
662         self.tags.len() - self.num_imported_tags
663     }
664 
665     /// Tests whether `index` is valid for this module.
is_valid(&self, index: EntityIndex) -> bool666     pub fn is_valid(&self, index: EntityIndex) -> bool {
667         match index {
668             EntityIndex::Function(i) => self.functions.is_valid(i),
669             EntityIndex::Table(i) => self.tables.is_valid(i),
670             EntityIndex::Memory(i) => self.memories.is_valid(i),
671             EntityIndex::Global(i) => self.globals.is_valid(i),
672             EntityIndex::Tag(i) => self.tags.is_valid(i),
673         }
674     }
675 }
676 
677 impl TypeTrace for Module {
trace<F, E>(&self, func: &mut F) -> Result<(), E> where F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,678     fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
679     where
680         F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
681     {
682         // NB: Do not `..` elide unmodified fields so that we get compile errors
683         // when adding new fields that might need re-canonicalization.
684         let Self {
685             module_index: _,
686             strings: _,
687             name: _,
688             initializers: _,
689             exports: _,
690             start_func: _,
691             table_initialization: _,
692             memory_initialization: _,
693             passive_elements: _,
694             passive_elements_map: _,
695             passive_data_map: _,
696             types,
697             num_imported_funcs: _,
698             num_imported_tables: _,
699             num_imported_memories: _,
700             num_imported_globals: _,
701             num_imported_tags: _,
702             num_escaped_funcs: _,
703             needs_gc_heap: _,
704             functions,
705             tables,
706             memories: _,
707             globals,
708             global_initializers: _,
709             tags,
710         } = self;
711 
712         for t in types.values().copied() {
713             func(t)?;
714         }
715         for f in functions.values() {
716             f.trace(func)?;
717         }
718         for t in tables.values() {
719             t.trace(func)?;
720         }
721         for g in globals.values() {
722             g.trace(func)?;
723         }
724         for t in tags.values() {
725             t.trace(func)?;
726         }
727         Ok(())
728     }
729 
trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E> where F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,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             start_func: _,
743             table_initialization: _,
744             memory_initialization: _,
745             passive_elements: _,
746             passive_elements_map: _,
747             passive_data_map: _,
748             types,
749             num_imported_funcs: _,
750             num_imported_tables: _,
751             num_imported_memories: _,
752             num_imported_globals: _,
753             num_imported_tags: _,
754             num_escaped_funcs: _,
755             needs_gc_heap: _,
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         Ok(())
780     }
781 }
782 
783 /// Type information about functions in a wasm module.
784 #[derive(Debug, Serialize, Deserialize)]
785 pub struct FunctionType {
786     /// The type of this function, indexed into the module-wide type tables for
787     /// a module compilation.
788     pub signature: EngineOrModuleTypeIndex,
789     /// The index into the funcref table, if present. Note that this is
790     /// `reserved_value()` if the function does not escape from a module.
791     pub func_ref: FuncRefIndex,
792 }
793 
794 impl TypeTrace for FunctionType {
trace<F, E>(&self, func: &mut F) -> Result<(), E> where F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,795     fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
796     where
797         F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
798     {
799         func(self.signature)
800     }
801 
trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E> where F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,802     fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
803     where
804         F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
805     {
806         func(&mut self.signature)
807     }
808 }
809 
810 impl FunctionType {
811     /// Returns whether this function's type is one that "escapes" the current
812     /// module, meaning that the function is exported, used in `ref.func`, used
813     /// in a table, etc.
is_escaping(&self) -> bool814     pub fn is_escaping(&self) -> bool {
815         !self.func_ref.is_reserved_value()
816     }
817 }
818 
819 /// Index into the funcref table within a VMContext for a function.
820 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
821 pub struct FuncRefIndex(u32);
822 cranelift_entity::entity_impl!(FuncRefIndex);
823