wasmtime/module.rs
1use crate::code::CodeObject;
2use crate::{
3 signatures::SignatureCollection,
4 types::{ExportType, ExternType, ImportType},
5 Engine,
6};
7use anyhow::{bail, Context, Result};
8use once_cell::sync::OnceCell;
9use std::any::Any;
10use std::fs;
11use std::mem;
12use std::ops::Range;
13use std::path::Path;
14use std::sync::Arc;
15use wasmparser::{Parser, ValidPayload, Validator};
16use wasmtime_environ::{
17 DefinedFuncIndex, DefinedMemoryIndex, HostPtr, ModuleEnvironment, ModuleTranslation,
18 ModuleTypes, ObjectKind, PrimaryMap, VMOffsets, WasmFunctionInfo,
19};
20use wasmtime_jit::{CodeMemory, CompiledModule, CompiledModuleInfo};
21use wasmtime_runtime::{
22 CompiledModuleId, MemoryImage, MmapVec, ModuleMemoryImages, VMFunctionBody,
23 VMSharedSignatureIndex,
24};
25
26mod registry;
27
28pub use registry::{is_wasm_trap_pc, register_code, unregister_code, ModuleRegistry};
29
30/// A compiled WebAssembly module, ready to be instantiated.
31///
32/// A `Module` is a compiled in-memory representation of an input WebAssembly
33/// binary. A `Module` is then used to create an [`Instance`](crate::Instance)
34/// through an instantiation process. You cannot call functions or fetch
35/// globals, for example, on a `Module` because it's purely a code
36/// representation. Instead you'll need to create an
37/// [`Instance`](crate::Instance) to interact with the wasm module.
38///
39/// Creating a `Module` currently involves compiling code, meaning that it can
40/// be an expensive operation. All `Module` instances are compiled according to
41/// the configuration in [`Config`], but typically they're JIT-compiled. If
42/// you'd like to instantiate a module multiple times you can do so with
43/// compiling the original wasm module only once with a single [`Module`]
44/// instance.
45///
46/// The `Module` is thread-safe and safe to share across threads.
47///
48/// ## Modules and `Clone`
49///
50/// Using `clone` on a `Module` is a cheap operation. It will not create an
51/// entirely new module, but rather just a new reference to the existing module.
52/// In other words it's a shallow copy, not a deep copy.
53///
54/// ## Examples
55///
56/// There are a number of ways you can create a `Module`, for example pulling
57/// the bytes from a number of locations. One example is loading a module from
58/// the filesystem:
59///
60/// ```no_run
61/// # use wasmtime::*;
62/// # fn main() -> anyhow::Result<()> {
63/// let engine = Engine::default();
64/// let module = Module::from_file(&engine, "path/to/foo.wasm")?;
65/// # Ok(())
66/// # }
67/// ```
68///
69/// You can also load the wasm text format if more convenient too:
70///
71/// ```no_run
72/// # use wasmtime::*;
73/// # fn main() -> anyhow::Result<()> {
74/// let engine = Engine::default();
75/// // Now we're using the WebAssembly text extension: `.wat`!
76/// let module = Module::from_file(&engine, "path/to/foo.wat")?;
77/// # Ok(())
78/// # }
79/// ```
80///
81/// And if you've already got the bytes in-memory you can use the
82/// [`Module::new`] constructor:
83///
84/// ```no_run
85/// # use wasmtime::*;
86/// # fn main() -> anyhow::Result<()> {
87/// let engine = Engine::default();
88/// # let wasm_bytes: Vec<u8> = Vec::new();
89/// let module = Module::new(&engine, &wasm_bytes)?;
90///
91/// // It also works with the text format!
92/// let module = Module::new(&engine, "(module (func))")?;
93/// # Ok(())
94/// # }
95/// ```
96///
97/// [`Config`]: crate::Config
98#[derive(Clone)]
99pub struct Module {
100 inner: Arc<ModuleInner>,
101}
102
103struct ModuleInner {
104 engine: Engine,
105 /// The compiled artifacts for this module that will be instantiated and
106 /// executed.
107 module: CompiledModule,
108
109 /// Runtime information such as the underlying mmap, type information, etc.
110 ///
111 /// Note that this `Arc` is used to share information between compiled
112 /// modules within a component. For bare core wasm modules created with
113 /// `Module::new`, for example, this is a uniquely owned `Arc`.
114 code: Arc<CodeObject>,
115
116 /// A set of initialization images for memories, if any.
117 ///
118 /// Note that this is behind a `OnceCell` to lazily create this image. On
119 /// Linux where `memfd_create` may be used to create the backing memory
120 /// image this is a pretty expensive operation, so by deferring it this
121 /// improves memory usage for modules that are created but may not ever be
122 /// instantiated.
123 memory_images: OnceCell<Option<ModuleMemoryImages>>,
124
125 /// Flag indicating whether this module can be serialized or not.
126 serializable: bool,
127
128 /// Runtime offset information for `VMContext`.
129 offsets: VMOffsets<HostPtr>,
130}
131
132impl Module {
133 /// Creates a new WebAssembly `Module` from the given in-memory `bytes`.
134 ///
135 /// The `bytes` provided must be in one of the following formats:
136 ///
137 /// * A [binary-encoded][binary] WebAssembly module. This is always supported.
138 /// * A [text-encoded][text] instance of the WebAssembly text format.
139 /// This is only supported when the `wat` feature of this crate is enabled.
140 /// If this is supplied then the text format will be parsed before validation.
141 /// Note that the `wat` feature is enabled by default.
142 ///
143 /// The data for the wasm module must be loaded in-memory if it's present
144 /// elsewhere, for example on disk. This requires that the entire binary is
145 /// loaded into memory all at once, this API does not support streaming
146 /// compilation of a module.
147 ///
148 /// If the module has not been already been compiled, the WebAssembly binary will
149 /// be decoded and validated. It will also be compiled according to the
150 /// configuration of the provided `engine`.
151 ///
152 /// # Errors
153 ///
154 /// This function may fail and return an error. Errors may include
155 /// situations such as:
156 ///
157 /// * The binary provided could not be decoded because it's not a valid
158 /// WebAssembly binary
159 /// * The WebAssembly binary may not validate (e.g. contains type errors)
160 /// * Implementation-specific limits were exceeded with a valid binary (for
161 /// example too many locals)
162 /// * The wasm binary may use features that are not enabled in the
163 /// configuration of `engine`
164 /// * If the `wat` feature is enabled and the input is text, then it may be
165 /// rejected if it fails to parse.
166 ///
167 /// The error returned should contain full information about why module
168 /// creation failed if one is returned.
169 ///
170 /// [binary]: https://webassembly.github.io/spec/core/binary/index.html
171 /// [text]: https://webassembly.github.io/spec/core/text/index.html
172 ///
173 /// # Examples
174 ///
175 /// The `new` function can be invoked with a in-memory array of bytes:
176 ///
177 /// ```no_run
178 /// # use wasmtime::*;
179 /// # fn main() -> anyhow::Result<()> {
180 /// # let engine = Engine::default();
181 /// # let wasm_bytes: Vec<u8> = Vec::new();
182 /// let module = Module::new(&engine, &wasm_bytes)?;
183 /// # Ok(())
184 /// # }
185 /// ```
186 ///
187 /// Or you can also pass in a string to be parsed as the wasm text
188 /// format:
189 ///
190 /// ```
191 /// # use wasmtime::*;
192 /// # fn main() -> anyhow::Result<()> {
193 /// # let engine = Engine::default();
194 /// let module = Module::new(&engine, "(module (func))")?;
195 /// # Ok(())
196 /// # }
197 /// ```
198 #[cfg(compiler)]
199 #[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
200 pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
201 let bytes = bytes.as_ref();
202 #[cfg(feature = "wat")]
203 let bytes = wat::parse_bytes(bytes)?;
204 Self::from_binary(engine, &bytes)
205 }
206
207 /// Creates a new WebAssembly `Module` from the contents of the given
208 /// `file` on disk.
209 ///
210 /// This is a convenience function that will read the `file` provided and
211 /// pass the bytes to the [`Module::new`] function. For more information
212 /// see [`Module::new`]
213 ///
214 /// # Examples
215 ///
216 /// ```no_run
217 /// # use wasmtime::*;
218 /// # fn main() -> anyhow::Result<()> {
219 /// let engine = Engine::default();
220 /// let module = Module::from_file(&engine, "./path/to/foo.wasm")?;
221 /// # Ok(())
222 /// # }
223 /// ```
224 ///
225 /// The `.wat` text format is also supported:
226 ///
227 /// ```no_run
228 /// # use wasmtime::*;
229 /// # fn main() -> anyhow::Result<()> {
230 /// # let engine = Engine::default();
231 /// let module = Module::from_file(&engine, "./path/to/foo.wat")?;
232 /// # Ok(())
233 /// # }
234 /// ```
235 #[cfg(compiler)]
236 #[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
237 pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
238 match Self::new(
239 engine,
240 &fs::read(&file).with_context(|| "failed to read input file")?,
241 ) {
242 Ok(m) => Ok(m),
243 Err(e) => {
244 cfg_if::cfg_if! {
245 if #[cfg(feature = "wat")] {
246 let mut e = e.downcast::<wat::Error>()?;
247 e.set_path(file);
248 bail!(e)
249 } else {
250 Err(e)
251 }
252 }
253 }
254 }
255 }
256
257 /// Creates a new WebAssembly `Module` from the given in-memory `binary`
258 /// data.
259 ///
260 /// This is similar to [`Module::new`] except that it requires that the
261 /// `binary` input is a WebAssembly binary, the text format is not supported
262 /// by this function. It's generally recommended to use [`Module::new`], but
263 /// if it's required to not support the text format this function can be
264 /// used instead.
265 ///
266 /// # Examples
267 ///
268 /// ```
269 /// # use wasmtime::*;
270 /// # fn main() -> anyhow::Result<()> {
271 /// # let engine = Engine::default();
272 /// let wasm = b"\0asm\x01\0\0\0";
273 /// let module = Module::from_binary(&engine, wasm)?;
274 /// # Ok(())
275 /// # }
276 /// ```
277 ///
278 /// Note that the text format is **not** accepted by this function:
279 ///
280 /// ```
281 /// # use wasmtime::*;
282 /// # fn main() -> anyhow::Result<()> {
283 /// # let engine = Engine::default();
284 /// assert!(Module::from_binary(&engine, b"(module)").is_err());
285 /// # Ok(())
286 /// # }
287 /// ```
288 #[cfg(compiler)]
289 #[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
290 pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
291 engine
292 .check_compatible_with_native_host()
293 .context("compilation settings are not compatible with the native host")?;
294
295 cfg_if::cfg_if! {
296 if #[cfg(feature = "cache")] {
297 let state = (HashedEngineCompileEnv(engine), binary);
298 let (code, info_and_types) = wasmtime_cache::ModuleCacheEntry::new(
299 "wasmtime",
300 engine.cache_config(),
301 )
302 .get_data_raw(
303 &state,
304
305 // Cache miss, compute the actual artifacts
306 |(engine, wasm)| -> Result<_> {
307 let (mmap, info) = Module::build_artifacts(engine.0, wasm)?;
308 let code = publish_mmap(mmap)?;
309 Ok((code, info))
310 },
311
312 // Implementation of how to serialize artifacts
313 |(_engine, _wasm), (code, _info_and_types)| {
314 Some(code.mmap().to_vec())
315 },
316
317 // Cache hit, deserialize the provided artifacts
318 |(engine, _wasm), serialized_bytes| {
319 let code = engine.0.load_code_bytes(&serialized_bytes, ObjectKind::Module).ok()?;
320 Some((code, None))
321 },
322 )?;
323 } else {
324 let (mmap, info_and_types) = Module::build_artifacts(engine, binary)?;
325 let code = publish_mmap(mmap)?;
326 }
327 };
328
329 let info_and_types = info_and_types.map(|(info, types)| (info, types.into()));
330 return Self::from_parts(engine, code, info_and_types);
331
332 fn publish_mmap(mmap: MmapVec) -> Result<Arc<CodeMemory>> {
333 let mut code = CodeMemory::new(mmap)?;
334 code.publish()?;
335 Ok(Arc::new(code))
336 }
337 }
338
339 /// Creates a new WebAssembly `Module` from the contents of the given `file`
340 /// on disk, but with assumptions that the file is from a trusted source.
341 /// The file should be a binary- or text-format WebAssembly module, or a
342 /// precompiled artifact generated by the same version of Wasmtime.
343 ///
344 /// # Unsafety
345 ///
346 /// All of the reasons that [`deserialize`] is `unsafe` apply to this
347 /// function as well. Arbitrary data loaded from a file may trick Wasmtime
348 /// into arbitrary code execution since the contents of the file are not
349 /// validated to be a valid precompiled module.
350 ///
351 /// [`deserialize`]: Module::deserialize
352 ///
353 /// Additionally though this function is also `unsafe` because the file
354 /// referenced must remain unchanged and a valid precompiled module for the
355 /// entire lifetime of the [`Module`] returned. Any changes to the file on
356 /// disk may change future instantiations of the module to be incorrect.
357 /// This is because the file is mapped into memory and lazily loaded pages
358 /// reflect the current state of the file, not necessarily the origianl
359 /// state of the file.
360 #[cfg(compiler)]
361 #[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
362 pub unsafe fn from_trusted_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
363 let mmap = MmapVec::from_file(file.as_ref())?;
364 if &mmap[0..4] == b"\x7fELF" {
365 let code = engine.load_code(mmap, ObjectKind::Module)?;
366 return Module::from_parts(engine, code, None);
367 }
368
369 Module::new(engine, &*mmap)
370 }
371
372 /// Converts an input binary-encoded WebAssembly module to compilation
373 /// artifacts and type information.
374 ///
375 /// This is where compilation actually happens of WebAssembly modules and
376 /// translation/parsing/validation of the binary input occurs. The binary
377 /// artifact represented in the `MmapVec` returned here is an in-memory ELF
378 /// file in an owned area of virtual linear memory where permissions (such
379 /// as the executable bit) can be applied.
380 ///
381 /// Additionally compilation returns an `Option` here which is always
382 /// `Some`, notably compiled metadata about the module in addition to the
383 /// type information found within.
384 #[cfg(compiler)]
385 pub(crate) fn build_artifacts(
386 engine: &Engine,
387 wasm: &[u8],
388 ) -> Result<(MmapVec, Option<(CompiledModuleInfo, ModuleTypes)>)> {
389 let tunables = &engine.config().tunables;
390 let compiler = engine.compiler();
391
392 // First a `ModuleEnvironment` is created which records type information
393 // about the wasm module. This is where the WebAssembly is parsed and
394 // validated. Afterwards `types` will have all the type information for
395 // this module.
396 let mut validator =
397 wasmparser::Validator::new_with_features(engine.config().features.clone());
398 let parser = wasmparser::Parser::new(0);
399 let mut types = Default::default();
400 let mut translation = ModuleEnvironment::new(tunables, &mut validator, &mut types)
401 .translate(parser, wasm)
402 .context("failed to parse WebAssembly module")?;
403 let types = types.finish();
404
405 // Afterwards compile all functions and trampolines required by the
406 // module.
407 let signatures = translation.exported_signatures.clone();
408 let (funcs, trampolines) = engine.join_maybe_parallel(
409 // In one (possibly) parallel task all wasm functions are compiled
410 // in parallel. Note that this is also where the actual validation
411 // of all function bodies happens as well.
412 || Self::compile_functions(engine, &mut translation, &types),
413 // In another (possibly) parallel task all trampolines necessary
414 // for untyped host-to-wasm entry are compiled. Note that this
415 // isn't really expected to take all that long, it's moreso "well
416 // if we're using rayon why not use it here too".
417 || -> Result<_> {
418 engine.run_maybe_parallel(signatures, |sig| {
419 let ty = &types[sig];
420 Ok(compiler.compile_host_to_wasm_trampoline(ty)?)
421 })
422 },
423 );
424
425 // Weave the separate list of compiled functions into one list, storing
426 // the other metadata off to the side for now.
427 let funcs = funcs?;
428 let trampolines = trampolines?;
429 let mut func_infos = PrimaryMap::with_capacity(funcs.len());
430 let mut compiled_funcs = Vec::with_capacity(funcs.len() + trampolines.len());
431 for (info, func) in funcs {
432 let idx = func_infos.push(info);
433 let sym = format!(
434 "_wasm_function_{}",
435 translation.module.func_index(idx).as_u32()
436 );
437 compiled_funcs.push((sym, func));
438 }
439 for (sig, func) in translation.exported_signatures.iter().zip(trampolines) {
440 let sym = format!("_trampoline_{}", sig.as_u32());
441 compiled_funcs.push((sym, func));
442 }
443
444 // Emplace all compiled functions into the object file with any other
445 // sections associated with code as well.
446 let mut obj = engine.compiler().object(ObjectKind::Module)?;
447 let locs = compiler.append_code(&mut obj, &compiled_funcs, tunables, &|i, idx| {
448 assert!(i < func_infos.len());
449 let defined = translation.module.defined_func_index(idx).unwrap();
450 defined.as_u32() as usize
451 })?;
452
453 // If requested, generate and add dwarf information.
454 if tunables.generate_native_debuginfo && !func_infos.is_empty() {
455 let mut locs = locs.iter();
456 let mut funcs = compiled_funcs.iter();
457 let funcs = (0..func_infos.len())
458 .map(|_| (locs.next().unwrap().0, &*funcs.next().unwrap().1))
459 .collect();
460 compiler.append_dwarf(&mut obj, &translation, &funcs)?;
461 }
462
463 // Process all the results of compilation into a final state for our
464 // internal representation.
465 let mut locs = locs.into_iter();
466 let funcs = func_infos
467 .into_iter()
468 .map(|(_, info)| (info, locs.next().unwrap().1))
469 .collect();
470 let trampolines = translation
471 .exported_signatures
472 .iter()
473 .cloned()
474 .map(|i| (i, locs.next().unwrap().1))
475 .collect();
476 assert!(locs.next().is_none());
477
478 // Insert `Engine` and type-level information into the compiled
479 // artifact so if this module is deserialized later it contains all
480 // information necessary.
481 //
482 // Note that `append_compiler_info` and `append_types` here in theory
483 // can both be skipped if this module will never get serialized.
484 // They're only used during deserialization and not during runtime for
485 // the module itself. Currently there's no need for that, however, so
486 // it's left as an exercise for later.
487 engine.append_compiler_info(&mut obj);
488 engine.append_bti(&mut obj);
489
490 let mut obj = wasmtime_jit::ObjectBuilder::new(obj, tunables);
491 let info = obj.append(translation, funcs, trampolines)?;
492 obj.serialize_info(&(&info, &types));
493 let mmap = obj.finish()?;
494
495 Ok((mmap, Some((info, types))))
496 }
497
498 #[cfg(compiler)]
499 pub(crate) fn compile_functions(
500 engine: &Engine,
501 translation: &mut ModuleTranslation<'_>,
502 types: &ModuleTypes,
503 ) -> Result<Vec<(WasmFunctionInfo, Box<dyn Any + Send>)>> {
504 let tunables = &engine.config().tunables;
505 let functions = mem::take(&mut translation.function_body_inputs);
506 let functions = functions.into_iter().collect::<Vec<_>>();
507 let compiler = engine.compiler();
508 let funcs = engine.run_maybe_parallel(functions, |(index, func)| {
509 let offset = func.body.range().start;
510 let result = compiler.compile_function(&translation, index, func, tunables, types);
511 result.with_context(|| {
512 let index = translation.module.func_index(index);
513 let name = match translation.debuginfo.name_section.func_names.get(&index) {
514 Some(name) => format!(" (`{}`)", name),
515 None => String::new(),
516 };
517 let index = index.as_u32();
518 format!("failed to compile wasm function {index}{name} at offset {offset:#x}")
519 })
520 })?;
521
522 // If configured attempt to use static memory initialization which
523 // can either at runtime be implemented as a single memcpy to
524 // initialize memory or otherwise enabling virtual-memory-tricks
525 // such as mmap'ing from a file to get copy-on-write.
526 if engine.config().memory_init_cow {
527 let align = engine.compiler().page_size_align();
528 let max_always_allowed = engine.config().memory_guaranteed_dense_image_size;
529 translation.try_static_init(align, max_always_allowed);
530 }
531
532 // Attempt to convert table initializer segments to
533 // FuncTable representation where possible, to enable
534 // table lazy init.
535 translation.try_func_table_init();
536
537 Ok(funcs)
538 }
539
540 /// Deserializes an in-memory compiled module previously created with
541 /// [`Module::serialize`] or [`Engine::precompile_module`].
542 ///
543 /// This function will deserialize the binary blobs emitted by
544 /// [`Module::serialize`] and [`Engine::precompile_module`] back into an
545 /// in-memory [`Module`] that's ready to be instantiated.
546 ///
547 /// Note that the [`Module::deserialize_file`] method is more optimized than
548 /// this function, so if the serialized module is already present in a file
549 /// it's recommended to use that method instead.
550 ///
551 /// # Unsafety
552 ///
553 /// This function is marked as `unsafe` because if fed invalid input or used
554 /// improperly this could lead to memory safety vulnerabilities. This method
555 /// should not, for example, be exposed to arbitrary user input.
556 ///
557 /// The structure of the binary blob read here is only lightly validated
558 /// internally in `wasmtime`. This is intended to be an efficient
559 /// "rehydration" for a [`Module`] which has very few runtime checks beyond
560 /// deserialization. Arbitrary input could, for example, replace valid
561 /// compiled code with any other valid compiled code, meaning that this can
562 /// trivially be used to execute arbitrary code otherwise.
563 ///
564 /// For these reasons this function is `unsafe`. This function is only
565 /// designed to receive the previous input from [`Module::serialize`] and
566 /// [`Engine::precompile_module`]. If the exact output of those functions
567 /// (unmodified) is passed to this function then calls to this function can
568 /// be considered safe. It is the caller's responsibility to provide the
569 /// guarantee that only previously-serialized bytes are being passed in
570 /// here.
571 ///
572 /// Note that this function is designed to be safe receiving output from
573 /// *any* compiled version of `wasmtime` itself. This means that it is safe
574 /// to feed output from older versions of Wasmtime into this function, in
575 /// addition to newer versions of wasmtime (from the future!). These inputs
576 /// will deterministically and safely produce an `Err`. This function only
577 /// successfully accepts inputs from the same version of `wasmtime`, but the
578 /// safety guarantee only applies to externally-defined blobs of bytes, not
579 /// those defined by any version of wasmtime. (this means that if you cache
580 /// blobs across versions of wasmtime you can be safely guaranteed that
581 /// future versions of wasmtime will reject old cache entries).
582 pub unsafe fn deserialize(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
583 let code = engine.load_code_bytes(bytes.as_ref(), ObjectKind::Module)?;
584 Module::from_parts(engine, code, None)
585 }
586
587 /// Same as [`deserialize`], except that the contents of `path` are read to
588 /// deserialize into a [`Module`].
589 ///
590 /// This method is provided because it can be faster than [`deserialize`]
591 /// since the data doesn't need to be copied around, but rather the module
592 /// can be used directly from an mmap'd view of the file provided.
593 ///
594 /// [`deserialize`]: Module::deserialize
595 ///
596 /// # Unsafety
597 ///
598 /// All of the reasons that [`deserialize`] is `unsafe` applies to this
599 /// function as well. Arbitrary data loaded from a file may trick Wasmtime
600 /// into arbitrary code execution since the contents of the file are not
601 /// validated to be a valid precompiled module.
602 ///
603 /// Additionally though this function is also `unsafe` because the file
604 /// referenced must remain unchanged and a valid precompiled module for the
605 /// entire lifetime of the [`Module`] returned. Any changes to the file on
606 /// disk may change future instantiations of the module to be incorrect.
607 /// This is because the file is mapped into memory and lazily loaded pages
608 /// reflect the current state of the file, not necessarily the origianl
609 /// state of the file.
610 pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef<Path>) -> Result<Module> {
611 let code = engine.load_code_file(path.as_ref(), ObjectKind::Module)?;
612 Module::from_parts(engine, code, None)
613 }
614
615 /// Entrypoint for creating a `Module` for all above functions, both
616 /// of the AOT and jit-compiled cateogries.
617 ///
618 /// In all cases the compilation artifact, `code_memory`, is provided here.
619 /// The `info_and_types` argument is `None` when a module is being
620 /// deserialized from a precompiled artifact or it's `Some` if it was just
621 /// compiled and the values are already available.
622 fn from_parts(
623 engine: &Engine,
624 code_memory: Arc<CodeMemory>,
625 info_and_types: Option<(CompiledModuleInfo, ModuleTypes)>,
626 ) -> Result<Self> {
627 // Acquire this module's metadata and type information, deserializing
628 // it from the provided artifact if it wasn't otherwise provided
629 // already.
630 let (info, types) = match info_and_types {
631 Some((info, types)) => (info, types),
632 None => bincode::deserialize(code_memory.wasmtime_info())?,
633 };
634
635 // Register function type signatures into the engine for the lifetime
636 // of the `Module` that will be returned. This notably also builds up
637 // maps for trampolines to be used for this module when inserted into
638 // stores.
639 //
640 // Note that the unsafety here should be ok since the `trampolines`
641 // field should only point to valid trampoline function pointers
642 // within the text section.
643 let signatures = SignatureCollection::new_for_module(
644 engine.signatures(),
645 &types,
646 info.trampolines
647 .iter()
648 .map(|(idx, f)| (*idx, unsafe { code_memory.vmtrampoline(*f) })),
649 );
650
651 // Package up all our data into a `CodeObject` and delegate to the final
652 // step of module compilation.
653 let code = Arc::new(CodeObject::new(code_memory, signatures, types.into()));
654 Module::from_parts_raw(engine, code, info, true)
655 }
656
657 pub(crate) fn from_parts_raw(
658 engine: &Engine,
659 code: Arc<CodeObject>,
660 info: CompiledModuleInfo,
661 serializable: bool,
662 ) -> Result<Self> {
663 let module = CompiledModule::from_artifacts(
664 code.code_memory().clone(),
665 info,
666 engine.profiler(),
667 engine.unique_id_allocator(),
668 )?;
669
670 // Validate the module can be used with the current allocator
671 let offsets = VMOffsets::new(HostPtr, module.module());
672 engine.allocator().validate(module.module(), &offsets)?;
673
674 Ok(Self {
675 inner: Arc::new(ModuleInner {
676 engine: engine.clone(),
677 code,
678 memory_images: OnceCell::new(),
679 module,
680 serializable,
681 offsets,
682 }),
683 })
684 }
685
686 /// Validates `binary` input data as a WebAssembly binary given the
687 /// configuration in `engine`.
688 ///
689 /// This function will perform a speedy validation of the `binary` input
690 /// WebAssembly module (which is in [binary form][binary], the text format
691 /// is not accepted by this function) and return either `Ok` or `Err`
692 /// depending on the results of validation. The `engine` argument indicates
693 /// configuration for WebAssembly features, for example, which are used to
694 /// indicate what should be valid and what shouldn't be.
695 ///
696 /// Validation automatically happens as part of [`Module::new`].
697 ///
698 /// # Errors
699 ///
700 /// If validation fails for any reason (type check error, usage of a feature
701 /// that wasn't enabled, etc) then an error with a description of the
702 /// validation issue will be returned.
703 ///
704 /// [binary]: https://webassembly.github.io/spec/core/binary/index.html
705 pub fn validate(engine: &Engine, binary: &[u8]) -> Result<()> {
706 let mut validator = Validator::new_with_features(engine.config().features);
707
708 let mut functions = Vec::new();
709 for payload in Parser::new(0).parse_all(binary) {
710 let payload = payload?;
711 if let ValidPayload::Func(a, b) = validator.payload(&payload)? {
712 functions.push((a, b));
713 }
714 if let wasmparser::Payload::Version { encoding, .. } = &payload {
715 if let wasmparser::Encoding::Component = encoding {
716 bail!("component passed to module validation");
717 }
718 }
719 }
720
721 engine.run_maybe_parallel(functions, |(validator, body)| {
722 // FIXME: it would be best here to use a rayon-specific parallel
723 // iterator that maintains state-per-thread to share the function
724 // validator allocations (`Default::default` here) across multiple
725 // functions.
726 validator.into_validator(Default::default()).validate(&body)
727 })?;
728 Ok(())
729 }
730
731 /// Serializes this module to a vector of bytes.
732 ///
733 /// This function is similar to the [`Engine::precompile_module`] method
734 /// where it produces an artifact of Wasmtime which is suitable to later
735 /// pass into [`Module::deserialize`]. If a module is never instantiated
736 /// then it's recommended to use [`Engine::precompile_module`] instead of
737 /// this method, but if a module is both instantiated and serialized then
738 /// this method can be useful to get the serialized version without
739 /// compiling twice.
740 #[cfg(compiler)]
741 #[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
742 pub fn serialize(&self) -> Result<Vec<u8>> {
743 // The current representation of compiled modules within a compiled
744 // component means that it cannot be serialized. The mmap returned here
745 // is the mmap for the entire component and while it contains all
746 // necessary data to deserialize this particular module it's all
747 // embedded within component-specific information.
748 //
749 // It's not the hardest thing in the world to support this but it's
750 // expected that there's not much of a use case at this time. In theory
751 // all that needs to be done is to edit the `.wasmtime.info` section
752 // to contains this module's metadata instead of the metadata for the
753 // whole component. The metadata itself is fairly trivially
754 // recreateable here it's more that there's no easy one-off API for
755 // editing the sections of an ELF object to use here.
756 //
757 // Overall for now this simply always returns an error in this
758 // situation. If you're reading this and feel that the situation should
759 // be different please feel free to open an issue.
760 if !self.inner.serializable {
761 bail!("cannot serialize a module exported from a component");
762 }
763 Ok(self.compiled_module().mmap().to_vec())
764 }
765
766 pub(crate) fn compiled_module(&self) -> &CompiledModule {
767 &self.inner.module
768 }
769
770 fn code_object(&self) -> &Arc<CodeObject> {
771 &self.inner.code
772 }
773
774 pub(crate) fn env_module(&self) -> &wasmtime_environ::Module {
775 self.compiled_module().module()
776 }
777
778 pub(crate) fn types(&self) -> &ModuleTypes {
779 self.inner.code.module_types()
780 }
781
782 pub(crate) fn signatures(&self) -> &SignatureCollection {
783 self.inner.code.signatures()
784 }
785
786 /// Returns identifier/name that this [`Module`] has. This name
787 /// is used in traps/backtrace details.
788 ///
789 /// Note that most LLVM/clang/Rust-produced modules do not have a name
790 /// associated with them, but other wasm tooling can be used to inject or
791 /// add a name.
792 ///
793 /// # Examples
794 ///
795 /// ```
796 /// # use wasmtime::*;
797 /// # fn main() -> anyhow::Result<()> {
798 /// # let engine = Engine::default();
799 /// let module = Module::new(&engine, "(module $foo)")?;
800 /// assert_eq!(module.name(), Some("foo"));
801 ///
802 /// let module = Module::new(&engine, "(module)")?;
803 /// assert_eq!(module.name(), None);
804 ///
805 /// # Ok(())
806 /// # }
807 /// ```
808 pub fn name(&self) -> Option<&str> {
809 self.compiled_module().module().name.as_deref()
810 }
811
812 /// Returns the list of imports that this [`Module`] has and must be
813 /// satisfied.
814 ///
815 /// This function returns the list of imports that the wasm module has, but
816 /// only the types of each import. The type of each import is used to
817 /// typecheck the [`Instance::new`](crate::Instance::new) method's `imports`
818 /// argument. The arguments to that function must match up 1-to-1 with the
819 /// entries in the array returned here.
820 ///
821 /// The imports returned reflect the order of the imports in the wasm module
822 /// itself, and note that no form of deduplication happens.
823 ///
824 /// # Examples
825 ///
826 /// Modules with no imports return an empty list here:
827 ///
828 /// ```
829 /// # use wasmtime::*;
830 /// # fn main() -> anyhow::Result<()> {
831 /// # let engine = Engine::default();
832 /// let module = Module::new(&engine, "(module)")?;
833 /// assert_eq!(module.imports().len(), 0);
834 /// # Ok(())
835 /// # }
836 /// ```
837 ///
838 /// and modules with imports will have a non-empty list:
839 ///
840 /// ```
841 /// # use wasmtime::*;
842 /// # fn main() -> anyhow::Result<()> {
843 /// # let engine = Engine::default();
844 /// let wat = r#"
845 /// (module
846 /// (import "host" "foo" (func))
847 /// )
848 /// "#;
849 /// let module = Module::new(&engine, wat)?;
850 /// assert_eq!(module.imports().len(), 1);
851 /// let import = module.imports().next().unwrap();
852 /// assert_eq!(import.module(), "host");
853 /// assert_eq!(import.name(), "foo");
854 /// match import.ty() {
855 /// ExternType::Func(_) => { /* ... */ }
856 /// _ => panic!("unexpected import type!"),
857 /// }
858 /// # Ok(())
859 /// # }
860 /// ```
861 pub fn imports<'module>(
862 &'module self,
863 ) -> impl ExactSizeIterator<Item = ImportType<'module>> + 'module {
864 let module = self.compiled_module().module();
865 let types = self.types();
866 module
867 .imports()
868 .map(move |(module, field, ty)| ImportType::new(module, field, ty, types))
869 .collect::<Vec<_>>()
870 .into_iter()
871 }
872
873 /// Returns the list of exports that this [`Module`] has and will be
874 /// available after instantiation.
875 ///
876 /// This function will return the type of each item that will be returned
877 /// from [`Instance::exports`](crate::Instance::exports). Each entry in this
878 /// list corresponds 1-to-1 with that list, and the entries here will
879 /// indicate the name of the export along with the type of the export.
880 ///
881 /// # Examples
882 ///
883 /// Modules might not have any exports:
884 ///
885 /// ```
886 /// # use wasmtime::*;
887 /// # fn main() -> anyhow::Result<()> {
888 /// # let engine = Engine::default();
889 /// let module = Module::new(&engine, "(module)")?;
890 /// assert!(module.exports().next().is_none());
891 /// # Ok(())
892 /// # }
893 /// ```
894 ///
895 /// When the exports are not empty, you can inspect each export:
896 ///
897 /// ```
898 /// # use wasmtime::*;
899 /// # fn main() -> anyhow::Result<()> {
900 /// # let engine = Engine::default();
901 /// let wat = r#"
902 /// (module
903 /// (func (export "foo"))
904 /// (memory (export "memory") 1)
905 /// )
906 /// "#;
907 /// let module = Module::new(&engine, wat)?;
908 /// assert_eq!(module.exports().len(), 2);
909 ///
910 /// let mut exports = module.exports();
911 /// let foo = exports.next().unwrap();
912 /// assert_eq!(foo.name(), "foo");
913 /// match foo.ty() {
914 /// ExternType::Func(_) => { /* ... */ }
915 /// _ => panic!("unexpected export type!"),
916 /// }
917 ///
918 /// let memory = exports.next().unwrap();
919 /// assert_eq!(memory.name(), "memory");
920 /// match memory.ty() {
921 /// ExternType::Memory(_) => { /* ... */ }
922 /// _ => panic!("unexpected export type!"),
923 /// }
924 /// # Ok(())
925 /// # }
926 /// ```
927 pub fn exports<'module>(
928 &'module self,
929 ) -> impl ExactSizeIterator<Item = ExportType<'module>> + 'module {
930 let module = self.compiled_module().module();
931 let types = self.types();
932 module.exports.iter().map(move |(name, entity_index)| {
933 ExportType::new(name, module.type_of(*entity_index), types)
934 })
935 }
936
937 /// Looks up an export in this [`Module`] by name.
938 ///
939 /// This function will return the type of an export with the given name.
940 ///
941 /// # Examples
942 ///
943 /// There may be no export with that name:
944 ///
945 /// ```
946 /// # use wasmtime::*;
947 /// # fn main() -> anyhow::Result<()> {
948 /// # let engine = Engine::default();
949 /// let module = Module::new(&engine, "(module)")?;
950 /// assert!(module.get_export("foo").is_none());
951 /// # Ok(())
952 /// # }
953 /// ```
954 ///
955 /// When there is an export with that name, it is returned:
956 ///
957 /// ```
958 /// # use wasmtime::*;
959 /// # fn main() -> anyhow::Result<()> {
960 /// # let engine = Engine::default();
961 /// let wat = r#"
962 /// (module
963 /// (func (export "foo"))
964 /// (memory (export "memory") 1)
965 /// )
966 /// "#;
967 /// let module = Module::new(&engine, wat)?;
968 /// let foo = module.get_export("foo");
969 /// assert!(foo.is_some());
970 ///
971 /// let foo = foo.unwrap();
972 /// match foo {
973 /// ExternType::Func(_) => { /* ... */ }
974 /// _ => panic!("unexpected export type!"),
975 /// }
976 ///
977 /// # Ok(())
978 /// # }
979 /// ```
980 pub fn get_export(&self, name: &str) -> Option<ExternType> {
981 let module = self.compiled_module().module();
982 let entity_index = module.exports.get(name)?;
983 Some(ExternType::from_wasmtime(
984 self.types(),
985 &module.type_of(*entity_index),
986 ))
987 }
988
989 /// Returns the [`Engine`] that this [`Module`] was compiled by.
990 pub fn engine(&self) -> &Engine {
991 &self.inner.engine
992 }
993
994 /// Returns the `ModuleInner` cast as `ModuleRuntimeInfo` for use
995 /// by the runtime.
996 pub(crate) fn runtime_info(&self) -> Arc<dyn wasmtime_runtime::ModuleRuntimeInfo> {
997 // N.B.: this needs to return a clone because we cannot
998 // statically cast the &Arc<ModuleInner> to &Arc<dyn Trait...>.
999 self.inner.clone()
1000 }
1001
1002 pub(crate) fn module_info(&self) -> &dyn wasmtime_runtime::ModuleInfo {
1003 &*self.inner
1004 }
1005
1006 /// Returns the range of bytes in memory where this module's compilation
1007 /// image resides.
1008 ///
1009 /// The compilation image for a module contains executable code, data, debug
1010 /// information, etc. This is roughly the same as the `Module::serialize`
1011 /// but not the exact same.
1012 ///
1013 /// The range of memory reported here is exposed to allow low-level
1014 /// manipulation of the memory in platform-specific manners such as using
1015 /// `mlock` to force the contents to be paged in immediately or keep them
1016 /// paged in after they're loaded.
1017 ///
1018 /// It is not safe to modify the memory in this range, nor is it safe to
1019 /// modify the protections of memory in this range.
1020 pub fn image_range(&self) -> Range<usize> {
1021 self.compiled_module().image_range()
1022 }
1023
1024 /// Force initialization of copy-on-write images to happen here-and-now
1025 /// instead of when they're requested during first instantiation.
1026 ///
1027 /// When [copy-on-write memory
1028 /// initialization](crate::Config::memory_init_cow) is enabled then Wasmtime
1029 /// will lazily create the initialization image for a module. This method
1030 /// can be used to explicitly dictate when this initialization happens.
1031 ///
1032 /// Note that this largely only matters on Linux when memfd is used.
1033 /// Otherwise the copy-on-write image typically comes from disk and in that
1034 /// situation the creation of the image is trivial as the image is always
1035 /// sourced from disk. On Linux, though, when memfd is used a memfd is
1036 /// created and the initialization image is written to it.
1037 ///
1038 /// Also note that this method is not required to be called, it's available
1039 /// as a performance optimization if required but is otherwise handled
1040 /// automatically.
1041 pub fn initialize_copy_on_write_image(&self) -> Result<()> {
1042 self.inner.memory_images()?;
1043 Ok(())
1044 }
1045
1046 /// Get the map from `.text` section offsets to Wasm binary offsets for this
1047 /// module.
1048 ///
1049 /// Each entry is a (`.text` section offset, Wasm binary offset) pair.
1050 ///
1051 /// Entries are yielded in order of `.text` section offset.
1052 ///
1053 /// Some entries are missing a Wasm binary offset. This is for code that is
1054 /// not associated with any single location in the Wasm binary, or for when
1055 /// source information was optimized away.
1056 ///
1057 /// Not every module has an address map, since address map generation can be
1058 /// turned off on `Config`.
1059 ///
1060 /// There is not an entry for every `.text` section offset. Every offset
1061 /// after an entry's offset, but before the next entry's offset, is
1062 /// considered to map to the same Wasm binary offset as the original
1063 /// entry. For example, the address map will not contain the following
1064 /// sequnce of entries:
1065 ///
1066 /// ```ignore
1067 /// [
1068 /// // ...
1069 /// (10, Some(42)),
1070 /// (11, Some(42)),
1071 /// (12, Some(42)),
1072 /// (13, Some(43)),
1073 /// // ...
1074 /// ]
1075 /// ```
1076 ///
1077 /// Instead, it will drop the entries for offsets `11` and `12` since they
1078 /// are the same as the entry for offset `10`:
1079 ///
1080 /// ```ignore
1081 /// [
1082 /// // ...
1083 /// (10, Some(42)),
1084 /// (13, Some(43)),
1085 /// // ...
1086 /// ]
1087 /// ```
1088 pub fn address_map<'a>(&'a self) -> Option<impl Iterator<Item = (usize, Option<u32>)> + 'a> {
1089 Some(
1090 wasmtime_environ::iterate_address_map(
1091 self.code_object().code_memory().address_map_data(),
1092 )?
1093 .map(|(offset, file_pos)| (offset as usize, file_pos.file_offset())),
1094 )
1095 }
1096
1097 /// Get this module's code object's `.text` section, containing its compiled
1098 /// executable code.
1099 pub fn text(&self) -> &[u8] {
1100 self.code_object().code_memory().text()
1101 }
1102
1103 /// Get the locations of functions in this module's `.text` section.
1104 ///
1105 /// Each function's locartion is a (`.text` section offset, length) pair.
1106 pub fn function_locations<'a>(&'a self) -> impl ExactSizeIterator<Item = (usize, usize)> + 'a {
1107 self.compiled_module().finished_functions().map(|(f, _)| {
1108 let loc = self.compiled_module().func_loc(f);
1109 (loc.start as usize, loc.length as usize)
1110 })
1111 }
1112}
1113
1114impl ModuleInner {
1115 fn memory_images(&self) -> Result<Option<&ModuleMemoryImages>> {
1116 let images = self
1117 .memory_images
1118 .get_or_try_init(|| memory_images(&self.engine, &self.module))?
1119 .as_ref();
1120 Ok(images)
1121 }
1122}
1123
1124impl Drop for ModuleInner {
1125 fn drop(&mut self) {
1126 // When a `Module` is being dropped that means that it's no longer
1127 // present in any `Store` and it's additionally not longer held by any
1128 // embedder. Take this opportunity to purge any lingering instantiations
1129 // within a pooling instance allocator, if applicable.
1130 self.engine
1131 .allocator()
1132 .purge_module(self.module.unique_id());
1133 }
1134}
1135
1136fn _assert_send_sync() {
1137 fn _assert<T: Send + Sync>() {}
1138 _assert::<Module>();
1139}
1140
1141/// This is a helper struct used when caching to hash the state of an `Engine`
1142/// used for module compilation.
1143///
1144/// The hash computed for this structure is used to key the global wasmtime
1145/// cache and dictates whether artifacts are reused. Consequently the contents
1146/// of this hash dictate when artifacts are or aren't re-used.
1147#[cfg(all(feature = "cache", compiler))]
1148struct HashedEngineCompileEnv<'a>(&'a Engine);
1149
1150#[cfg(all(feature = "cache", compiler))]
1151impl std::hash::Hash for HashedEngineCompileEnv<'_> {
1152 fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
1153 // Hash the compiler's state based on its target and configuration.
1154 let compiler = self.0.compiler();
1155 compiler.triple().hash(hasher);
1156 compiler.flags().hash(hasher);
1157 compiler.isa_flags().hash(hasher);
1158
1159 // Hash configuration state read for compilation
1160 let config = self.0.config();
1161 config.tunables.hash(hasher);
1162 config.features.hash(hasher);
1163
1164 // Catch accidental bugs of reusing across crate versions.
1165 env!("CARGO_PKG_VERSION").hash(hasher);
1166 }
1167}
1168
1169impl wasmtime_runtime::ModuleRuntimeInfo for ModuleInner {
1170 fn module(&self) -> &Arc<wasmtime_environ::Module> {
1171 self.module.module()
1172 }
1173
1174 fn function(&self, index: DefinedFuncIndex) -> *mut VMFunctionBody {
1175 self.module
1176 .finished_function(index)
1177 .as_ptr()
1178 .cast::<VMFunctionBody>()
1179 .cast_mut()
1180 }
1181
1182 fn memory_image(&self, memory: DefinedMemoryIndex) -> Result<Option<&Arc<MemoryImage>>> {
1183 let images = self.memory_images()?;
1184 Ok(images.and_then(|images| images.get_memory_image(memory)))
1185 }
1186
1187 fn unique_id(&self) -> Option<CompiledModuleId> {
1188 Some(self.module.unique_id())
1189 }
1190
1191 fn wasm_data(&self) -> &[u8] {
1192 self.module.code_memory().wasm_data()
1193 }
1194
1195 fn signature_ids(&self) -> &[VMSharedSignatureIndex] {
1196 self.code.signatures().as_module_map().values().as_slice()
1197 }
1198
1199 fn offsets(&self) -> &VMOffsets<HostPtr> {
1200 &self.offsets
1201 }
1202}
1203
1204impl wasmtime_runtime::ModuleInfo for ModuleInner {
1205 fn lookup_stack_map(&self, pc: usize) -> Option<&wasmtime_environ::StackMap> {
1206 let text_offset = pc - self.module.text().as_ptr() as usize;
1207 let (index, func_offset) = self.module.func_by_text_offset(text_offset)?;
1208 let info = self.module.wasm_func_info(index);
1209
1210 // Do a binary search to find the stack map for the given offset.
1211 let index = match info
1212 .stack_maps
1213 .binary_search_by_key(&func_offset, |i| i.code_offset)
1214 {
1215 // Found it.
1216 Ok(i) => i,
1217
1218 // No stack map associated with this PC.
1219 //
1220 // Because we know we are in Wasm code, and we must be at some kind
1221 // of call/safepoint, then the Cranelift backend must have avoided
1222 // emitting a stack map for this location because no refs were live.
1223 Err(_) => return None,
1224 };
1225
1226 Some(&info.stack_maps[index].stack_map)
1227 }
1228}
1229
1230/// A barebones implementation of ModuleRuntimeInfo that is useful for
1231/// cases where a purpose-built environ::Module is used and a full
1232/// CompiledModule does not exist (for example, for tests or for the
1233/// default-callee instance).
1234pub(crate) struct BareModuleInfo {
1235 module: Arc<wasmtime_environ::Module>,
1236 one_signature: Option<VMSharedSignatureIndex>,
1237 offsets: VMOffsets<HostPtr>,
1238}
1239
1240impl BareModuleInfo {
1241 pub(crate) fn empty(module: Arc<wasmtime_environ::Module>) -> Self {
1242 BareModuleInfo::maybe_imported_func(module, None)
1243 }
1244
1245 pub(crate) fn maybe_imported_func(
1246 module: Arc<wasmtime_environ::Module>,
1247 one_signature: Option<VMSharedSignatureIndex>,
1248 ) -> Self {
1249 BareModuleInfo {
1250 offsets: VMOffsets::new(HostPtr, &module),
1251 module,
1252 one_signature,
1253 }
1254 }
1255
1256 pub(crate) fn into_traitobj(self) -> Arc<dyn wasmtime_runtime::ModuleRuntimeInfo> {
1257 Arc::new(self)
1258 }
1259}
1260
1261impl wasmtime_runtime::ModuleRuntimeInfo for BareModuleInfo {
1262 fn module(&self) -> &Arc<wasmtime_environ::Module> {
1263 &self.module
1264 }
1265
1266 fn function(&self, _index: DefinedFuncIndex) -> *mut VMFunctionBody {
1267 unreachable!()
1268 }
1269
1270 fn memory_image(&self, _memory: DefinedMemoryIndex) -> Result<Option<&Arc<MemoryImage>>> {
1271 Ok(None)
1272 }
1273
1274 fn unique_id(&self) -> Option<CompiledModuleId> {
1275 None
1276 }
1277
1278 fn wasm_data(&self) -> &[u8] {
1279 &[]
1280 }
1281
1282 fn signature_ids(&self) -> &[VMSharedSignatureIndex] {
1283 match &self.one_signature {
1284 Some(id) => std::slice::from_ref(id),
1285 None => &[],
1286 }
1287 }
1288
1289 fn offsets(&self) -> &VMOffsets<HostPtr> {
1290 &self.offsets
1291 }
1292}
1293
1294/// Helper method to construct a `ModuleMemoryImages` for an associated
1295/// `CompiledModule`.
1296fn memory_images(engine: &Engine, module: &CompiledModule) -> Result<Option<ModuleMemoryImages>> {
1297 // If initialization via copy-on-write is explicitly disabled in
1298 // configuration then this path is skipped entirely.
1299 if !engine.config().memory_init_cow {
1300 return Ok(None);
1301 }
1302
1303 // ... otherwise logic is delegated to the `ModuleMemoryImages::new`
1304 // constructor.
1305 let mmap = if engine.config().force_memory_init_memfd {
1306 None
1307 } else {
1308 Some(module.mmap())
1309 };
1310 ModuleMemoryImages::new(module.module(), module.code_memory().wasm_data(), mmap)
1311}