6.4 KiB
Migrating from Wasmer 2.x to Wasmer 3.0.0
This document will describe the differences between Wasmer 2.x and Wasmer 3.0.0 and provide examples to make migrating to the new API as simple as possible.
Table of Contents
Rationale for changes in 3.0.0
This version introduces the following changes to make the Wasmer API more ergonomic and safe:
ImportsObjectand the traitsResolver,NamedResolver, etc have been removed and replaced with a single simple typeImports. This reduces the complexity of setting up anInstance. The helper macroimports!can still be used.- There is a new
Contextthat goes along theStore. TheContextwill keep track of all memory and functions used, removing old tracking and Weak/Strong pointer difference. Every function and memory that is retreive is linked to a specificContext, and cannot be mixed with anotherContext WasmerEnvand associated traits and macro have been removed. To use Environenment, a simple structure now need to be attached to theContext, and can be retreive from currentContext. All functions now takes a mendatory first argument that is of typeContextMut<_>, with_being either nothing()or the Environement type needed. the function creationXXX_with_env(...)don't exist anymore, simply useFunction::new(...)orFunction::native_new(...)with the correctContextMut<_>type. Because theWasmerEnvand all helpers don't exists anymore, you have to import memory yourself, there isn't any per instance initialisation automatically done anymore. It's especialy important for WasiEnv context.Envcan be accessed from aContextusingContext::data()orContext::data_mut().- The
Engines API has been simplified, Instead of thewasmeruser choosing and setting up an engine explicitly, everything now uses the universal engine. All functionalites of thestaticlib,dylibEngines should be available unless explicitly stated as unsupported.
How to use Wasmer 3.0.0
Installing Wasmer CLI
See wasmer.io for installation instructions.
If you already have wasmer installed, run wasmer self-update.
Install the latest versions of Wasmer with wasmer-nightly or by following the steps described in the documentation: Getting Started.
Using Wasmer 3.0.0
See the examples to find out how to do specific things in Wasmer 3.0.0.
Project Structure
TODO
Differences
Creating a Context
You need a Store to create a context. Simple context is created using:
let ctx = Context::new(&store, ());
For a Context with a custom Env, it will be similar:
#[derive(Clone)]
struct Env {
counter: i32,
}
let ctx = Context::new(&store, Env{counter: 0});
Managing imports
Instantiating a Wasm module is similar to 2.x with just the need of a context as difference:
let import_object: Imports = imports! {
"env" => {
"host_function" => host_function,
},
};
let instance = Instance::new(&mut ctx, &module, &import_object).expect("Could not instantiate module.");
You can also build the Imports object manually:
let mut import_object: Imports = Imports::new();
import_object.define("env", "host_function", host_function);
let instance = Instance::new(&mut ctx, &module, &import_object).expect("Could not instantiate module.");
For WASI, don't forget to import memory to WasiEnv
let mut wasi_env = WasiState::new("hello").finalize()?;
let mut ctx = Context::new(&store, wasi_env.clone());
let import_object = wasi_env.import_object(&mut ctx.as_context_mut(), &module)?;
let instance = Instance::new(&mut ctx, &module, &import_object).expect("Could not instantiate module.");
let memory = instance.exports.get_memory("memory")?;
ctx.data_mut().set_memory(memory.clone());
ChainableNamedResolver is removed
Chaining imports with a trait has been deemed too complex for what it does; it's possible to chain (i.e. override) an Imports' contents by using its implementation of std::iter::Extend from the Rust standard library:
let imports1: Imports = todo!();
let mut imports2: Imports = todo!();
imports2.extend(&imports);
// This is equivalent to the following:
// for ((ns, name), ext) in imports1.into_iter() {
// imports2.define(&ns &name, ext);
// }
Engines
Before
In Wasmer 2.0, you had to explicitly define the Engine you want to use:
let wasm_bytes = wat2wasm(
"..".as_bytes(),
)?;
let compiler_config = Cranelift::default();
let engine = Universal::new(compiler_config).engine();
let store = Store::new(&engine);
let module = Module::new(&store, wasm_bytes)?;
let instance = Instance::new(&module, &imports! {})?;
After
In Wasmer 3.0, there's only the universal engine. The user can ignore the engine details when using the API:
let wasm_bytes = wat2wasm(
"..".as_bytes(),
)?;
let compiler_config = Cranelift::default();
let store = Store::new(&compiler_config);
let module = Module::new(&store, wasm_bytes)?;
let instance = Instance::new(&module, &imports! {})?;