wasmer_runtime_core_fl/
module.rs

1//! This module contains the types to manipulate and access Wasm modules.
2//!
3//! A Wasm module is the artifact of compiling WebAssembly. Wasm modules are not executable
4//! until they're instantiated with imports (via [`ImportObject`]).
5use crate::{
6    backend::RunnableModule,
7    cache::{Artifact, Error as CacheError},
8    error,
9    import::ImportObject,
10    structures::{Map, TypedIndex},
11    types::{
12        ExportDescriptor, FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit,
13        ImportDescriptor, ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex,
14        ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex,
15        MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor, TableIndex,
16    },
17    Instance,
18};
19
20use crate::backend::CacheGen;
21#[cfg(feature = "generate-debug-information")]
22use crate::jit_debug;
23use indexmap::IndexMap;
24use std::collections::HashMap;
25use std::sync::Arc;
26
27/// This is used to instantiate a new WebAssembly module.
28#[doc(hidden)]
29pub struct ModuleInner {
30    pub runnable_module: Arc<Box<dyn RunnableModule>>,
31    pub cache_gen: Box<dyn CacheGen>,
32    pub info: ModuleInfo,
33}
34
35/// Container for module data including memories, globals, tables, imports, and exports.
36#[derive(Clone, Debug, Serialize, Deserialize)]
37pub struct ModuleInfo {
38    /// Map of memory index to memory descriptors.
39    // This are strictly local and the typesystem ensures that.
40    pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
41    /// Map of global index to global descriptors.
42    pub globals: Map<LocalGlobalIndex, GlobalInit>,
43    /// Map of table index to table descriptors.
44    pub tables: Map<LocalTableIndex, TableDescriptor>,
45
46    /// Map of imported function index to import name.
47    // These are strictly imported and the typesystem ensures that.
48    pub imported_functions: Map<ImportedFuncIndex, ImportName>,
49    /// Map of imported memory index to import name and memory descriptor.
50    pub imported_memories: Map<ImportedMemoryIndex, (ImportName, MemoryDescriptor)>,
51    /// Map of imported table index to import name and table descriptor.
52    pub imported_tables: Map<ImportedTableIndex, (ImportName, TableDescriptor)>,
53    /// Map of imported global index to import name and global descriptor.
54    pub imported_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDescriptor)>,
55
56    /// Map of string to export index.
57    // Implementation note: this should maintain the order that the exports appear in the
58    // Wasm module.  Be careful not to use APIs that may break the order!
59    // Side note, because this is public we can't actually guarantee that it will remain
60    // in order.
61    pub exports: IndexMap<String, ExportIndex>,
62
63    /// Vector of data initializers.
64    pub data_initializers: Vec<DataInitializer>,
65    /// Vector of table initializers.
66    pub elem_initializers: Vec<TableInitializer>,
67
68    /// Index of optional start function.
69    pub start_func: Option<FuncIndex>,
70
71    /// Map function index to signature index.
72    pub func_assoc: Map<FuncIndex, SigIndex>,
73    /// Map signature index to function signature.
74    pub signatures: Map<SigIndex, FuncSig>,
75    /// Backend.
76    pub backend: String,
77
78    /// Table of namespace indexes.
79    pub namespace_table: StringTable<NamespaceIndex>,
80    /// Table of name indexes.
81    pub name_table: StringTable<NameIndex>,
82
83    /// Symbol information from emscripten.
84    pub em_symbol_map: Option<HashMap<u32, String>>,
85
86    /// Custom sections.
87    pub custom_sections: HashMap<String, Vec<Vec<u8>>>,
88
89    /// Flag controlling whether or not debug information for use in a debugger
90    /// will be generated.
91    pub generate_debug_info: bool,
92
93    #[cfg(feature = "generate-debug-information")]
94    #[serde(skip)]
95    /// Resource manager of debug information being used by a debugger.
96    pub(crate) debug_info_manager: jit_debug::JitCodeDebugInfoManager,
97}
98
99impl ModuleInfo {
100    /// Creates custom section info from the given wasm file.
101    pub fn import_custom_sections(&mut self, wasm: &[u8]) -> crate::error::ParseResult<()> {
102        let mut parser = wasmparser::ModuleReader::new(wasm)?;
103        while !parser.eof() {
104            let section = parser.read()?;
105            if let wasmparser::SectionCode::Custom { name, kind: _ } = section.code {
106                let mut reader = section.get_binary_reader();
107                let len = reader.bytes_remaining();
108                let bytes = reader.read_bytes(len)?;
109                let data = bytes.to_vec();
110                let name = name.to_string();
111                let entry: &mut Vec<Vec<u8>> = self.custom_sections.entry(name).or_default();
112                entry.push(data);
113            }
114        }
115        Ok(())
116    }
117}
118
119/// A compiled WebAssembly module.
120///
121/// `Module` is returned by the [`compile_with`][] function.
122///
123/// [`compile_with`]: crate::compile_with
124pub struct Module {
125    inner: Arc<ModuleInner>,
126}
127
128impl Module {
129    pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
130        Module { inner }
131    }
132
133    /// Instantiate a WebAssembly module with the provided [`ImportObject`].
134    ///
135    /// [`ImportObject`]: struct.ImportObject.html
136    ///
137    /// # Note:
138    /// Instantiating a `Module` will also call the function designated as `start`
139    /// in the WebAssembly module, if there is one.
140    ///
141    /// # Usage:
142    /// ```
143    /// # use wasmer_runtime_core::error::Result;
144    /// # use wasmer_runtime_core::Module;
145    /// # use wasmer_runtime_core::imports;
146    /// # fn instantiate(module: &Module) -> Result<()> {
147    /// let import_object = imports! {
148    ///     // ...
149    /// };
150    /// let instance = module.instantiate(&import_object)?;
151    /// // ...
152    /// # Ok(())
153    /// # }
154    /// ```
155    pub fn instantiate(&self, import_object: &ImportObject) -> error::Result<Instance> {
156        Instance::new(Arc::clone(&self.inner), import_object)
157    }
158
159    /// Create a cache artifact from this module.
160    pub fn cache(&self) -> Result<Artifact, CacheError> {
161        let (backend_metadata, code) = self.inner.cache_gen.generate_cache()?;
162        Ok(Artifact::from_parts(
163            Box::new(self.inner.info.clone()),
164            backend_metadata,
165            code,
166        ))
167    }
168
169    /// Get the module data for this module.
170    pub fn info(&self) -> &ModuleInfo {
171        &self.inner.info
172    }
173
174    /// Get the [`ExportDescriptor`]s of the exports this [`Module`] provides.
175    pub fn exports(&self) -> Vec<ExportDescriptor> {
176        self.inner.exports()
177    }
178
179    /// Get the [`ImportDescriptor`]s describing the imports this [`Module`]
180    /// requires to be instantiated.
181    pub fn imports(&self) -> Vec<ImportDescriptor> {
182        let mut out = Vec::with_capacity(
183            self.inner.info.imported_functions.len()
184                + self.inner.info.imported_memories.len()
185                + self.inner.info.imported_tables.len()
186                + self.inner.info.imported_globals.len(),
187        );
188
189        /// Lookup the (namespace, name) in the [`ModuleInfo`] by index.
190        fn get_import_name(
191            info: &ModuleInfo,
192            &ImportName {
193                namespace_index,
194                name_index,
195            }: &ImportName,
196        ) -> (String, String) {
197            let namespace = info.namespace_table.get(namespace_index).to_string();
198            let name = info.name_table.get(name_index).to_string();
199
200            (namespace, name)
201        }
202
203        let info = &self.inner.info;
204
205        let imported_functions = info.imported_functions.iter().map(|(idx, import_name)| {
206            let (namespace, name) = get_import_name(info, import_name);
207            let sig = info
208                .signatures
209                .get(*info.func_assoc.get(FuncIndex::new(idx.index())).unwrap())
210                .unwrap();
211            ImportDescriptor {
212                namespace,
213                name,
214                ty: sig.into(),
215            }
216        });
217        let imported_memories =
218            info.imported_memories
219                .values()
220                .map(|(import_name, memory_descriptor)| {
221                    let (namespace, name) = get_import_name(info, import_name);
222                    ImportDescriptor {
223                        namespace,
224                        name,
225                        ty: memory_descriptor.into(),
226                    }
227                });
228        let imported_tables =
229            info.imported_tables
230                .values()
231                .map(|(import_name, table_descriptor)| {
232                    let (namespace, name) = get_import_name(info, import_name);
233                    ImportDescriptor {
234                        namespace,
235                        name,
236                        ty: table_descriptor.into(),
237                    }
238                });
239        let imported_globals =
240            info.imported_globals
241                .values()
242                .map(|(import_name, global_descriptor)| {
243                    let (namespace, name) = get_import_name(info, import_name);
244                    ImportDescriptor {
245                        namespace,
246                        name,
247                        ty: global_descriptor.into(),
248                    }
249                });
250
251        out.extend(imported_functions);
252        out.extend(imported_memories);
253        out.extend(imported_tables);
254        out.extend(imported_globals);
255        out
256    }
257
258    /// Get the custom sections matching the given name.
259    pub fn custom_sections(&self, key: impl AsRef<str>) -> Option<&[Vec<u8>]> {
260        let key = key.as_ref();
261        self.inner.info.custom_sections.get(key).map(|v| v.as_ref())
262    }
263}
264
265impl Clone for Module {
266    fn clone(&self) -> Self {
267        Self {
268            inner: Arc::clone(&self.inner),
269        }
270    }
271}
272
273impl ModuleInner {
274    /// Iterate over the [`ExportDescriptor`]s of the exports that this module provides.
275    pub(crate) fn exports_iter(&self) -> impl Iterator<Item = ExportDescriptor> + '_ {
276        self.info
277            .exports
278            .iter()
279            .map(move |(name, &ei)| ExportDescriptor {
280                name,
281                ty: match ei {
282                    ExportIndex::Func(f_idx) => {
283                        let sig_idx = self.info.func_assoc[f_idx].into();
284                        self.info.signatures[sig_idx].clone().into()
285                    }
286                    ExportIndex::Global(g_idx) => {
287                        let info = &self.info;
288                        let local_global_idx =
289                            LocalGlobalIndex::new(g_idx.index() - info.imported_globals.len());
290                        info.globals[local_global_idx].desc.into()
291                    }
292                    ExportIndex::Memory(m_idx) => {
293                        let info = &self.info;
294                        let local_memory_idx =
295                            LocalMemoryIndex::new(m_idx.index() - info.imported_memories.len());
296                        info.memories[local_memory_idx].into()
297                    }
298                    ExportIndex::Table(t_idx) => {
299                        let info = &self.info;
300                        let local_table_idx =
301                            LocalTableIndex::new(t_idx.index() - info.imported_tables.len());
302                        info.tables[local_table_idx].into()
303                    }
304                },
305            })
306    }
307
308    /// Get the [`ExportDescriptor`]s of the exports this [`Module`] provides.
309    pub fn exports(&self) -> Vec<ExportDescriptor> {
310        self.exports_iter().collect()
311    }
312}
313
314#[doc(hidden)]
315#[derive(Serialize, Deserialize, Debug, Clone)]
316pub struct ImportName {
317    pub namespace_index: NamespaceIndex,
318    pub name_index: NameIndex,
319}
320
321/// A wrapper around the [`TypedIndex`]es for Wasm functions, Wasm memories,
322/// Wasm globals, and Wasm tables.
323///
324/// Used in [`ModuleInfo`] to access function signatures ([`SigIndex`]s,
325/// [`FuncSig`]), [`GlobalInit`]s, [`MemoryDescriptor`]s, and
326/// [`TableDescriptor`]s.
327#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
328pub enum ExportIndex {
329    /// Function export index. [`FuncIndex`] is a type-safe handle referring to
330    /// a Wasm function.
331    Func(FuncIndex),
332    /// Memory export index. [`MemoryIndex`] is a type-safe handle referring to
333    /// a Wasm memory.
334    Memory(MemoryIndex),
335    /// Global export index. [`GlobalIndex`] is a type-safe handle referring to
336    /// a Wasm global.
337    Global(GlobalIndex),
338    /// Table export index. [`TableIndex`] is a type-safe handle referring to
339    /// to a Wasm table.
340    Table(TableIndex),
341}
342
343/// A data initializer for linear memory.
344#[derive(Serialize, Deserialize, Debug, Clone)]
345pub struct DataInitializer {
346    /// The index of the memory to initialize.
347    pub memory_index: MemoryIndex,
348    /// Either a constant offset or a `get_global`
349    pub base: Initializer,
350    /// The initialization data.
351    #[cfg_attr(feature = "cache", serde(with = "serde_bytes"))]
352    pub data: Vec<u8>,
353}
354
355/// A WebAssembly table initializer.
356#[derive(Serialize, Deserialize, Debug, Clone)]
357pub struct TableInitializer {
358    /// The index of a table to initialize.
359    pub table_index: TableIndex,
360    /// Either a constant offset or a `get_global`
361    pub base: Initializer,
362    /// The values to write into the table elements.
363    pub elements: Vec<FuncIndex>,
364}
365
366/// String table builder.
367pub struct StringTableBuilder<K: TypedIndex> {
368    map: IndexMap<String, (K, u32, u32)>,
369    buffer: String,
370    count: u32,
371}
372
373impl<K: TypedIndex> StringTableBuilder<K> {
374    /// Creates a new [`StringTableBuilder`].
375    pub fn new() -> Self {
376        Self {
377            map: IndexMap::new(),
378            buffer: String::new(),
379            count: 0,
380        }
381    }
382
383    /// Register a new string into table.
384    pub fn register<S>(&mut self, s: S) -> K
385    where
386        S: Into<String> + AsRef<str>,
387    {
388        let s_str = s.as_ref();
389
390        if self.map.contains_key(s_str) {
391            self.map[s_str].0
392        } else {
393            let offset = self.buffer.len();
394            let length = s_str.len();
395            let index = TypedIndex::new(self.count as _);
396
397            self.buffer.push_str(s_str);
398            self.map
399                .insert(s.into(), (index, offset as u32, length as u32));
400            self.count += 1;
401
402            index
403        }
404    }
405
406    /// Finish building the [`StringTable`].
407    pub fn finish(self) -> StringTable<K> {
408        let table = self
409            .map
410            .values()
411            .map(|(_, offset, length)| (*offset, *length))
412            .collect();
413
414        StringTable {
415            table,
416            buffer: self.buffer,
417        }
418    }
419}
420
421/// A map of index to string.
422#[derive(Serialize, Deserialize, Debug, Clone)]
423pub struct StringTable<K: TypedIndex> {
424    table: Map<K, (u32, u32)>,
425    buffer: String,
426}
427
428impl<K: TypedIndex> StringTable<K> {
429    /// Creates a `StringTable`.
430    pub fn new() -> Self {
431        Self {
432            table: Map::new(),
433            buffer: String::new(),
434        }
435    }
436
437    /// Gets a reference to a string at the given index.
438    pub fn get(&self, index: K) -> &str {
439        let (offset, length) = self.table[index];
440        let offset = offset as usize;
441        let length = length as usize;
442
443        &self.buffer[offset..offset + length]
444    }
445}
446
447/// A type-safe handle referring to a module namespace.
448#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
449pub struct NamespaceIndex(u32);
450
451impl TypedIndex for NamespaceIndex {
452    #[doc(hidden)]
453    fn new(index: usize) -> Self {
454        NamespaceIndex(index as _)
455    }
456
457    #[doc(hidden)]
458    fn index(&self) -> usize {
459        self.0 as usize
460    }
461}
462
463/// A type-safe handle referring to a name in a module namespace.
464#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
465pub struct NameIndex(u32);
466
467impl TypedIndex for NameIndex {
468    #[doc(hidden)]
469    fn new(index: usize) -> Self {
470        NameIndex(index as _)
471    }
472
473    #[doc(hidden)]
474    fn index(&self) -> usize {
475        self.0 as usize
476    }
477}