Features
View SourceWhat 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
| Area | Status |
|---|---|
Compile from binary or .wat text | yes, dirty CPU scheduler |
| WebAssembly proposals | Wasmtime 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 functions | yes, function imports only |
| Call exports | yes, i32, i64, f32, f64, v128 values |
| Traps | reported with class => trap and a kind per Wasmtime trap code |
| Interruption | timeout option and interrupt/1, epoch based, 10 ms granularity |
| Memory cap | memory_limit, default 256 MB, enforced by the store limiter |
| Table, element and instance caps | max_tables, max_table_elements, max_instances |
| Memory access from Erlang | read_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 modules | serialize/1 and deserialize/1, Wasmtime's .cwasm form; see precompiled |
| Host functions in a dedicated process | host => Pid at instantiate, handle_host_call/2 in that process |
| Non-blocking calls | call_async/3 and await/2,3 |
| Fuel metering | compile(Bin, #{fuel => true}), call/4 with fuel, fuel_remaining/1; kind => out_of_fuel |
| Structured traps | trace on trap errors: [#{func_index, func_offset, func_name, module_name}], innermost first |
| Validation without compiling | validate/1, validate/2 with options |
| Compile options | compile/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 Erlang | global_get/2, global_set/3, table_size/2, table_get/3, table_set/4, table_grow/3,4 |
| References across the boundary | funcref, 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 memory | stdin => {binary, _}, stdout/stderr => capture with read_output/1 and output_limit; args/env => inherit |
| Streams | send/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 builds | WASMTIME_RUNTIME_ONLY=1: no compiler, 4 MB; features/0 reports the linked library's capabilities; see building |
| Source build fallback | a platform without a prebuilt archive compiles the C API itself |
| WASI preview 1 | args, env, preopened dirs with read or write, stdio to file or inherited |
| Caller death | the abandoned call is interrupted, queued calls proceed |
| Host function timeout | host_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.
timeoutcancels 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
| Request | Error |
|---|---|
| Import the module does not provide | class => link |
| Non-function import from Erlang | kind => unsupported_import |
exnref in a call or host signature, or v128 and references in one signature | kind => unsupported_type |
| A reference used with another instance | kind => wrong_instance |
null for a non-nullable type, a reference of the wrong family, an {i31, N} out of range | kind => badarg |
| Memory access while the guest runs | kind => busy |
| Memory access on an instance without memory | kind => no_memory |
| Out of range memory access | kind => out_of_bounds |
| Wrong argument count or type | kind => badarity, kind => badarg |
| A host function calling the instance it runs on | kind => reentrant |
compile/1, {wat, _}, serialize/1 or the wasi option on a build without them | kind => unavailable |
fuel on a module compiled without metering | kind => fuel_disabled |
| A 33rd distinct compile option set | kind => too_many_configurations |
opt_level other than speed, or a proposal the library lacks, on a build without it | kind => unavailable |
| Writing a constant global | kind => immutable |
send/2 past inbox_limit, or after close/1 | kind => inbox_full, kind => closed |
An imports entry for erlang.send or erlang.recv | kind => reserved_import |
erlang.send or erlang.recv imported with another type | kind => unsupported_type |
stdin => stream on a runtime-only build of a platform without a shim in priv/shims | kind => 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 => portrunning 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-threadsand no host function for it. A module is one thread.