Wasmex.Instance (wasmex v0.9.2)

Instantiates a Wasm module and allows calling exported functions on it.

In the majority of cases, you will not need to use this module directly but use the main module Wasmex instead. This module expects to be executed within GenServer context which Wasmex sets up.

Summary

Functions

Calls a function the given name exported by the Wasm instance with the given params.

Whether the Wasm instance exports a function with the given name.

Reads the value of an exported global.

Returns the Wasmex.Memory of the Wasm instance.

Instantiates a Wasm module with the given imports.

Sets the value of an exported mutable global.

Types

@type t() :: %Wasmex.Instance{reference: reference(), resource: binary()}

Functions

Link to this function

call_exported_function(store_or_caller, instance, name, params, from)

@spec call_exported_function(
  Wasmex.StoreOrCaller.t(),
  t(),
  binary(),
  [any()],
  GenServer.from()
) :: :ok | {:error, binary()}

Calls a function the given name exported by the Wasm instance with the given params.

The Wasm function will be invoked asynchronously in a new OS thread. The calling Process/GenServer will receive a {:returned_function_call, result, from} message once execution finishes. The result either is an {:error, reason} or :ok.

call_exported_function/5 assumes to be called within a GenServer context, it expects a from argument as given by GenServer.handle_call/3. from is returned unchanged to allow the wrapping GenServer to reply to their caller.

A BadArg exception may be thrown when given unexpected input data.

Function parameters

Parameters for Wasm functions are automatically casted to Wasm values. Note that WebAssembly only knows number datatypes (floats and integers of various sizes).

You can pass arbitrary data to WebAssembly by writing that data into an instances Wasmex.Memory. The memory/2 function returns the instances memory.

Example

iex> %{store: store, module: module} = TestHelper.wasm_module()
iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
iex> Wasmex.Instance.call_exported_function(store, instance, "sum", [1, 2], :from)
:ok
iex> receive do
...>   {:returned_function_call, {:ok, [3]}, :from} -> :ok
...> after
...>  1000 -> raise "message_expected"
...> end
Link to this function

function_export_exists(store_or_caller, instance, name)

@spec function_export_exists(Wasmex.StoreOrCaller.t(), t(), binary()) :: boolean()

Whether the Wasm instance exports a function with the given name.

Example

iex> %{store: store, module: module} = TestHelper.wasm_module()
iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
iex> Wasmex.Instance.function_export_exists(store, instance, "sum")
true
iex> Wasmex.Instance.function_export_exists(store, instance, "does_not_exist")
false
Link to this function

get_global_value(store_or_caller, instance, global_name)

@spec get_global_value(Wasmex.StoreOrCaller.t(), t(), binary()) ::
  {:ok, number()} | {:error, binary()}

Reads the value of an exported global.

Examples

iex> wat = "(module
...>          (global $answer i32 (i32.const 42))
...>          (export \"answer\" (global $answer))
...>        )"
iex> {:ok, store} = Wasmex.Store.new()
iex> {:ok, module} = Wasmex.Module.compile(store, wat)
iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
iex> Wasmex.Instance.get_global_value(store, instance, "answer")
{:ok, 42}
iex> Wasmex.Instance.get_global_value(store, instance, "not_a_global")
{:error, "exported global `not_a_global` not found"}
Link to this function

memory(store, instance)

@spec memory(Wasmex.StoreOrCaller.t(), t()) ::
  {:ok, Wasmex.Memory.t()} | {:error, binary()}

Returns the Wasmex.Memory of the Wasm instance.

Example

iex> %{store: store, module: module} = TestHelper.wasm_module()
iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
iex> {:ok, %Wasmex.Memory{}} = Wasmex.Instance.memory(store, instance)
Link to this function

new(store_or_caller, module, imports, links \\ [])

@spec new(
  Wasmex.StoreOrCaller.t(),
  Wasmex.Module.t(),
  %{optional(binary()) => (... -> any())},
  [%{optional(binary()) => Wasmex.Module.t()}] | []
) :: {:ok, t()} | {:error, binary()}

Instantiates a Wasm module with the given imports.

Returns the instantiated Wasm instance.

The import parameter is a nested map of Wasm namespaces. Each namespace consists of a name and a map of function names to function signatures.

The links parameter is a list of name-module pairs that are dynamically linked to the instance.

Function signatures are a tuple of the form {:fn, arg_types, return_types, callback}. Where arg_types and return_types are lists of :i32, :i64, :f32, :f64, :v128.

Each callback function receives a context map as the first argument followed by the arguments specified in its signature. context has the following keys:

  • :memory - The default exported Wasmex.Memory of the Wasm instance
  • :caller - The caller of the Wasm instance which MUST be used instead of a Wasmex.Store in all Wasmex functions called from within the callback. Failure to do so will result in a deadlock. The caller MUST NOT be used outside of the callback.

Example

This example instantiates a Wasm module with one namespace env having three imported functions imported_sum3, imported_sumf, and imported_void.

The imported function imported_sum3 takes three :i32 (32 bit integer) arguments and returns a :i32 number. Its implementation is defined by the callback function fn _context, a, b, c -> a + b + c end.

iex> %{store: store, module: module} = TestHelper.wasm_module()
iex> imports = %{
...>   "env" =>
...>     %{
...>       "imported_sum3" => {:fn, [:i32, :i32, :i32], [:i32], fn _context, a, b, c -> a + b + c end},
...>       "imported_sumf" => {:fn, [:f32, :f32], [:f32], fn _context, a, b -> a + b end},
...>       "imported_void" => {:fn, [], [], fn _context -> nil end}
...>     }
...> }
...> links = []
iex> {:ok, %Wasmex.Instance{}} = Wasmex.Instance.new(store, module, imports, links)
Link to this function

set_global_value(store_or_caller, instance, global_name, new_value)

@spec set_global_value(Wasmex.StoreOrCaller.t(), t(), binary(), number()) ::
  {:ok, number()} | {:error, binary()}

Sets the value of an exported mutable global.

Examples

iex> wat = "(module
...>          (global $count (mut i32) (i32.const 0))
...>          (export \"count\" (global $count))
...>        )"
iex> {:ok, store} = Wasmex.Store.new()
iex> {:ok, module} = Wasmex.Module.compile(store, wat)
iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
iex> Wasmex.Instance.set_global_value(store, instance, "count", 1)
:ok
iex> Wasmex.Instance.get_global_value(store, instance, "count")
{:ok, 1}