Install the wasmtime gem
mainYou can install wasmtime-rb by adding it to your Gemfile or via the command line.
To use with Bundler:
gem "wasmtime"To install manually:
gem install wasmtimegem "wasmtime"repository·main·Indexed 40 days ago
https://github.com/bytecodealliance/wasmtime-rbA Ruby embedding of the Wasmtime runtime (version 48.0.1) that allows Ruby developers to execute WebAssembly modules and components with minimal overhead. It provides APIs for engine configuration, AoT compilation, and the WebAssembly component model, including type mapping between Wasm and Ruby objects.
You can install wasmtime-rb by adding it to your Gemfile or via the command line.
To use with Bundler:
gem "wasmtime"To install manually:
gem install wasmtimegem "wasmtime"To avoid slow and unreliable source compilations, use the precompiled gems for Linux, macOS, and Windows. When using Bundler, you should lock your bundle to the specific platforms you intend to deploy to using bundle lock --add-platform.
Supported platforms include:
x86_64-linux: Standard Linux (e.g., Heroku, GitHub Actions)x86_64-linux-musl: MUSL Linux (e.g., Alpine Linux)aarch64-linux: ARM64 Linux (e.g., AWS Graviton2)x86_64-darwin: Intel MacOSarm64-darwin: Apple Silicon MacOS (e.g., M1)bundle lock --add-platform x86_64-linux
bundle lock --add-platform x86_64-linux-musl
bundle lock --add-platform aarch64-linux
bundle lock --add-platform x86_64-darwin
bundle lock --add-platform arm64-darwinThe Wasmtime::PoolingAllocationConfig class provides configuration options used with an engine's allocation_strategy to modify the behavior of the pooling instance allocator. This is used to tune memory, tables, stacks, and instance limits for the Wasmtime runtime.
You can create a new configuration object using Wasmtime::PoolingAllocationConfig.new and then use setter methods to configure its properties.
config = Wasmtime::PoolingAllocationConfig.new do |c|
c.total_memories = 10
c.max_memory_size = 1024 * 1024
endWhen calling Wasm functions, you can control how the Ruby Global VM Lock (GVL) is handled. By default, Wasmtime::Func operations hold the GVL.
Use without_gvl to obtain a version of the function that releases the GVL during execution. This is useful for long-running Wasm computations that you want to allow other Ruby threads to run concurrently.
The Linker manages the global state of imports. To define imports, you use a block-based API that yields a LinkerInstance.
LinkerInstance objects are ephemeral builders. They are only valid within the block they are yielded to. Once the block finishes, the instance becomes unusable. This pattern ensures that the hierarchical structure of imports (namespaces) is correctly scoped.
linker.root { |instance| ... } to define imports at the top level.linker.instance("namespace") { |instance| ... } to define imports within a specific namespace.instance.instance("sub-namespace") { |nested| ... } to create nested namespaces.The Wasmtime::Component module provides the entry point for component-related functionality. It includes several key classes for interacting with components:
Wasmtime::Component::Component: The core WebAssembly component object.Wasmtime::Component::Linker: Used to define imports for instantiating components.Wasmtime::Component::Instance: Represents an instantiated component.Wasmtime::Component::Func: Represents a function within a component.Wasmtime::Component::WasiCommand: Specifically for WASI command components.The following workflow demonstrates how to initialize a Wasmtime environment, compile a module from WAT (WebAssembly Text format), define a Ruby-based function to be imported by the Wasm module, and execute the module.
require "wasmtime"
# 1. Create an engine (re-use throughout your program)
engine = Wasmtime::Engine.new
# 2. Compile a Wasm module from Wasm or WAT
mod = Wasmtime::Module.new(engine, <<~WAT)
(module
(func $hello (import "" "hello"))
(func (export "run") (call $hello))
)
WAT
# 3. Create a store to hold state
store = Wasmtime::Store.new(engine, {count: 0})
# 4. Define a Wasm function using Ruby code
func = Wasmtime::Func.new(store, [], []) do |caller|
puts "Hello from Func!"
caller.store_data[:count] += 1
puts "Ran #{caller.store_data[:count]} time(s)"
end
# 5. Build the Wasm instance by providing imports
instance = Wasmtime::Instance.new(store, mod, [func])
# 6. Run the exported function
instance.invoke("run")
# Alternatively, get the export and call it directly:
# instance.export("run").to_func.callWhen working with wasmtime-rb, errors are organized in a hierarchy under Wasmtime::Error. You should catch specific error types to handle different failure modes:
Wasmtime::ResultError: Occurs when a Ruby-backed function fails to convert its return value into Wasm-compatible types.Wasmtime::ConversionError: Occurs when attempting to convert a Wasmtime::Extern to a concrete type fails.Wasmtime::Trap: Occurs when the WebAssembly execution hits a trap (a runtime error). This class includes several specific trap types that can be identified.Wasmtime::WasiExit: Occurs when a WASI program terminates early by calling exit. You can retrieve the exit code from this error.You can create a new WebAssembly memory instance by calling Wasmtime::Memory.new. This requires a Store instance and optional keyword arguments for memory limits. Memory limits are defined in terms of pages.
Arguments:
store: A Wasmtime::Store instance.min_size:: (Required) The minimum number of memory pages.max_size:: (Optional) The maximum number of memory pages.# Example of creating a memory with 10 minimum pages and 100 maximum pages
memory = Wasmtime::Memory.new(store, min_size: 10, max_size: 100)Once a Wasmtime::Table is created, you can interact with its elements using get, set, and grow.
# Get an element at a specific index (returns nil if out of bounds)
value = table.get(0)
# Set an element at a specific index
table.set(0, new_value)
# Grow the table by a delta, providing an initial value for new slots
table.grow(5, initial_value)
# Get the current size of the table
current_size = table.sizeCreate a new Wasmtime::Engine instance by passing a configuration hash. The engine is the core execution environment for Wasmtime. You typically only need one engine per program and can reuse it across multiple stores and instances.
Note on Parallel Compilation and Forking:
If your Ruby server uses a pre-forking mechanism (like Unicorn or Puma in certain modes), you must disable parallel_compilation in any engine created before the fork. Compiling Wasm with parallel compilation enabled prior to Process.fork can cause deadlocks. You can safely enable it in engines created after the fork.
# Disabling parallel compilation for pre-forking environments
prefork_engine = Wasmtime::Engine.new(parallel_compilation: false)
wasm_module = Wasmtime::Module.new(prefork_engine, "(module)")
fork do
# Enable parallel compilation after forking
engine = Wasmtime::Engine.new(parallel_compilation: true)
store = Wasmtime::Store.new(engine)
instance = Wasmtime::Instance.new(store, wasm_module)
endThe Wasmtime::Func class provides methods to inspect the signature of the specific function instance.
params: Returns an Array<Symbol> of the function's parameter types.results: Returns an Array<Symbol> of the function's result types.