Struct wasmtime::Module

source ·
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.

Creating a Module currently involves compiling code, meaning that it can be an expensive operation. All Module instances are compiled according to the configuration in Config, but typically they’re JIT-compiled. If you’d like to instantiate a module multiple times you can do so with compiling the original wasm module only once with a single Module instance.

The 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))")?;

Implementations§

source§

impl Module

source

pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module>

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 the wat 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.

If the module has not been already been compiled, 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))")?;
source

pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module>

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")?;
source

pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module>

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());
source

pub unsafe fn deserialize( engine: &Engine, bytes: impl AsRef<[u8]> ) -> Result<Module>

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).

source

pub unsafe fn deserialize_file( engine: &Engine, path: impl AsRef<Path> ) -> Result<Module>

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 origianl state of the file.

source

pub fn validate(engine: &Engine, binary: &[u8]) -> Result<()>

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.

source

pub fn serialize(&self) -> Result<Vec<u8>>

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.

source

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);
source

pub fn imports<'module>( &'module self ) -> impl ExactSizeIterator<Item = ImportType<'module>> + '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!"),
}
source

pub fn exports<'module>( &'module self ) -> impl ExactSizeIterator<Item = ExportType<'module>> + '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!"),
}
source

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!"),
}
source

pub fn engine(&self) -> &Engine

Returns the Engine that this Module was compiled by.

source

pub fn image_range(&self) -> Range<usize>

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.

source

pub fn initialize_copy_on_write_image(&self) -> Result<()>

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.

Trait Implementations§

source§

impl Clone for Module

source§

fn clone(&self) -> Module

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

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> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Pointable for T

source§

const ALIGN: usize = mem::align_of::<T>()

The alignment of pointer.
§

type Init = T

The type for initializers.
source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<V, T> VZip<V> for Twhere V: MultiLane<T>,

source§

fn vzip(self) -> V