Wasmex (Wasmex v0.3.1)

Wasmex is an Elixir library for executing WebAssembly binaries.

WASM functions can be executed like this:

{:ok, bytes } = File.read("wasmex_test.wasm")
{:ok, instance } = Wasmex.start_link.from_bytes(bytes)

{:ok, [42]} == Wasmex.call_function(instance, "sum", [50, -8])

Memory can be read/written using Wasmex.Memory:

offset = 7
index = 4
value = 42

{:ok, memory} = Wasmex.Instance.memory(instance, :uint8, offset)
Wasmex.Memory.set(memory, index, value)
IO.puts Wasmex.Memory.get(memory, index) # 42

Link to this section Summary

Functions

Calls a function with the given name and params on the WebAssembly instance and returns its results.

Returns a specification to start this module under a supervisor.

Returns whether a function export with the given name exists in the WebAssembly instance.

Params

Finds the exported memory of the given WASM instance and returns it as a Wasmex.Memory.

Starts a GenServer which compiles and instantiates a WASM module from the given bytes and imports map.

Link to this section Functions

Link to this function

call_function(pid, name, params)

Calls a function with the given name and params on the WebAssembly instance and returns its results.

Link to this function

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

Link to this function

function_exists(pid, name)

Returns whether a function export with the given name exists in the WebAssembly instance.

Params:

  • bytes (binary): the WASM bites defining the WASM module
  • imports (map): a map defining imports. Structure is:
               %{
                 namespace_name: %{
                   import_name: {:fn, [:i32, :i32], [:i32], function_reference}
                 }
               }
Link to this function

memory(pid, type, offset)

Finds the exported memory of the given WASM instance and returns it as a Wasmex.Memory.

The memory is a collection of bytes which can be viewed and interpreted as a sequence of different (data-)types:

  • uint8 / int8 - (un-)signed 8-bit integer values
  • uint16 / int16 - (un-)signed 16-bit integer values
  • uint32 / int32 - (un-)signed 32-bit integer values

We can think of it as a list of values of the above type (where each value may be larger than a byte). The offset value can be used to start reading the memory from a chosen position.

Link to this function

start_link(bytes)

Starts a GenServer which compiles and instantiates a WASM module from the given bytes and imports map.

imports = %{
  env: %{
    add_ints: {:fn, [:i32, :i32], [:i32], fn (_context, a, b) -> a + b end},
  }
}
{:ok, bytes } = File.read("wasmex_test.wasm")
{:ok, instance } = Wasmex.start_link(%{bytes: bytes, imports: imports})

{:ok, [42]} == Wasmex.call_function(instance, "sum", [50, -8])

The imports are given as a map of namespaces. In the example above, we import the "env" namespace. Each namespace is, again, a map listing imports. Under the name add_ints, we imported a function which is represented with a tuple of:

  1. the import type: :fn (a function),
  2. the functions parameter types: [:i32, :i32],
  3. the functions return types: [:i32], and
  4. a function reference: fn (_context, a, b, c) -> a + b end

When the WASM code executes the add_ints imported function, the execution context is forwarded to the given function reference. The first param is always the call context (a Map containing e.g. the instances memory). All other params are regular parameters as specified by the parameter type list.

Valid parameter/return types are:

  • :i32 a 32 bit integer
  • :i64 a 64 bit integer
  • :f32 a 32 bit float
  • :f64 a 64 bit float

The return type must always be one value. (There are preparations to enable WASM to return multiple values from a function call. We prepared the API for this future by specifying an array of return types.)