substrate_wasmtime/
module.rs

1use crate::frame_info::GlobalFrameInfoRegistration;
2use crate::runtime::Engine;
3use crate::types::{EntityType, ExportType, ExternType, ImportType};
4use anyhow::Result;
5use std::path::Path;
6use std::sync::{Arc, Mutex};
7use wasmtime_jit::CompiledModule;
8
9/// A compiled WebAssembly module, ready to be instantiated.
10///
11/// A `Module` is a compiled in-memory representation of an input WebAssembly
12/// binary. A `Module` is then used to create an [`Instance`](crate::Instance)
13/// through an instantiation process. You cannot call functions or fetch
14/// globals, for example, on a `Module` because it's purely a code
15/// representation. Instead you'll need to create an
16/// [`Instance`](crate::Instance) to interact with the wasm module.
17///
18/// Creating a `Module` currently involves compiling code, meaning that it can
19/// be an expensive operation. All `Module` instances are compiled according to
20/// the configuration in [`Config`], but typically they're JIT-compiled. If
21/// you'd like to instantiate a module multiple times you can do so with
22/// compiling the original wasm module only once with a single [`Module`]
23/// instance.
24///
25/// The `Module` is threadsafe and safe to share accross threads.
26///
27/// ## Modules and `Clone`
28///
29/// Using `clone` on a `Module` is a cheap operation. It will not create an
30/// entirely new module, but rather just a new reference to the existing module.
31/// In other words it's a shallow copy, not a deep copy.
32///
33/// ## Examples
34///
35/// There are a number of ways you can create a `Module`, for example pulling
36/// the bytes from a number of locations. One example is loading a module from
37/// the filesystem:
38///
39/// ```no_run
40/// # use wasmtime::*;
41/// # fn main() -> anyhow::Result<()> {
42/// let engine = Engine::default();
43/// let module = Module::from_file(&engine, "path/to/foo.wasm")?;
44/// # Ok(())
45/// # }
46/// ```
47///
48/// You can also load the wasm text format if more convenient too:
49///
50/// ```no_run
51/// # use wasmtime::*;
52/// # fn main() -> anyhow::Result<()> {
53/// let engine = Engine::default();
54/// // Now we're using the WebAssembly text extension: `.wat`!
55/// let module = Module::from_file(&engine, "path/to/foo.wat")?;
56/// # Ok(())
57/// # }
58/// ```
59///
60/// And if you've already got the bytes in-memory you can use the
61/// [`Module::new`] constructor:
62///
63/// ```no_run
64/// # use wasmtime::*;
65/// # fn main() -> anyhow::Result<()> {
66/// let engine = Engine::default();
67/// # let wasm_bytes: Vec<u8> = Vec::new();
68/// let module = Module::new(&engine, &wasm_bytes)?;
69///
70/// // It also works with the text format!
71/// let module = Module::new(&engine, "(module (func))")?;
72/// # Ok(())
73/// # }
74/// ```
75///
76/// [`Config`]: crate::Config
77#[derive(Clone)]
78pub struct Module {
79    engine: Engine,
80    compiled: Arc<CompiledModule>,
81    frame_info_registration: Arc<Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>>,
82}
83
84impl Module {
85    /// Creates a new WebAssembly `Module` from the given in-memory `bytes`.
86    ///
87    /// The `bytes` provided must be in one of two formats:
88    ///
89    /// * It can be a [binary-encoded][binary] WebAssembly module. This
90    ///   is always supported.
91    /// * It may also be a [text-encoded][text] instance of the WebAssembly
92    ///   text format. This is only supported when the `wat` feature of this
93    ///   crate is enabled. If this is supplied then the text format will be
94    ///   parsed before validation. Note that the `wat` feature is enabled by
95    ///   default.
96    ///
97    /// The data for the wasm module must be loaded in-memory if it's present
98    /// elsewhere, for example on disk. This requires that the entire binary is
99    /// loaded into memory all at once, this API does not support streaming
100    /// compilation of a module.
101    ///
102    /// The WebAssembly binary will be decoded and validated. It will also be
103    /// compiled according to the configuration of the provided `engine`.
104    ///
105    /// # Errors
106    ///
107    /// This function may fail and return an error. Errors may include
108    /// situations such as:
109    ///
110    /// * The binary provided could not be decoded because it's not a valid
111    ///   WebAssembly binary
112    /// * The WebAssembly binary may not validate (e.g. contains type errors)
113    /// * Implementation-specific limits were exceeded with a valid binary (for
114    ///   example too many locals)
115    /// * The wasm binary may use features that are not enabled in the
116    ///   configuration of `enging`
117    /// * If the `wat` feature is enabled and the input is text, then it may be
118    ///   rejected if it fails to parse.
119    ///
120    /// The error returned should contain full information about why module
121    /// creation failed if one is returned.
122    ///
123    /// [binary]: https://webassembly.github.io/spec/core/binary/index.html
124    /// [text]: https://webassembly.github.io/spec/core/text/index.html
125    ///
126    /// # Examples
127    ///
128    /// The `new` function can be invoked with a in-memory array of bytes:
129    ///
130    /// ```no_run
131    /// # use wasmtime::*;
132    /// # fn main() -> anyhow::Result<()> {
133    /// # let engine = Engine::default();
134    /// # let wasm_bytes: Vec<u8> = Vec::new();
135    /// let module = Module::new(&engine, &wasm_bytes)?;
136    /// # Ok(())
137    /// # }
138    /// ```
139    ///
140    /// Or you can also pass in a string to be parsed as the wasm text
141    /// format:
142    ///
143    /// ```
144    /// # use wasmtime::*;
145    /// # fn main() -> anyhow::Result<()> {
146    /// # let engine = Engine::default();
147    /// let module = Module::new(&engine, "(module (func))")?;
148    /// # Ok(())
149    /// # }
150    /// ```
151    pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
152        #[cfg(feature = "wat")]
153        let bytes = wat::parse_bytes(bytes.as_ref())?;
154        Module::from_binary(engine, bytes.as_ref())
155    }
156
157    /// Creates a new WebAssembly `Module` from the given in-memory `binary`
158    /// data. The provided `name` will be used in traps/backtrace details.
159    ///
160    /// See [`Module::new`] for other details.
161    pub fn new_with_name(engine: &Engine, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
162        let mut module = Module::new(engine, bytes.as_ref())?;
163        Arc::get_mut(&mut module.compiled)
164            .unwrap()
165            .module_mut()
166            .expect("mutable module")
167            .name = Some(name.to_string());
168        Ok(module)
169    }
170
171    /// Creates a new WebAssembly `Module` from the contents of the given
172    /// `file` on disk.
173    ///
174    /// This is a convenience function that will read the `file` provided and
175    /// pass the bytes to the [`Module::new`] function. For more information
176    /// see [`Module::new`]
177    ///
178    /// # Examples
179    ///
180    /// ```no_run
181    /// # use wasmtime::*;
182    /// # fn main() -> anyhow::Result<()> {
183    /// let engine = Engine::default();
184    /// let module = Module::from_file(&engine, "./path/to/foo.wasm")?;
185    /// # Ok(())
186    /// # }
187    /// ```
188    ///
189    /// The `.wat` text format is also supported:
190    ///
191    /// ```no_run
192    /// # use wasmtime::*;
193    /// # fn main() -> anyhow::Result<()> {
194    /// # let engine = Engine::default();
195    /// let module = Module::from_file(&engine, "./path/to/foo.wat")?;
196    /// # Ok(())
197    /// # }
198    /// ```
199    pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
200        #[cfg(feature = "wat")]
201        let wasm = wat::parse_file(file)?;
202        #[cfg(not(feature = "wat"))]
203        let wasm = std::fs::read(file)?;
204        Module::new(engine, &wasm)
205    }
206
207    /// Creates a new WebAssembly `Module` from the given in-memory `binary`
208    /// data.
209    ///
210    /// This is similar to [`Module::new`] except that it requires that the
211    /// `binary` input is a WebAssembly binary, the text format is not supported
212    /// by this function. It's generally recommended to use [`Module::new`],
213    /// but if it's required to not support the text format this function can be
214    /// used instead.
215    ///
216    /// # Examples
217    ///
218    /// ```
219    /// # use wasmtime::*;
220    /// # fn main() -> anyhow::Result<()> {
221    /// # let engine = Engine::default();
222    /// let wasm = b"\0asm\x01\0\0\0";
223    /// let module = Module::from_binary(&engine, wasm)?;
224    /// # Ok(())
225    /// # }
226    /// ```
227    ///
228    /// Note that the text format is **not** accepted by this function:
229    ///
230    /// ```
231    /// # use wasmtime::*;
232    /// # fn main() -> anyhow::Result<()> {
233    /// # let engine = Engine::default();
234    /// assert!(Module::from_binary(&engine, b"(module)").is_err());
235    /// # Ok(())
236    /// # }
237    /// ```
238    pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
239        Module::validate(engine, binary)?;
240        // Note that the call to `from_binary_unchecked` here should be ok
241        // because we previously validated the binary, meaning we're guaranteed
242        // to pass a valid binary for `engine`.
243        unsafe { Module::from_binary_unchecked(engine, binary) }
244    }
245
246    /// Creates a new WebAssembly `Module` from the given in-memory `binary`
247    /// data, skipping validation and asserting that `binary` is a valid
248    /// WebAssembly module.
249    ///
250    /// This function is the same as [`Module::new`] except that it skips the
251    /// call to [`Module::validate`] and it does not support the text format of
252    /// WebAssembly. The WebAssembly binary is not validated for
253    /// correctness and it is simply assumed as valid.
254    ///
255    /// For more information about creation of a module and the `engine` argument
256    /// see the documentation of [`Module::new`].
257    ///
258    /// # Unsafety
259    ///
260    /// This function is `unsafe` due to the unchecked assumption that the input
261    /// `binary` is valid. If the `binary` is not actually a valid wasm binary it
262    /// may cause invalid machine code to get generated, cause panics, etc.
263    ///
264    /// It is only safe to call this method if [`Module::validate`] succeeds on
265    /// the same arguments passed to this function.
266    ///
267    /// # Errors
268    ///
269    /// This function may fail for many of the same reasons as [`Module::new`].
270    /// While this assumes that the binary is valid it still needs to actually
271    /// be somewhat valid for decoding purposes, and the basics of decoding can
272    /// still fail.
273    pub unsafe fn from_binary_unchecked(engine: &Engine, binary: &[u8]) -> Result<Module> {
274        Module::compile(engine, binary)
275    }
276
277    /// Validates `binary` input data as a WebAssembly binary given the
278    /// configuration in `engine`.
279    ///
280    /// This function will perform a speedy validation of the `binary` input
281    /// WebAssembly module (which is in [binary form][binary], the text format
282    /// is not accepted by this function) and return either `Ok` or `Err`
283    /// depending on the results of validation. The `engine` argument indicates
284    /// configuration for WebAssembly features, for example, which are used to
285    /// indicate what should be valid and what shouldn't be.
286    ///
287    /// Validation automatically happens as part of [`Module::new`], but is a
288    /// requirement for [`Module::from_binary_unchecked`] to be safe.
289    ///
290    /// # Errors
291    ///
292    /// If validation fails for any reason (type check error, usage of a feature
293    /// that wasn't enabled, etc) then an error with a description of the
294    /// validation issue will be returned.
295    ///
296    /// [binary]: https://webassembly.github.io/spec/core/binary/index.html
297    pub fn validate(engine: &Engine, binary: &[u8]) -> Result<()> {
298        engine.config().validator().validate_all(binary)?;
299        Ok(())
300    }
301
302    unsafe fn compile(engine: &Engine, binary: &[u8]) -> Result<Self> {
303        let compiled = CompiledModule::new(engine.compiler(), binary, &*engine.config().profiler)?;
304
305        Ok(Module {
306            engine: engine.clone(),
307            compiled: Arc::new(compiled),
308            frame_info_registration: Arc::new(Mutex::new(None)),
309        })
310    }
311
312    pub(crate) fn compiled_module(&self) -> &CompiledModule {
313        &self.compiled
314    }
315
316    /// Returns identifier/name that this [`Module`] has. This name
317    /// is used in traps/backtrace details.
318    ///
319    /// Note that most LLVM/clang/Rust-produced modules do not have a name
320    /// associated with them, but other wasm tooling can be used to inject or
321    /// add a name.
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// # use wasmtime::*;
327    /// # fn main() -> anyhow::Result<()> {
328    /// # let engine = Engine::default();
329    /// let module = Module::new(&engine, "(module $foo)")?;
330    /// assert_eq!(module.name(), Some("foo"));
331    ///
332    /// let module = Module::new(&engine, "(module)")?;
333    /// assert_eq!(module.name(), None);
334    ///
335    /// let module = Module::new_with_name(&engine, "(module)", "bar")?;
336    /// assert_eq!(module.name(), Some("bar"));
337    /// # Ok(())
338    /// # }
339    /// ```
340    pub fn name(&self) -> Option<&str> {
341        self.compiled.module().name.as_deref()
342    }
343
344    /// Returns the list of imports that this [`Module`] has and must be
345    /// satisfied.
346    ///
347    /// This function returns the list of imports that the wasm module has, but
348    /// only the types of each import. The type of each import is used to
349    /// typecheck the [`Instance::new`](crate::Instance::new) method's `imports`
350    /// argument. The arguments to that function must match up 1-to-1 with the
351    /// entries in the array returned here.
352    ///
353    /// The imports returned reflect the order of the imports in the wasm module
354    /// itself, and note that no form of deduplication happens.
355    ///
356    /// # Examples
357    ///
358    /// Modules with no imports return an empty list here:
359    ///
360    /// ```
361    /// # use wasmtime::*;
362    /// # fn main() -> anyhow::Result<()> {
363    /// # let engine = Engine::default();
364    /// let module = Module::new(&engine, "(module)")?;
365    /// assert_eq!(module.imports().len(), 0);
366    /// # Ok(())
367    /// # }
368    /// ```
369    ///
370    /// and modules with imports will have a non-empty list:
371    ///
372    /// ```
373    /// # use wasmtime::*;
374    /// # fn main() -> anyhow::Result<()> {
375    /// # let engine = Engine::default();
376    /// let wat = r#"
377    ///     (module
378    ///         (import "host" "foo" (func))
379    ///     )
380    /// "#;
381    /// let module = Module::new(&engine, wat)?;
382    /// assert_eq!(module.imports().len(), 1);
383    /// let import = module.imports().next().unwrap();
384    /// assert_eq!(import.module(), "host");
385    /// assert_eq!(import.name(), "foo");
386    /// match import.ty() {
387    ///     ExternType::Func(_) => { /* ... */ }
388    ///     _ => panic!("unexpected import type!"),
389    /// }
390    /// # Ok(())
391    /// # }
392    /// ```
393    pub fn imports<'module>(
394        &'module self,
395    ) -> impl ExactSizeIterator<Item = ImportType<'module>> + 'module {
396        let module = self.compiled.module();
397        module
398            .imports
399            .iter()
400            .map(move |(module_name, name, entity_index)| {
401                let r#type = EntityType::new(entity_index, module);
402                ImportType::new(module_name, name, r#type)
403            })
404    }
405
406    /// Returns the list of exports that this [`Module`] has and will be
407    /// available after instantiation.
408    ///
409    /// This function will return the type of each item that will be returned
410    /// from [`Instance::exports`](crate::Instance::exports). Each entry in this
411    /// list corresponds 1-to-1 with that list, and the entries here will
412    /// indicate the name of the export along with the type of the export.
413    ///
414    /// # Examples
415    ///
416    /// Modules might not have any exports:
417    ///
418    /// ```
419    /// # use wasmtime::*;
420    /// # fn main() -> anyhow::Result<()> {
421    /// # let engine = Engine::default();
422    /// let module = Module::new(&engine, "(module)")?;
423    /// assert!(module.exports().next().is_none());
424    /// # Ok(())
425    /// # }
426    /// ```
427    ///
428    /// When the exports are not empty, you can inspect each export:
429    ///
430    /// ```
431    /// # use wasmtime::*;
432    /// # fn main() -> anyhow::Result<()> {
433    /// # let engine = Engine::default();
434    /// let wat = r#"
435    ///     (module
436    ///         (func (export "foo"))
437    ///         (memory (export "memory") 1)
438    ///     )
439    /// "#;
440    /// let module = Module::new(&engine, wat)?;
441    /// assert_eq!(module.exports().len(), 2);
442    ///
443    /// let mut exports = module.exports();
444    /// let foo = exports.next().unwrap();
445    /// assert_eq!(foo.name(), "foo");
446    /// match foo.ty() {
447    ///     ExternType::Func(_) => { /* ... */ }
448    ///     _ => panic!("unexpected export type!"),
449    /// }
450    ///
451    /// let memory = exports.next().unwrap();
452    /// assert_eq!(memory.name(), "memory");
453    /// match memory.ty() {
454    ///     ExternType::Memory(_) => { /* ... */ }
455    ///     _ => panic!("unexpected export type!"),
456    /// }
457    /// # Ok(())
458    /// # }
459    /// ```
460    pub fn exports<'module>(
461        &'module self,
462    ) -> impl ExactSizeIterator<Item = ExportType<'module>> + 'module {
463        let module = self.compiled.module();
464        module.exports.iter().map(move |(name, entity_index)| {
465            let r#type = EntityType::new(entity_index, module);
466            ExportType::new(name, r#type)
467        })
468    }
469
470    /// Looks up an export in this [`Module`] by name.
471    ///
472    /// This function will return the type of an export with the given name.
473    ///
474    /// # Examples
475    ///
476    /// There may be no export with that name:
477    ///
478    /// ```
479    /// # use wasmtime::*;
480    /// # fn main() -> anyhow::Result<()> {
481    /// # let engine = Engine::default();
482    /// let module = Module::new(&engine, "(module)")?;
483    /// assert!(module.get_export("foo").is_none());
484    /// # Ok(())
485    /// # }
486    /// ```
487    ///
488    /// When there is an export with that name, it is returned:
489    ///
490    /// ```
491    /// # use wasmtime::*;
492    /// # fn main() -> anyhow::Result<()> {
493    /// # let engine = Engine::default();
494    /// let wat = r#"
495    ///     (module
496    ///         (func (export "foo"))
497    ///         (memory (export "memory") 1)
498    ///     )
499    /// "#;
500    /// let module = Module::new(&engine, wat)?;
501    /// let foo = module.get_export("foo");
502    /// assert!(foo.is_some());
503    ///
504    /// let foo = foo.unwrap();
505    /// match foo {
506    ///     ExternType::Func(_) => { /* ... */ }
507    ///     _ => panic!("unexpected export type!"),
508    /// }
509    ///
510    /// # Ok(())
511    /// # }
512    /// ```
513    pub fn get_export<'module>(&'module self, name: &'module str) -> Option<ExternType> {
514        let module = self.compiled.module();
515        let entity_index = module.exports.get(name)?;
516        Some(EntityType::new(entity_index, module).extern_type())
517    }
518
519    /// Returns the [`Engine`] that this [`Module`] was compiled by.
520    pub fn engine(&self) -> &Engine {
521        &self.engine
522    }
523
524    /// Register this module's stack frame information into the global scope.
525    ///
526    /// This is required to ensure that any traps can be properly symbolicated.
527    pub(crate) fn register_frame_info(&self) -> Option<Arc<GlobalFrameInfoRegistration>> {
528        let mut info = self.frame_info_registration.lock().unwrap();
529        if let Some(info) = &*info {
530            return info.clone();
531        }
532        let ret = super::frame_info::register(&self.compiled).map(Arc::new);
533        *info = Some(ret.clone());
534        return ret;
535    }
536}
537
538fn _assert_send_sync() {
539    fn _assert<T: Send + Sync>() {}
540    _assert::<Module>();
541}