Features

View Source

What is implemented, what is refused explicitly, and what is deferred. When a feature is missing the runtime says so with an error; it does not approximate.

Implemented

AreaStatus
Compile from binary or .wat textyes, dirty CPU scheduler
WebAssembly proposalsWasmtime 48 defaults, verified by compiling probe modules: bulk memory, reference types, multi-value, SIMD, relaxed SIMD, tail calls, extended const, multi-memory, memory64, exceptions, GC and typed function references, threads and shared memories
Instantiate with host functionsyes, function imports only
Call exportsyes, i32, i64, f32, f64, v128 values
Trapsreported with class => trap and a kind per Wasmtime trap code
Interruptiontimeout option and interrupt/1, epoch based, 10 ms granularity
Memory capmemory_limit, default 256 MB, enforced by the store limiter
Table, element and instance capsmax_tables, max_table_elements, max_instances
Memory access from Erlangread_memory/3,4, write_memory/3,4, memory_size/1,2: the export named memory (or the first exported memory) by default, any exported memory by name
Precompiled modulesserialize/1 and deserialize/1, Wasmtime's .cwasm form; see precompiled
Host functions in a dedicated processhost => Pid at instantiate, handle_host_call/2 in that process
Non-blocking callscall_async/3 and await/2,3
Fuel meteringcompile(Bin, #{fuel => true}), call/4 with fuel, fuel_remaining/1; kind => out_of_fuel
Structured trapstrace on trap errors: [#{func_index, func_offset, func_name, module_name}], innermost first
Validation without compilingvalidate/1, validate/2 with options
Compile optionscompile/2: opt_level (none, speed, speed_and_size), proposals on or off, fuel; module_options/1; deserialize/2 to pick the engine
Globals and tables from Erlangglobal_get/2, global_set/3, table_size/2, table_get/3, table_set/4, table_grow/3,4
References across the boundaryfuncref, externref and GC values as ref() terms, null, {i31, N}: in calls, host signatures, globals and tables; externref/2 wraps a term; call_ref/3,4; struct_get/set, array_len/get/set; gc/1; see references
WASI stdio in memorystdin => {binary, _}, stdout/stderr => capture with read_output/1 and output_limit; args/env => inherit
Streamssend/2, close/1, inbox_limit; stdin/stdout/stderr => stream (a streamed stdout looks like a terminal to the guest, so lines leave as written); the erlang.send and erlang.recv imports; {wasmtime_stream, Ref, Kind, Bytes} to the stream process; see streams
Runtime-only buildsWASMTIME_RUNTIME_ONLY=1: no compiler, 4 MB; features/0 reports the linked library's capabilities; see building
Source build fallbacka platform without a prebuilt archive compiles the C API itself
WASI preview 1args, env, preopened dirs with read or write, stdio to file or inherited
Caller deaththe abandoned call is interrupted, queued calls proceed
Host function timeouthost_timeout, default 30 s

Execution model

  • One OS thread per instance owns the Wasmtime store. Calls are queued; one runs at a time.
  • The calling process waits in receive; it is never blocked inside a NIF while the guest runs, so schedulers are not held.
  • Host functions run in the calling process.
  • One shared engine compiles every module; instances share nothing else.
  • Erlang holds a handle; the instance itself is owned jointly by that handle and its thread. Dropping the handle tells the thread to stop and never blocks a scheduler. A caller that dies has its running call interrupted and its queued calls dropped.
  • timeout cancels the request by id: its result is dropped in the NIF, so nothing lands in the mailbox afterwards. A result that arrived just as the timeout fired is returned as the answer.

Refused explicitly

RequestError
Import the module does not provideclass => link
Non-function import from Erlangkind => unsupported_import
exnref in a call or host signature, or v128 and references in one signaturekind => unsupported_type
A reference used with another instancekind => wrong_instance
null for a non-nullable type, a reference of the wrong family, an {i31, N} out of rangekind => badarg
Memory access while the guest runskind => busy
Memory access on an instance without memorykind => no_memory
Out of range memory accesskind => out_of_bounds
Wrong argument count or typekind => badarity, kind => badarg
A host function calling the instance it runs onkind => reentrant
compile/1, {wat, _}, serialize/1 or the wasi option on a build without themkind => unavailable
fuel on a module compiled without meteringkind => fuel_disabled
A 33rd distinct compile option setkind => too_many_configurations
opt_level other than speed, or a proposal the library lacks, on a build without itkind => unavailable
Writing a constant globalkind => immutable
send/2 past inbox_limit, or after close/1kind => inbox_full, kind => closed
An imports entry for erlang.send or erlang.recvkind => reserved_import
erlang.send or erlang.recv imported with another typekind => unsupported_type
stdin => stream on a runtime-only build of a platform without a shim in priv/shimskind => unavailable

Deferred

  • Creating GC structs and arrays from Erlang. Values the guest creates can be read and written field by field; creating one needs a type handle the C API only gives for an existing value. Exception references (exnref) are not exposed.
  • Thread pool. Measured on an M-series Mac: 13,900 instantiate, call and drop cycles per second from one process, 34,500 per second from eight, with one OS thread per instance. That covers "thousands of short-lived instances per second", so a pool is not planned unless a workload shows the thread cost first. Each thread reserves a 4 MB stack.
  • Fault isolation from Wasmtime itself. A bug in Wasmtime would take the VM down, like any NIF. A mode => port running the instance in a separate OS process is the answer if that matters; same API, not built.
  • WASI preview 2 and components. Not exposed.
  • Spawning guest threads. The threads proposal validates and shared memories can be declared, but nothing lets a guest start a thread: there is no wasi-threads and no host function for it. A module is one thread.