Wasmex.Module (wasmex v0.9.1)
A compiled WebAssembly module.
A Wasm Module contains stateless WebAssembly code that has already been compiled and can be instantiated multiple times.
Summary
Functions
Compiles a Wasm module from it's Wasm (a .wasm file) or WAT (a .wat file) representation.
Lists all exports of a Wasm module.
Lists all imports of a WebAssembly module grouped by their module namespace.
Returns the name of the current module if a name is given.
Serializes a compiled Wasm module into a binary.
Deserializes an in-memory compiled module previously created with
Wasmex.Module.serialize/1
or Wasmex.Engine::precompile_module/2
.
Types
Functions
compile(store_or_caller, bytes)
@spec compile(Wasmex.StoreOrCaller.t(), binary()) :: {:ok, t()} | {:error, binary()}
Compiles a Wasm module from it's Wasm (a .wasm file) or WAT (a .wat file) representation.
Compiled modules can be instantiated using Wasmex.start_link/1
or Instance.new/3
.
Since module compilation takes time and resources but instantiation is comparatively cheap, it may be a good idea to compile a module once and instantiate it often if you want to run a Wasm binary multiple times.
Example
Read a Wasm file and compile it into a Wasm module.
Use the compiled module to start a running Wasmex.Instance
.
iex> {:ok, store} = Wasmex.Store.new()
iex> {:ok, module} = Wasmex.Module.compile(store, File.read!(TestHelper.wasm_test_file_path()))
iex> {:ok, _pid} = Wasmex.start_link(%{store: store, module: module})
Modules can be compiled from WAT (WebAssembly Text) format:
iex> wat = "(module)" # minimal and not very useful
iex> {:ok, store} = Wasmex.Store.new()
iex> {:ok, %Wasmex.Module{}} = Wasmex.Module.compile(store, wat)
exports(module)
Lists all exports of a Wasm module.
Returns a map which has the exports name (string) as key and export info-tuples as values. Info tuples always start with an atom indicating the exports type:
:fn
(function):global
:table
:memory
Further parts of the info tuple vary depending on the type.
Example
List the exported function "hello_world()" of a Wasm module:
iex> {:ok, store} = Wasmex.Store.new()
iex> wat = "(module
...> (func $helloWorld (result i32) (i32.const 42))
...> (export \"hello_world\" (func $helloWorld))
...> )"
iex> {:ok, module} = Wasmex.Module.compile(store, wat)
iex> Wasmex.Module.exports(module)
%{
"hello_world" => {:fn, [], [:i32]},
}
imports(module)
Lists all imports of a WebAssembly module grouped by their module namespace.
Returns a map of namespace names to namespaces with each namespace being a map again. A namespace is a map of imports with the import name as key and and info-tuple as value.
Info tuples always start with an atom indicating the imports type:
:fn
(function):global
:table
:memory
Further parts of the info tuple vary depending on the type.
Example
Show that the Wasm module imports a function "inspect" from the "IO" namespace:
iex> {:ok, store} = Wasmex.Store.new()
iex> wat = "(module
...> (import \"IO\" \"inspect\" (func $log (param i32)))
...> )"
iex> {:ok, module} = Wasmex.Module.compile(store, wat)
iex> Wasmex.Module.imports(module)
%{
"IO" => %{
"inspect" => {:fn, [:i32], []},
}
}
name(module)
Returns the name of the current module if a name is given.
This name is normally set in the Wasm bytecode by some compilers.
Example
iex> {:ok, store} = Wasmex.Store.new()
iex> wat = "(module $hiFromTheDocs)" # minimal and not very useful Wasm module
iex> {:ok, module} = Wasmex.Module.compile(store, wat)
iex> Wasmex.Module.name(module)
"hiFromTheDocs"
serialize(module)
Serializes a compiled Wasm module into a binary.
The generated binary can be deserialized back into a module using unsafe_deserialize/1
.
It is unsafe do alter the binary in any way. See unsafe_deserialize/1
for safety considerations.
Example
Serializes a compiled module:
iex> {:ok, store} = Wasmex.Store.new()
iex> {:ok, module} = Wasmex.Module.compile(store, File.read!(TestHelper.wasm_test_file_path()))
iex> {:ok, serialized} = Wasmex.Module.serialize(module)
iex> is_binary(serialized)
true
unsafe_deserialize(bytes, engine \\ nil)
@spec unsafe_deserialize(binary(), Wasmex.Engine.t() | nil) :: {:ok, t()} | {:error, binary()}
Deserializes an in-memory compiled module previously created with
Wasmex.Module.serialize/1
or Wasmex.Engine::precompile_module/2
.
This function will deserialize the binary blobs emitted by
Wasmex.Module.serialize/1
and Wasmex.Engine::precompile_module/2
back into an in-memory Wasmex.Module
that's ready to be instantiated.
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 Wasmex.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 Wasmex.Module.serialize/1
and Wasmex.Engine::precompile_module/2
. 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 error. This function only
successfully accepts inputs from the same 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).
It is best to deserialize modules using an Engine with the same configuration as the one used to serialize/precompile it.
Example
Serializes a compiled module and deserializes it again:
iex> {:ok, store} = Wasmex.Store.new()
iex> {:ok, module} = Wasmex.Module.compile(store, File.read!(TestHelper.wasm_test_file_path()))
iex> {:ok, serialized} = Wasmex.Module.serialize(module)
iex> {:ok, %Wasmex.Module{}} = Wasmex.Module.unsafe_deserialize(serialized)