An Erlang module with a NIF implementation to load and call web-assembly code to run within the Erlang runtime VM.
Get WebAssembly Micro Runtime
git clone https://github.com/bytecodealliance/wasm-micro-runtime
cd wasm-micro-runtime
export WASM_DIR=`pwd`
and build it with thread support
cd $WASM_DIR/product-mini/platforms/linux
mkdir build-thr-mng
cd build-thr-mng
cmake .. -DWAMR_BUILD_LIB_PTHREAD=1
make
An Erlang/OTP installation
export ERL_DIR=...
First set WASM_DIR
and ERL_DIR
like above.
Then just run make in the root of this repo.
make
$ERL_DIR/bin/erl
1> wasm_runtime_nif:init("./test.wasm").
then create an instance of the wasm module
2> M = wasm_runtime_nif:new().
Function call_raw/3
is used to call functions that use plain integer and float
types for arguments and return value. For example the add_I32
function in test.c:
int32_t add_I32(int32_t first, int32_t second)
{
return first + second;
}
can be called with call_raw
like this
2> wasm_runtime_nif:call_raw(M, add_I32, [4,7]).
11
Function call/3
is used to call functions that use the erl_nif_wasm.h
interface to read and create Erlang terms. For example function add_terms
in test.c
ERL_NIF_TERM add_terms(ErlNifEnv env, ERL_NIF_TERM arg1, ERL_NIF_TERM arg2)
{
int32_t a1, a2;
if (!enif_wasm_get_int32(env, arg1, &a1) ||
!enif_wasm_get_int32(env, arg2, &a2))
return enif_wasm_make_badarg(env);
return enif_wasm_make_int32(env, a1+a2);
}
can be called with call
like this
3> wasm_runtime_nif:call(M, add_terms, [4,7]).
11
More complex data structures can be passed as Erlang terms using the erl_nif_wasm.h interface:
4> wasm_runtime_nif:call(M, add_list_terms, [[4,6,3,7,5]]).
25
4> wasm_runtime_nif:call(M, binary_reverse, [<<1,2,3,4,5>>]).
<<5,4,3,2,1>>
Only one Erlang process (VM thread) at a time can call functions in a wasm module instance. This is by default enforced by a mutex lock (like above) or by binding the module instance to the calling Erlang process:
5> Mb = wasm_runtime_nif:new([process_bound]).
6> wasm_runtime_nif:call(Mb, add_terms, [4,7]).
11
7> self().
<0.96.0>
now crash the shell to get a new shell process
8> 1=2.
** exception error: no match of right hand side value 2
9> self().
<0.99.0>
10> wasm_runtime_nif:call(Mb, add_terms, [4,7]).
** exception error: "called by wrong process"
Different wasm module instancess can be called concurrently, but they will not share any data with each other. The only way to run purely multi-threaded wasm code is to spawn threads within the wasm code (not tested).