diff --git a/Cargo.toml b/Cargo.toml
index caafff5a374..5a1f672110b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -230,3 +230,18 @@ required-features = ["cranelift"]
name = "memory"
path = "examples/memory.rs"
required-features = ["cranelift"]
+
+[[example]]
+name = "instance"
+path = "examples/instance.rs"
+required-features = ["cranelift"]
+
+[[example]]
+name = "errors"
+path = "examples/errors.rs"
+required-features = ["cranelift"]
+
+[[example]]
+name = "imported-function-env"
+path = "examples/imports_function_env.rs"
+required-features = ["cranelift"]
diff --git a/examples/README.md b/examples/README.md
index 3d107cac533..ab5df284271 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -37,245 +37,288 @@ The examples are written in a difficulty/discovery order. Concepts that
are explained in an example is not necessarily re-explained in a next
example.
-### Engines
+### Basics
-1. [**JIT engine**][engine-jit], explains what an engine is, what the
- JIT engine is, and how to set it up. The example completes itself
- with the compilation of the Wasm module, its instantiation, and
- finally, by calling an exported function.
+1. [**Instantiating a module**][instance], explains the basics of using Wasmer
+ and how to create an instance out of a Wasm module.
- _Keywords_: JIT, engine, in-memory, executable code.
+ _Keywords_: instance, module.
- Execute the example
+ Execute the example
- ```shell
- $ cargo run --example engine-jit --release --features "cranelift"
- ```
+ ```shell
+ $ cargo run --example instance --release --features "cranelift"
+ ```
-2. [**Native engine**][engine-native], explains what a native engine
- is, and how to set it up. The example completes itself with the
- compilation of the Wasm module, its instantiation, and finally, by
- calling an exported function.
+2. [**Handling errors**][errors], explains the basics of interacting with
+ Wasm module memory.
- _Keywords_: native, engine, shared library, dynamic library,
- executable code.
+ _Keywords_: memory, module.
+
+
+ Execute the example
+ ```shell
+ $ cargo run --example memory --release --features "cranelift"
+ ```
+
+
+
+3. [**Interacting with memory**][memory], explains the basics of interacting with
+ Wasm module memory.
+
+ _Keywords_: memory, module.
+
- Execute the example
+ Execute the example
- ```shell
- $ cargo run --example engine-native --release --features "cranelift"
- ```
+ ```shell
+ $ cargo run --example memory --release --features "cranelift"
+ ```
-3. [**Headless engines**][engine-headless], explains what a headless
- engine is, what problem it does solve, and what are the benefits of
- it. The example completes itself with the instantiation of a
- pre-compiled Wasm module, and finally, by calling an exported
- function.
+### Exports
+
+1. [**Exported global**][exported-global], explains how to work with
+ exported globals: get/set their value, have information about their
+ type.
- _Keywords_: native, engine, constrained environment, ahead-of-time
- compilation, cross-compilation, executable code, serialization.
+ _Keywords_: export, global.
Execute the example
```shell
- $ cargo run --example engine-headless --release --features "cranelift"
+ $ cargo run --example exported-globals --release --features "cranelift"
```
-
-4. [**Cross-compilation**][cross-compilation], illustrates the power
- of the abstraction over the engines and the compilers, such as it
- is possible to cross-compile a Wasm module for a custom target.
- _Keywords_: engine, compiler, cross-compilation.
+2. [**Exported function**][exported-function], explains how to get and
+ how to call an exported function. They come in 2 flavors: dynamic,
+ and “static”/native. The pros and cons are discussed briefly.
+
+ _Keywords_: export, function, dynamic, static, native.
Execute the example
```shell
- $ cargo run --example cross-compilation --release --features "cranelift"
+ $ cargo run --example exported-function --release --features "cranelift"
```
-### Compilers
-5. [**Singlepass compiler**][compiler-singlepass], explains how to use
- the [`wasmer-compiler-singlepass`] compiler.
+3. [**Exported memory**][exported-memory], explains how to read from
+ and write to exported memory.
- _Keywords_: compiler, singlepass.
+ _Keywords_: export, memory.
Execute the example
```shell
- $ cargo run --example compiler-singlepass --release --features "singlepass"
+ $ cargo run --example exported-memory --release --features "cranelift"
```
-6. [**Cranelift compiler**][compiler-cranelift], explains how to use
- the [`wasmer-compiler-cranelift`] compiler.
+### Imports
+
+1. [**Imported global**][imported-global], explains how to work with
+ imported globals: create globals, import them, get/set their value.
- _Keywords_: compiler, cranelift.
+ _Keywords_: import, global.
Execute the example
```shell
- $ cargo run --example compiler-cranelift --release --features "cranelift"
+ $ cargo run --example imported-globals --release --features "cranelift"
```
-7. [**LLVM compiler**][compiler-llvm], explains how to use the
- [`wasmer-compiler-llvm`] compiler.
+2. [**Imported function**][imported-function], explains how to define
+ an imported function. They come in 2 flavors: dynamic,
+ and “static”/native.
- _Keywords_: compiler, llvm.
+ _Keywords_: import, function, dynamic, static, native.
Execute the example
```shell
- $ cargo run --example compiler-llvm --release --features "llvm"
+ $ cargo run --example imported-function --release --features "cranelift"
```
-### Exports
+### Externs
-8. [**Exported global**][exported-global], explains how to work with
- exported globals: get/set their value, have information about their
- type.
-
- _Keywords_: export, global.
+1. [**Table**][table], explains how to use Wasm Tables from the Wasmer API.
+
+ _Keywords_: basic, table, call_indirect
Execute the example
```shell
- $ cargo run --example exported-globals --release --features "cranelift"
+ $ cargo run --example table --release --features "cranelift"
```
-9. [**Exported function**][exported-function], explains how to get and
- how to call an exported function. They come in 2 flavors: dynamic,
- and “static”/native. The pros and cons are discussed briefly.
-
- _Keywords_: export, function, dynamic, static, native.
+2. [**Memory**][memory], explains how to use Wasm Memories from
+ the Wasmer API. Memory example is a work in progress.
+
+ _Keywords_: basic, memory
Execute the example
```shell
- $ cargo run --example exported-function --release --features "cranelift"
+ $ cargo run --example memory --release --features "cranelift"
```
+### Tunables
-10. [**Exported memory**][exported-memory], explains how to read from
- and write to exported memory.
-
- _Keywords_: export, memory.
+1. **Limit memory**, explains how to use Tunables to limit the
+ size of an exported Wasm memory
+
+ _Keywords_: basic, tunables, memory
Execute the example
```shell
- $ cargo run --example exported-memory --release --features "cranelift"
+ $ cargo run --example tunables-limit-memory --release --features "cranelift"
```
-### Imports
+### Engines
-11. [**Imported global**][imported-global], explains how to work with
- imported globals: create globals, import them, get/set their value.
+1. [**JIT engine**][engine-jit], explains what an engine is, what the
+ JIT engine is, and how to set it up. The example completes itself
+ with the compilation of the Wasm module, its instantiation, and
+ finally, by calling an exported function.
+
+ _Keywords_: JIT, engine, in-memory, executable code.
- _Keywords_: import, global.
-
Execute the example
```shell
- $ cargo run --example imported-globals --release --features "cranelift"
+ $ cargo run --example engine-jit --release --features "cranelift"
```
-12. [**Imported function**][imported-function], explains how to define
- an imported function. They come in 2 flavors: dynamic,
- and “static”/native.
+2. [**Native engine**][engine-native], explains what a native engine
+ is, and how to set it up. The example completes itself with the
+ compilation of the Wasm module, its instantiation, and finally, by
+ calling an exported function.
- _Keywords_: import, function, dynamic, static, native.
+ _Keywords_: native, engine, shared library, dynamic library,
+ executable code.
Execute the example
```shell
- $ cargo run --example imported-function --release --features "cranelift"
+ $ cargo run --example engine-native --release --features "cranelift"
```
-### Externs
+3. [**Headless engines**][engine-headless], explains what a headless
+ engine is, what problem it does solve, and what are the benefits of
+ it. The example completes itself with the instantiation of a
+ pre-compiled Wasm module, and finally, by calling an exported
+ function.
+
+ _Keywords_: native, engine, constrained environment, ahead-of-time
+ compilation, cross-compilation, executable code, serialization.
-13. [**Table**][table], explains how to use Wasm Tables from the Wasmer API.
+
+ Execute the example
- _Keywords_: basic, table, call_indirect
+ ```shell
+ $ cargo run --example engine-headless --release --features "cranelift"
+ ```
+
+
+
+4. [**Cross-compilation**][cross-compilation], illustrates the power
+ of the abstraction over the engines and the compilers, such as it
+ is possible to cross-compile a Wasm module for a custom target.
+
+ _Keywords_: engine, compiler, cross-compilation.
Execute the example
```shell
- $ cargo run --example table --release --features "cranelift"
+ $ cargo run --example cross-compilation --release --features "cranelift"
```
-
-14. [**Memory**][memory], explains how to use Wasm Memories from
- the Wasmer API. Memory example is a work in progress.
- _Keywords_: basic, memory
+### Compilers
+
+1. [**Singlepass compiler**][compiler-singlepass], explains how to use
+ the [`wasmer-compiler-singlepass`] compiler.
+
+ _Keywords_: compiler, singlepass.
Execute the example
```shell
- $ cargo run --example memory --release --features "cranelift"
+ $ cargo run --example compiler-singlepass --release --features "singlepass"
```
-### Tunables
+2. [**Cranelift compiler**][compiler-cranelift], explains how to use
+ the [`wasmer-compiler-cranelift`] compiler.
+
+ _Keywords_: compiler, cranelift.
-15. **Limit memory**, explains how to use Tunables to limit the
- size of an exported Wasm Memories
+
+ Execute the example
- _Keywords_: basic, tunables, memory
+ ```shell
+ $ cargo run --example compiler-cranelift --release --features "cranelift"
+ ```
+
+
+
+3. [**LLVM compiler**][compiler-llvm], explains how to use the
+ [`wasmer-compiler-llvm`] compiler.
+
+ _Keywords_: compiler, llvm.
Execute the example
```shell
- $ cargo run --example tunables-limit-memory --release --features "cranelift"
+ $ cargo run --example compiler-llvm --release --features "llvm"
```
-
### Integrations
-16. [**WASI**][wasi], explains how to use the [WebAssembly System
+1. [**WASI**][wasi], explains how to use the [WebAssembly System
Interface][WASI] (WASI), i.e. the [`wasmer-wasi`] crate.
_Keywords_: wasi, system, interface
@@ -301,6 +344,7 @@ example.
[exported-memory]: ./exports_memory.rs
[imported-global]: ./imports_global.rs
[imported-function]: ./imports_function.rs
+[instance]: ./instance.rs
[wasi]: ./wasi.rs
[table]: ./table.rs
[memory]: ./memory.rs
diff --git a/examples/early_exit.rs b/examples/early_exit.rs
index 814ab01ff6c..911fd3d6089 100644
--- a/examples/early_exit.rs
+++ b/examples/early_exit.rs
@@ -1,5 +1,18 @@
-//! This example shows how the host can terminate execution of Wasm early from
-//! inside a host function called by the Wasm.
+//! There are cases where you may want to interrupt this synchronous execution of the WASM module
+//! while the it is calling a host function. This can be useful for saving resources, and not
+//! returning back to the guest WASM for execution, when you already know the WASM execution will
+//! fail, or no longer be needed.
+//!
+//! In this example, we will run a WASM module that calls the imported host function
+//! interrupt_execution. This host function will immediately stop executing the WebAssembly module.
+//!
+//! You can run the example directly by executing in Wasmer root:
+//!
+//! ```shell
+//! cargo run --example early-exit --release --features "cranelift"
+//! ```
+//!
+//! Ready?
use anyhow::bail;
use std::fmt;
@@ -21,12 +34,6 @@ impl fmt::Display for ExitCode {
// And then we implement `std::error::Error`.
impl std::error::Error for ExitCode {}
-// The host function that we'll use to terminate execution.
-fn early_exit() {
- // This is where it happens.
- RuntimeError::raise(Box::new(ExitCode(1)));
-}
-
fn main() -> anyhow::Result<()> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
@@ -44,21 +51,40 @@ fn main() -> anyhow::Result<()> {
"#,
)?;
+ // Create a Store.
+ // Note that we don't need to specify the engine/compiler if we want to use
+ // the default provided by Wasmer.
+ // You can use `Store::default()` for that.
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
+
+ println!("Compiling module...");
+ // Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
+ // We declare the host function that we'll use to terminate execution.
+ fn early_exit() {
+ // This is where it happens.
+ RuntimeError::raise(Box::new(ExitCode(1)));
+ }
+
+ // Create an import object.
let import_object = imports! {
"env" => {
"early_exit" => Function::new_native(&store, early_exit),
}
};
+
+ println!("Instantiating module...");
+ // Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
+ // Here we go.
+ //
// Get the `run` function which we'll use as our entrypoint.
- let run_func: NativeFunc<(i32, i32), i32> =
- instance.exports.get_native_function("run").unwrap();
+ println!("Calling `run` function...");
+ let run_func: NativeFunc<(i32, i32), i32> = instance.exports.get_native_function("run")?;
- // When we call a function it can either succeed or fail.
+ // When we call a function it can either succeed or fail. We expect it to fail.
match run_func.call(1, 7) {
Ok(result) => {
bail!(
@@ -66,12 +92,13 @@ fn main() -> anyhow::Result<()> {
result
);
}
- // We're expecting it to fail.
- // We attempt to downcast the error into the error type that we were expecting.
+ // In case of a failure, which we expect, we attempt to downcast the error into the error
+ // type that we were expecting.
Err(e) => match e.downcast::() {
// We found the exit code used to terminate execution.
Ok(exit_code) => {
println!("Exited early with exit code: {}", exit_code);
+
Ok(())
}
Err(e) => {
diff --git a/examples/errors.rs b/examples/errors.rs
new file mode 100644
index 00000000000..fef46c26fe7
--- /dev/null
+++ b/examples/errors.rs
@@ -0,0 +1,103 @@
+//! A Wasm module can sometimes be invalid or trigger traps, and in those case we will get
+//! an error back from the API.
+//!
+//! In this example we'll see how to handle such errors in the most
+//! basic way. To do that we'll use a Wasm module that we know will
+//! produce an error.
+//!
+//! You can run the example directly by executing in Wasmer root:
+//!
+//! ```shell
+//! cargo run --example errors --release --features "cranelift"
+//! ```
+//!
+//! Ready?
+
+use wasmer::{imports, wat2wasm, Instance, Module, Store};
+use wasmer_compiler_cranelift::Cranelift;
+use wasmer_engine_jit::JIT;
+
+fn main() -> Result<(), Box> {
+ // Let's declare the Wasm module with the text representation.
+ let wasm_bytes = wat2wasm(
+ br#"
+(module
+ (type $do_div_by_zero_t (func (result i32)))
+ (func $do_div_by_zero_f (type $do_div_by_zero_t) (result i32)
+ i32.const 4
+ i32.const 0
+ i32.div_s)
+
+ (type $div_by_zero_t (func (result i32)))
+ (func $div_by_zero_f (type $div_by_zero_t) (result i32)
+ call $do_div_by_zero_f)
+ (export "div_by_zero" (func $div_by_zero_f)))
+"#,
+ )?;
+
+ // Create a Store.
+ // Note that we don't need to specify the engine/compiler if we want to use
+ // the default provided by Wasmer.
+ // You can use `Store::default()` for that.
+ let store = Store::new(&JIT::new(&Cranelift::default()).engine());
+
+ println!("Compiling module...");
+ // Let's compile the Wasm module.
+ let module = Module::new(&store, wasm_bytes)?;
+
+ // Create an import object.
+ let import_object = imports! {};
+
+ println!("Instantiating module...");
+ // Let's instantiate the Wasm module.
+ let instance = Instance::new(&module, &import_object)?;
+
+ // Here we go.
+ //
+ // The Wasm module exports a function called `div_by_zero`. As its name
+ // implies, this function will try to do a division by zero and thus
+ // produce an error.
+ //
+ // Let's get it.
+ let div_by_zero = instance
+ .exports
+ .get_function("div_by_zero")?
+ .native::<(), i32>()?;
+
+ println!("Calling `div_by_zero` function...");
+ // Let's call the `div_by_zero` exported function.
+ let result = div_by_zero.call();
+
+ // When we call a function it can either succeed or fail. We expect it to fail.
+ match result {
+ Ok(_) => {
+ // This should have thrown an error, return an error
+ panic!("div_by_zero did not error");
+ }
+ Err(e) => {
+ // Log the error
+ println!("Error caught from `div_by_zero`: {}", e.message());
+
+ // Errors come with a trace we can inspect to get more
+ // information on the execution flow.
+ let frames = e.trace();
+ let frames_len = frames.len();
+
+ for i in 0..frames_len {
+ println!(
+ " Frame #{}: {:?}::{:?}",
+ frames_len - i,
+ frames[i].module_name(),
+ frames[i].function_name().or(Some("")).unwrap()
+ );
+ }
+ }
+ }
+
+ Ok(())
+}
+
+#[test]
+fn test_exported_function() -> Result<(), Box> {
+ main()
+}
diff --git a/examples/exports_function.rs b/examples/exports_function.rs
index 941733847bb..853f3699865 100644
--- a/examples/exports_function.rs
+++ b/examples/exports_function.rs
@@ -72,10 +72,11 @@ fn main() -> Result<(), Box> {
println!("Calling `sum` function...");
// Let's call the `sum` exported function. The parameters are a
// slice of `Value`s. The results are a boxed slice of `Value`s.
- let results = sum.call(&[Value::I32(1), Value::I32(2)])?;
+ let args = [Value::I32(1), Value::I32(2)];
+ let result = sum.call(&args)?;
- println!("Results: {:?}", results);
- assert_eq!(results.to_vec(), vec![Value::I32(3)]);
+ println!("Results: {:?}", result);
+ assert_eq!(result.to_vec(), vec![Value::I32(3)]);
// That was fun. But what if we can get rid of the `Value`s? Well,
// that's possible with the `NativeFunction` API. The function
@@ -85,16 +86,16 @@ fn main() -> Result<(), Box> {
// `Rets`, respectively for the parameters and the results. If
// those values don't match the exported function signature, an
// error will be raised.
- let sum = sum.native::<(i32, i32), i32>()?;
+ let sum_native = sum.native::<(i32, i32), i32>()?;
println!("Calling `sum` function (natively)...");
// Let's call the `sum` exported function. The parameters are
// statically typed Rust values of type `i32` and `i32`. The
// result, in this case particular case, in a unit of type `i32`.
- let result = sum.call(1, 2)?;
+ let result = sum_native.call(3, 4)?;
println!("Results: {:?}", result);
- assert_eq!(result, 3);
+ assert_eq!(result, 7);
// Much nicer, isn't it?
//
diff --git a/examples/exports_global.rs b/examples/exports_global.rs
index 0ad1e9b65ac..8884a1406a7 100644
--- a/examples/exports_global.rs
+++ b/examples/exports_global.rs
@@ -68,16 +68,16 @@ fn main() -> Result<(), Box> {
let one = instance.exports.get_global("one")?;
let some = instance.exports.get_global("some")?;
- println!("Getting global type informations...");
+ println!("Getting globals types information...");
// Let's get the globals types. The results are `GlobalType`s.
let one_type = one.ty();
let some_type = some.ty();
- println!("one type: {:?} {:?}", one_type.mutability, one_type.ty);
+ println!("`one` type: {:?} {:?}", one_type.mutability, one_type.ty);
assert_eq!(one_type.mutability, Mutability::Const);
assert_eq!(one_type.ty, Type::F32);
- println!("some type: {:?} {:?}", some_type.mutability, some_type.ty);
+ println!("`some` type: {:?} {:?}", some_type.mutability, some_type.ty);
assert_eq!(some_type.mutability, Mutability::Var);
assert_eq!(some_type.ty, Type::F32);
@@ -93,14 +93,14 @@ fn main() -> Result<(), Box> {
.get_function("get_one")?
.native::<(), f32>()?;
- let one_result = get_one.call()?;
- let some_result = some.get();
+ let one_value = get_one.call()?;
+ let some_value = some.get();
- println!("one value: {:?}", one_result);
- assert_eq!(one_result, 1.0);
+ println!("`one` value: {:?}", one_value);
+ assert_eq!(one_value, 1.0);
- println!("some value: {:?}", some_result);
- assert_eq!(some_result, Value::F32(0.0));
+ println!("`some` value: {:?}", some_value);
+ assert_eq!(some_value, Value::F32(0.0));
println!("Setting global values...");
// Trying to set the value of a immutable global (`const`)
@@ -112,7 +112,7 @@ fn main() -> Result<(), Box> {
);
let one_result = one.get();
- println!("one value after `set`: {:?}", one_result);
+ println!("`one` value after `set`: {:?}", one_result);
assert_eq!(one_result, Value::F32(1.0));
// Setting the values of globals can be done in two ways:
@@ -126,12 +126,12 @@ fn main() -> Result<(), Box> {
.native::()?;
set_some.call(21.0)?;
let some_result = some.get();
- println!("some value after `set_some`: {:?}", some_result);
+ println!("`some` value after `set_some`: {:?}", some_result);
assert_eq!(some_result, Value::F32(21.0));
some.set(Value::F32(42.0))?;
let some_result = some.get();
- println!("some value after `set`: {:?}", some_result);
+ println!("`some` value after `set`: {:?}", some_result);
assert_eq!(some_result, Value::F32(42.0));
Ok(())
diff --git a/examples/imports_function.rs b/examples/imports_function.rs
index 7007b2f4f6e..56496fefe6d 100644
--- a/examples/imports_function.rs
+++ b/examples/imports_function.rs
@@ -70,7 +70,7 @@ fn main() -> Result<(), Box> {
}
let multiply_native = Function::new_native(&store, multiply);
- // Create an empty import object.
+ // Create an import object.
let import_object = imports! {
"env" => {
"multiply_dynamic" => multiply_dynamic,
diff --git a/examples/imports_function_env.rs b/examples/imports_function_env.rs
new file mode 100644
index 00000000000..88caf3c6ef7
--- /dev/null
+++ b/examples/imports_function_env.rs
@@ -0,0 +1,129 @@
+//! A Wasm module can import entities, like functions, memories,
+//! globals and tables.
+//!
+//! In this example, we'll create a system for getting and adjusting a counter value. However, host
+//! functions are not limited to storing data outside of WASM, they're normal host functions and
+//! can do anything that the host can do.
+//!
+//! 1. There will be a `get_counter` function that will return an i32 of
+//! the current global counter,
+//! 2. There will be an `add_to_counter` function will add the passed
+//! i32 value to the counter, and return an i32 of the current
+//! global counter.
+//!
+//! You can run the example directly by executing in Wasmer root:
+//!
+//! ```shell
+//! cargo run --example imported-function-env --release --features "cranelift"
+//! ```
+//!
+//! Ready?
+
+use std::cell::RefCell;
+use std::sync::Arc;
+use wasmer::{imports, wat2wasm, Function, Instance, Module, Store};
+use wasmer_compiler_cranelift::Cranelift;
+use wasmer_engine_jit::JIT;
+
+fn main() -> Result<(), Box> {
+ // Let's declare the Wasm module with the text representation.
+ let wasm_bytes = wat2wasm(
+ br#"
+(module
+ (func $get_counter (import "env" "get_counter") (result i32))
+ (func $add_to_counter (import "env" "add_to_counter") (param i32) (result i32))
+
+ (type $increment_t (func (param i32) (result i32)))
+ (func $increment_f (type $increment_t) (param $x i32) (result i32)
+ (block
+ (loop
+ (call $add_to_counter (i32.const 1))
+ (set_local $x (i32.sub (get_local $x) (i32.const 1)))
+ (br_if 1 (i32.eq (get_local $x) (i32.const 0)))
+ (br 0)))
+ call $get_counter)
+ (export "increment_counter_loop" (func $increment_f)))
+"#,
+ )?;
+
+ // Create a Store.
+ // Note that we don't need to specify the engine/compiler if we want to use
+ // the default provided by Wasmer.
+ // You can use `Store::default()` for that.
+ let store = Store::new(&JIT::new(&Cranelift::default()).engine());
+
+ println!("Compiling module...");
+ // Let's compile the Wasm module.
+ let module = Module::new(&store, wasm_bytes)?;
+
+ // We create some shared data here, `Arc` is required because we may
+ // move our WebAssembly instance to another thread to run it. RefCell
+ // lets us get shared mutabilty which is fine because we know we won't
+ // run host calls concurrently. If concurrency is a possibilty, we'd have
+ // to use a `Mutex`.
+ let shared_counter: Arc> = Arc::new(RefCell::new(0));
+
+ // Once we have our counter we'll wrap it inside en `Env` which we'll pass
+ // to our imported functions.
+ //
+ // This struct may have been anything. The only constraint is it must be
+ // possible to know the size of the `Env` at compile time (i.e it has to
+ // implement the `Sized` trait).
+ struct Env {
+ counter: Arc>,
+ }
+
+ // Create the functions
+ fn get_counter(env: &mut Env) -> i32 {
+ *env.counter.borrow()
+ }
+ fn add_to_counter(env: &mut Env, add: i32) -> i32 {
+ let mut counter_ref = env.counter.borrow_mut();
+
+ *counter_ref += add;
+ *counter_ref
+ }
+
+ // Create an import object.
+ let import_object = imports! {
+ "env" => {
+ "get_counter" => Function::new_native_with_env(&store, Env { counter: shared_counter.clone() }, get_counter),
+ "add_to_counter" => Function::new_native_with_env(&store, Env { counter: shared_counter.clone() }, add_to_counter),
+ }
+ };
+
+ println!("Instantiating module...");
+ // Let's instantiate the Wasm module.
+ let instance = Instance::new(&module, &import_object)?;
+
+ // Here we go.
+ //
+ // The Wasm module exports a function called `increment_counter_loop`. Let's get it.
+ let increment_counter_loop = instance
+ .exports
+ .get_function("increment_counter_loop")?
+ .native::()?;
+
+ let counter_value: i32 = *shared_counter.borrow();
+ println!("Initial ounter value: {:?}", counter_value);
+
+ println!("Calling `increment_counter_loop` function...");
+ // Let's call the `increment_counter_loop` exported function.
+ //
+ // It will loop five times thus incrementing our counter five times.
+ let result = increment_counter_loop.call(5)?;
+
+ let counter_value: i32 = *shared_counter.borrow();
+ println!("New counter value (host): {:?}", counter_value);
+ assert_eq!(counter_value, 5);
+
+ println!("New counter value (guest): {:?}", counter_value);
+ assert_eq!(result, 5);
+
+ Ok(())
+}
+
+#[test]
+fn test_imported_function_env() -> Result<(), Box> {
+ main()
+}
diff --git a/examples/instance.rs b/examples/instance.rs
new file mode 100644
index 00000000000..9adc7910c06
--- /dev/null
+++ b/examples/instance.rs
@@ -0,0 +1,80 @@
+//! Wasmer will let you easily run Wasm module in a Rust host.
+//!
+//! This example illustrates the basics of using Wasmer through a "Hello World"-like project:
+//!
+//! 1. How to load a Wasm modules as bytes
+//! 2. How to compile the module
+//! 3. How to create an instance of the module
+//!
+//! You can run the example directly by executing in Wasmer root:
+//!
+//! ```shell
+//! cargo run --example instance --release --features "cranelift"
+//! ```
+//!
+//! Ready?
+
+use wasmer::{imports, wat2wasm, Instance, Module, Store};
+use wasmer_compiler_cranelift::Cranelift;
+use wasmer_engine_jit::JIT;
+
+fn main() -> Result<(), Box> {
+ // Let's declare the Wasm module.
+ //
+ // We are using the text representation of the module here but you can also load `.wasm`
+ // files using the `include_bytes!` macro.
+ let wasm_bytes = wat2wasm(
+ br#"
+(module
+ (type $add_one_t (func (param i32) (result i32)))
+ (func $add_one_f (type $add_one_t) (param $value i32) (result i32)
+ local.get $value
+ i32.const 1
+ i32.add)
+ (export "add_one" (func $add_one_f)))
+"#,
+ )?;
+
+ // Create a Store.
+ // Note that we don't need to specify the engine/compiler if we want to use
+ // the default provided by Wasmer.
+ // You can use `Store::default()` for that.
+ let store = Store::new(&JIT::new(&Cranelift::default()).engine());
+
+ println!("Compiling module...");
+ // Let's compile the Wasm module.
+ let module = Module::new(&store, wasm_bytes)?;
+
+ // Create an empty import object.
+ let import_object = imports! {};
+
+ println!("Instantiating module...");
+ // Let's instantiate the Wasm module.
+ let instance = Instance::new(&module, &import_object)?;
+
+ // We now have an instance ready to be used.
+ //
+ // From an `Instance` we can retrieve any exported entities.
+ // Each of these entities is covered in others examples.
+ //
+ // Here we are retrieving the exported function. We won't go into details here
+ // as the main focus of this example is to show how to create an instance out
+ // of a Wasm module and have basic interactions with it.
+ let add_one = instance
+ .exports
+ .get_function("add_one")?
+ .native::()?;
+
+ println!("Calling `add_one` function...");
+ let result = add_one.call(1)?;
+
+ println!("Results of `add_one`: {:?}", result);
+ assert_eq!(result, 2);
+
+ Ok(())
+}
+
+#[test]
+fn test_exported_function() -> Result<(), Box> {
+ main()
+}
diff --git a/examples/memory.rs b/examples/memory.rs
index 9da6d8131b2..d78b6dda5f9 100644
--- a/examples/memory.rs
+++ b/examples/memory.rs
@@ -1,4 +1,21 @@
-use wasmer::{imports, wat2wasm, Instance, Module, NativeFunc, Pages, Store};
+//! With Wasmer you'll be able to interact with guest module memory.
+//!
+//! This example illustrates the basics of interacting with Wasm module memory.:
+//!
+//! 1. How to load a Wasm modules as bytes
+//! 2. How to compile the module
+//! 3. How to create an instance of the module
+//!
+//! You can run the example directly by executing in Wasmer root:
+//!
+//! ```shell
+//! cargo run --example memory --release --features "cranelift"
+//! ```
+//!
+//! Ready?
+
+use std::mem;
+use wasmer::{imports, wat2wasm, Bytes, Instance, Module, NativeFunc, Pages, Store};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;
@@ -6,6 +23,10 @@ use wasmer_engine_jit::JIT;
// TODO: clean it up and comment it https://github.com/wasmerio/wasmer/issues/1749
fn main() -> anyhow::Result<()> {
+ // Let's declare the Wasm module.
+ //
+ // We are using the text representation of the module here but you can also load `.wasm`
+ // files using the `include_bytes!` macro.
let wasm_bytes = wat2wasm(
r#"
(module
@@ -32,48 +53,87 @@ fn main() -> anyhow::Result<()> {
.as_bytes(),
)?;
- // We set up our store with an engine and a compiler.
+ // Create a Store.
+ // Note that we don't need to specify the engine/compiler if we want to use
+ // the default provided by Wasmer.
+ // You can use `Store::default()` for that.
let store = Store::new(&JIT::new(&Cranelift::default()).engine());
- // Then compile our Wasm.
+
+ println!("Compiling module...");
+ // Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
+
+ // Create an empty import object.
let import_object = imports! {};
- // And instantiate it with no imports.
+
+ println!("Instantiating module...");
+ // Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
+ // The module exports some utility functions, let's get them.
+ //
+ // These function will be used later in this example.
let mem_size: NativeFunc<(), i32> = instance.exports.get_native_function("mem_size")?;
let get_at: NativeFunc = instance.exports.get_native_function("get_at")?;
let set_at: NativeFunc<(i32, i32), ()> = instance.exports.get_native_function("set_at")?;
let memory = instance.exports.get_memory("memory")?;
- let mem_addr = 0x2220;
- let val = 0xFEFEFFE;
-
+ // We now have an instance ready to be used.
+ //
+ // We will start by querying the most intersting information
+ // about the memory: its size. There are mainly two ways of getting
+ // this:
+ // * the size as a number of `Page`s
+ // * the size as a number of bytes
+ //
+ // The size in bytes can be found either by querying its pages or by
+ // querying the memory directly.
+ println!("Querying memory size...");
assert_eq!(memory.size(), Pages::from(1));
+ assert_eq!(memory.size().bytes(), Bytes::from(65536 as usize));
+ assert_eq!(memory.data_size(), 65536);
+
+ // Sometimes, the guest module may also export a function to let you
+ // query the memory. Here we have a `mem_size` function, let's try it:
+ let result = mem_size.call()?;
+ println!("Memory size: {:?}", result);
+ assert_eq!(Pages::from(result as u32), memory.size());
+
+ // Now that we know the size of our memory, it's time to see how wa
+ // can change this.
+ //
+ // A memory can be grown to allow storing more things into it. Let's
+ // see how we can do that:
+ println!("Growing memory...");
+ // Here we are requesting two more pages for our memory.
memory.grow(2)?;
assert_eq!(memory.size(), Pages::from(3));
- let result = mem_size.call()?;
- assert_eq!(result, 3);
+ assert_eq!(memory.data_size(), 65536 * 3);
- // -------------
+ // Now that we know how to query and adjust the size of the memory,
+ // let's see how wa can write to it or read from it.
+ //
+ // We'll only focus on how to do this using exported functions, the goal
+ // is to show how to work with memory addresses. Here we'll use absolute
+ // addresses to write and read a value.
+ let mem_addr = 0x2220;
+ let val = 0xFEFEFFE;
set_at.call(mem_addr, val)?;
- // -------------
+ let result = get_at.call(mem_addr)?;
+ println!("Value at {:#x?}: {:?}", mem_addr, result);
+ assert_eq!(result, val);
+
+ // Now instead of using hard coded memory addresses, let's try to write
+ // something at the end of the second memory page and read it.
let page_size = 0x1_0000;
- let result = get_at.call(page_size * 3 - 4)?;
- memory.grow(1025)?;
- assert_eq!(result, 123456);
- assert_eq!(memory.size(), Pages::from(1028));
- set_at.call(page_size * 1027 - 4, 123456)?;
- let result = get_at.call(page_size * 1027 - 4)?;
- assert_eq!(result, 123456);
- set_at.call(1024, 123456)?;
- let result = get_at.call(1024)?;
- assert_eq!(result, 123456);
-
- // -------------
+ let mem_addr = (page_size * 2) - mem::size_of_val(&val) as i32;
+ let val = 0xFEA09;
+ set_at.call(mem_addr, val)?;
+
let result = get_at.call(mem_addr)?;
+ println!("Value at {:#x?}: {:?}", mem_addr, result);
assert_eq!(result, val);
- // -------------
Ok(())
}
diff --git a/examples/tunables_limit_memory.rs b/examples/tunables_limit_memory.rs
index dfe5f40cd1d..c87f371bc21 100644
--- a/examples/tunables_limit_memory.rs
+++ b/examples/tunables_limit_memory.rs
@@ -16,7 +16,7 @@ use wasmer_engine_jit::JIT;
/// After adjusting the memory limits, it delegates all other logic
/// to the base tunables.
pub struct LimitingTunables {
- /// The maxium a linear memory is allowed to be (in Wasm pages, 65 KiB each).
+ /// The maximum a linear memory is allowed to be (in Wasm pages, 64 KiB each).
/// Since Wasmer ensures there is only none or one memory, this is practically
/// an upper limit for the guest memory.
limit: Pages,