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}