Struct Module
pub struct Module { /* private fields */ }
Expand description
A compiled WebAssembly module, ready to be instantiated.
A Module
is a compiled in-memory representation of an input WebAssembly
binary. A Module
is then used to create an Instance
through an instantiation process. You cannot call functions or fetch
globals, for example, on a Module
because it’s purely a code
representation. Instead you’ll need to create an
Instance
to interact with the wasm module.
A Module
can be created by compiling WebAssembly code through APIs such as
Module::new
. This would be a JIT-style use case where code is compiled
just before it’s used. Alternatively a Module
can be compiled in one
process and Module::serialize
can be used to save it to storage. A later
call to Module::deserialize
will quickly load the module to execute and
does not need to compile any code, representing a more AOT-style use case.
Currently a Module
does not implement any form of tiering or dynamic
optimization of compiled code. Creation of a Module
via Module::new
or
related APIs will perform the entire compilation step synchronously. When
finished no further compilation will happen at runtime or later during
execution of WebAssembly instances for example.
Compilation of WebAssembly by default goes through Cranelift and is recommended to be done once-per-module. The same WebAssembly binary need not be compiled multiple times and can instead used an embedder-cached result of the first call.
Module
is thread-safe and safe to share across threads.
§Modules and Clone
Using clone
on a Module
is a cheap operation. It will not create an
entirely new module, but rather just a new reference to the existing module.
In other words it’s a shallow copy, not a deep copy.
§Examples
There are a number of ways you can create a Module
, for example pulling
the bytes from a number of locations. One example is loading a module from
the filesystem:
let engine = Engine::default();
let module = Module::from_file(&engine, "path/to/foo.wasm")?;
You can also load the wasm text format if more convenient too:
let engine = Engine::default();
// Now we're using the WebAssembly text extension: `.wat`!
let module = Module::from_file(&engine, "path/to/foo.wat")?;
And if you’ve already got the bytes in-memory you can use the
Module::new
constructor:
let engine = Engine::default();
let module = Module::new(&engine, &wasm_bytes)?;
// It also works with the text format!
let module = Module::new(&engine, "(module (func))")?;
Serializing and deserializing a module looks like:
let engine = Engine::default();
let module = Module::new(&engine, &wasm_bytes)?;
let module_bytes = module.serialize()?;
// ... can save `module_bytes` to disk or other storage ...
// recreate the module from the serialized bytes. For the `unsafe` bits
// see the documentation of `deserialize`.
let module = unsafe { Module::deserialize(&engine, &module_bytes)? };
Implementations§
§impl Module
impl Module
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module, Error>
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module, Error>
Creates a new WebAssembly Module
from the given in-memory bytes
.
The bytes
provided must be in one of the following formats:
- A binary-encoded WebAssembly module. This is always supported.
- A text-encoded instance of the WebAssembly text format.
This is only supported when the
wat
feature of this crate is enabled. If this is supplied then the text format will be parsed before validation. Note that thewat
feature is enabled by default.
The data for the wasm module must be loaded in-memory if it’s present elsewhere, for example on disk. This requires that the entire binary is loaded into memory all at once, this API does not support streaming compilation of a module.
The WebAssembly binary will be decoded and validated. It will also be
compiled according to the configuration of the provided engine
.
§Errors
This function may fail and return an error. Errors may include situations such as:
- The binary provided could not be decoded because it’s not a valid WebAssembly binary
- The WebAssembly binary may not validate (e.g. contains type errors)
- Implementation-specific limits were exceeded with a valid binary (for example too many locals)
- The wasm binary may use features that are not enabled in the
configuration of
engine
- If the
wat
feature is enabled and the input is text, then it may be rejected if it fails to parse.
The error returned should contain full information about why module creation failed if one is returned.
§Examples
The new
function can be invoked with a in-memory array of bytes:
let module = Module::new(&engine, &wasm_bytes)?;
Or you can also pass in a string to be parsed as the wasm text format:
let module = Module::new(&engine, "(module (func))")?;
pub fn from_file(
engine: &Engine,
file: impl AsRef<Path>,
) -> Result<Module, Error>
pub fn from_file( engine: &Engine, file: impl AsRef<Path>, ) -> Result<Module, Error>
Creates a new WebAssembly Module
from the contents of the given
file
on disk.
This is a convenience function that will read the file
provided and
pass the bytes to the Module::new
function. For more information
see Module::new
§Examples
let engine = Engine::default();
let module = Module::from_file(&engine, "./path/to/foo.wasm")?;
The .wat
text format is also supported:
let module = Module::from_file(&engine, "./path/to/foo.wat")?;
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module, Error>
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module, Error>
Creates a new WebAssembly Module
from the given in-memory binary
data.
This is similar to Module::new
except that it requires that the
binary
input is a WebAssembly binary, the text format is not supported
by this function. It’s generally recommended to use Module::new
, but
if it’s required to not support the text format this function can be
used instead.
§Examples
let wasm = b"\0asm\x01\0\0\0";
let module = Module::from_binary(&engine, wasm)?;
Note that the text format is not accepted by this function:
assert!(Module::from_binary(&engine, b"(module)").is_err());
pub unsafe fn from_trusted_file(
engine: &Engine,
file: impl AsRef<Path>,
) -> Result<Module, Error>
pub unsafe fn from_trusted_file( engine: &Engine, file: impl AsRef<Path>, ) -> Result<Module, Error>
Creates a new WebAssembly Module
from the contents of the given file
on disk, but with assumptions that the file is from a trusted source.
The file should be a binary- or text-format WebAssembly module, or a
precompiled artifact generated by the same version of Wasmtime.
§Unsafety
All of the reasons that deserialize
is unsafe
apply to this
function as well. Arbitrary data loaded from a file may trick Wasmtime
into arbitrary code execution since the contents of the file are not
validated to be a valid precompiled module.
Additionally though this function is also unsafe
because the file
referenced must remain unchanged and a valid precompiled module for the
entire lifetime of the Module
returned. Any changes to the file on
disk may change future instantiations of the module to be incorrect.
This is because the file is mapped into memory and lazily loaded pages
reflect the current state of the file, not necessarily the original
state of the file.
pub unsafe fn deserialize(
engine: &Engine,
bytes: impl AsRef<[u8]>,
) -> Result<Module, Error>
pub unsafe fn deserialize( engine: &Engine, bytes: impl AsRef<[u8]>, ) -> Result<Module, Error>
Deserializes an in-memory compiled module previously created with
Module::serialize
or Engine::precompile_module
.
This function will deserialize the binary blobs emitted by
Module::serialize
and Engine::precompile_module
back into an
in-memory Module
that’s ready to be instantiated.
Note that the Module::deserialize_file
method is more optimized than
this function, so if the serialized module is already present in a file
it’s recommended to use that method instead.
§Unsafety
This function is marked as unsafe
because if fed invalid input or used
improperly this could lead to memory safety vulnerabilities. This method
should not, for example, be exposed to arbitrary user input.
The structure of the binary blob read here is only lightly validated
internally in wasmtime
. This is intended to be an efficient
“rehydration” for a Module
which has very few runtime checks beyond
deserialization. Arbitrary input could, for example, replace valid
compiled code with any other valid compiled code, meaning that this can
trivially be used to execute arbitrary code otherwise.
For these reasons this function is unsafe
. This function is only
designed to receive the previous input from Module::serialize
and
Engine::precompile_module
. If the exact output of those functions
(unmodified) is passed to this function then calls to this function can
be considered safe. It is the caller’s responsibility to provide the
guarantee that only previously-serialized bytes are being passed in
here.
Note that this function is designed to be safe receiving output from
any compiled version of wasmtime
itself. This means that it is safe
to feed output from older versions of Wasmtime into this function, in
addition to newer versions of wasmtime (from the future!). These inputs
will deterministically and safely produce an Err
. This function only
successfully accepts inputs from the same version of wasmtime
, but the
safety guarantee only applies to externally-defined blobs of bytes, not
those defined by any version of wasmtime. (this means that if you cache
blobs across versions of wasmtime you can be safely guaranteed that
future versions of wasmtime will reject old cache entries).
pub unsafe fn deserialize_file(
engine: &Engine,
path: impl AsRef<Path>,
) -> Result<Module, Error>
pub unsafe fn deserialize_file( engine: &Engine, path: impl AsRef<Path>, ) -> Result<Module, Error>
Same as deserialize
, except that the contents of path
are read to
deserialize into a Module
.
This method is provided because it can be faster than deserialize
since the data doesn’t need to be copied around, but rather the module
can be used directly from an mmap’d view of the file provided.
§Unsafety
All of the reasons that deserialize
is unsafe
applies to this
function as well. Arbitrary data loaded from a file may trick Wasmtime
into arbitrary code execution since the contents of the file are not
validated to be a valid precompiled module.
Additionally though this function is also unsafe
because the file
referenced must remain unchanged and a valid precompiled module for the
entire lifetime of the Module
returned. Any changes to the file on
disk may change future instantiations of the module to be incorrect.
This is because the file is mapped into memory and lazily loaded pages
reflect the current state of the file, not necessarily the original
state of the file.
pub unsafe fn deserialize_open_file(
engine: &Engine,
file: File,
) -> Result<Module, Error>
pub unsafe fn deserialize_open_file( engine: &Engine, file: File, ) -> Result<Module, Error>
Same as deserialize_file
, except that it takes an open File
instead of a path.
This method is provided because it can be used instead of
deserialize_file
in situations where wasmtime
is running with
limited file system permissions. In that case a process
with file system access can pass already opened files to wasmtime
.
Note that the corresponding will be mapped as private writeable
(copy-on-write) and executable. For windows
this means the file needs
to be opened with at least FILE_GENERIC_READ | FILE_GENERIC_EXECUTE
access_mode
.
§Unsafety
All of the reasons that deserialize_file
is unsafe
applies to this
function as well.
pub fn validate(engine: &Engine, binary: &[u8]) -> Result<(), Error>
pub fn validate(engine: &Engine, binary: &[u8]) -> Result<(), Error>
Validates binary
input data as a WebAssembly binary given the
configuration in engine
.
This function will perform a speedy validation of the binary
input
WebAssembly module (which is in binary form, the text format
is not accepted by this function) and return either Ok
or Err
depending on the results of validation. The engine
argument indicates
configuration for WebAssembly features, for example, which are used to
indicate what should be valid and what shouldn’t be.
Validation automatically happens as part of Module::new
.
§Errors
If validation fails for any reason (type check error, usage of a feature that wasn’t enabled, etc) then an error with a description of the validation issue will be returned.
pub fn serialize(&self) -> Result<Vec<u8>, Error>
pub fn serialize(&self) -> Result<Vec<u8>, Error>
Serializes this module to a vector of bytes.
This function is similar to the Engine::precompile_module
method
where it produces an artifact of Wasmtime which is suitable to later
pass into Module::deserialize
. If a module is never instantiated
then it’s recommended to use Engine::precompile_module
instead of
this method, but if a module is both instantiated and serialized then
this method can be useful to get the serialized version without
compiling twice.
pub fn name(&self) -> Option<&str>
pub fn name(&self) -> Option<&str>
Returns identifier/name that this Module
has. This name
is used in traps/backtrace details.
Note that most LLVM/clang/Rust-produced modules do not have a name associated with them, but other wasm tooling can be used to inject or add a name.
§Examples
let module = Module::new(&engine, "(module $foo)")?;
assert_eq!(module.name(), Some("foo"));
let module = Module::new(&engine, "(module)")?;
assert_eq!(module.name(), None);
pub fn imports<'module>(&'module self) -> impl ExactSizeIterator + 'module
pub fn imports<'module>(&'module self) -> impl ExactSizeIterator + 'module
Returns the list of imports that this Module
has and must be
satisfied.
This function returns the list of imports that the wasm module has, but
only the types of each import. The type of each import is used to
typecheck the Instance::new
method’s imports
argument. The arguments to that function must match up 1-to-1 with the
entries in the array returned here.
The imports returned reflect the order of the imports in the wasm module itself, and note that no form of deduplication happens.
§Examples
Modules with no imports return an empty list here:
let module = Module::new(&engine, "(module)")?;
assert_eq!(module.imports().len(), 0);
and modules with imports will have a non-empty list:
let wat = r#"
(module
(import "host" "foo" (func))
)
"#;
let module = Module::new(&engine, wat)?;
assert_eq!(module.imports().len(), 1);
let import = module.imports().next().unwrap();
assert_eq!(import.module(), "host");
assert_eq!(import.name(), "foo");
match import.ty() {
ExternType::Func(_) => { /* ... */ }
_ => panic!("unexpected import type!"),
}
pub fn exports<'module>(&'module self) -> impl ExactSizeIterator + 'module
pub fn exports<'module>(&'module self) -> impl ExactSizeIterator + 'module
Returns the list of exports that this Module
has and will be
available after instantiation.
This function will return the type of each item that will be returned
from Instance::exports
. Each entry in this
list corresponds 1-to-1 with that list, and the entries here will
indicate the name of the export along with the type of the export.
§Examples
Modules might not have any exports:
let module = Module::new(&engine, "(module)")?;
assert!(module.exports().next().is_none());
When the exports are not empty, you can inspect each export:
let wat = r#"
(module
(func (export "foo"))
(memory (export "memory") 1)
)
"#;
let module = Module::new(&engine, wat)?;
assert_eq!(module.exports().len(), 2);
let mut exports = module.exports();
let foo = exports.next().unwrap();
assert_eq!(foo.name(), "foo");
match foo.ty() {
ExternType::Func(_) => { /* ... */ }
_ => panic!("unexpected export type!"),
}
let memory = exports.next().unwrap();
assert_eq!(memory.name(), "memory");
match memory.ty() {
ExternType::Memory(_) => { /* ... */ }
_ => panic!("unexpected export type!"),
}
pub fn get_export(&self, name: &str) -> Option<ExternType>
pub fn get_export(&self, name: &str) -> Option<ExternType>
Looks up an export in this Module
by name.
This function will return the type of an export with the given name.
§Examples
There may be no export with that name:
let module = Module::new(&engine, "(module)")?;
assert!(module.get_export("foo").is_none());
When there is an export with that name, it is returned:
let wat = r#"
(module
(func (export "foo"))
(memory (export "memory") 1)
)
"#;
let module = Module::new(&engine, wat)?;
let foo = module.get_export("foo");
assert!(foo.is_some());
let foo = foo.unwrap();
match foo {
ExternType::Func(_) => { /* ... */ }
_ => panic!("unexpected export type!"),
}
pub fn get_export_index(&self, name: &str) -> Option<ModuleExport>
pub fn get_export_index(&self, name: &str) -> Option<ModuleExport>
Looks up an export in this Module
by name to get its index.
This function will return the index of an export with the given name. This can be useful
to avoid the cost of looking up the export by name multiple times. Instead the
ModuleExport
can be stored and used to look up the export on the
Instance
later.
pub fn resources_required(&self) -> ResourcesRequired
pub fn resources_required(&self) -> ResourcesRequired
Returns a summary of the resources required to instantiate this
Module
.
Potential uses of the returned information:
-
Determining whether your pooling allocator configuration supports instantiating this module.
-
Deciding how many of which
Module
you want to instantiate within a fixed amount of resources, e.g. determining whether to create 5 instances of module X or 10 instances of module Y.
§Example
use wasmtime::{Config, Engine, Module};
let mut config = Config::new();
config.wasm_multi_memory(true);
let engine = Engine::new(&config)?;
let module = Module::new(&engine, r#"
(module
;; Import a memory. Doesn't count towards required resources.
(import "a" "b" (memory 10))
;; Define two local memories. These count towards the required
;; resources.
(memory 1)
(memory 6)
)
"#)?;
let resources = module.resources_required();
// Instantiating the module will require allocating two memories, and
// the maximum initial memory size is six Wasm pages.
assert_eq!(resources.num_memories, 2);
assert_eq!(resources.max_initial_memory_size, Some(6));
// The module doesn't need any tables.
assert_eq!(resources.num_tables, 0);
assert_eq!(resources.max_initial_table_size, None);
pub fn image_range(&self) -> Range<*const u8> ⓘ
pub fn image_range(&self) -> Range<*const u8> ⓘ
Returns the range of bytes in memory where this module’s compilation image resides.
The compilation image for a module contains executable code, data, debug
information, etc. This is roughly the same as the Module::serialize
but not the exact same.
The range of memory reported here is exposed to allow low-level
manipulation of the memory in platform-specific manners such as using
mlock
to force the contents to be paged in immediately or keep them
paged in after they’re loaded.
It is not safe to modify the memory in this range, nor is it safe to modify the protections of memory in this range.
pub fn initialize_copy_on_write_image(&self) -> Result<(), Error>
pub fn initialize_copy_on_write_image(&self) -> Result<(), Error>
Force initialization of copy-on-write images to happen here-and-now instead of when they’re requested during first instantiation.
When copy-on-write memory initialization is enabled then Wasmtime will lazily create the initialization image for a module. This method can be used to explicitly dictate when this initialization happens.
Note that this largely only matters on Linux when memfd is used. Otherwise the copy-on-write image typically comes from disk and in that situation the creation of the image is trivial as the image is always sourced from disk. On Linux, though, when memfd is used a memfd is created and the initialization image is written to it.
Also note that this method is not required to be called, it’s available as a performance optimization if required but is otherwise handled automatically.
pub fn address_map<'a>(
&'a self,
) -> Option<impl Iterator<Item = (usize, Option<u32>)> + 'a>
pub fn address_map<'a>( &'a self, ) -> Option<impl Iterator<Item = (usize, Option<u32>)> + 'a>
Get the map from .text
section offsets to Wasm binary offsets for this
module.
Each entry is a (.text
section offset, Wasm binary offset) pair.
Entries are yielded in order of .text
section offset.
Some entries are missing a Wasm binary offset. This is for code that is not associated with any single location in the Wasm binary, or for when source information was optimized away.
Not every module has an address map, since address map generation can be
turned off on Config
.
There is not an entry for every .text
section offset. Every offset
after an entry’s offset, but before the next entry’s offset, is
considered to map to the same Wasm binary offset as the original
entry. For example, the address map will not contain the following
sequence of entries:
[
// ...
(10, Some(42)),
(11, Some(42)),
(12, Some(42)),
(13, Some(43)),
// ...
]
Instead, it will drop the entries for offsets 11
and 12
since they
are the same as the entry for offset 10
:
[
// ...
(10, Some(42)),
(13, Some(43)),
// ...
]
pub fn text(&self) -> &[u8] ⓘ
pub fn text(&self) -> &[u8] ⓘ
Get this module’s code object’s .text
section, containing its compiled
executable code.
pub fn functions<'a>(&'a self) -> impl ExactSizeIterator + 'a
pub fn functions<'a>(&'a self) -> impl ExactSizeIterator + 'a
Get information about functions in this module’s .text
section: their
index, name, and offset+length.
Results are yielded in a ModuleFunction struct.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Module
impl !RefUnwindSafe for Module
impl Send for Module
impl Sync for Module
impl Unpin for Module
impl !UnwindSafe for Module
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more