Skip to content

Commit

Permalink
doc(examples): Add Global examples
Browse files Browse the repository at this point in the history
  • Loading branch information
jubianchi committed Oct 26, 2020
1 parent e6394e8 commit 8782c0f
Show file tree
Hide file tree
Showing 5 changed files with 415 additions and 5 deletions.
10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,16 @@ name = "exported-function"
path = "examples/exports_function.rs"
required-features = ["cranelift"]

[[example]]
name = "exported-global"
path = "examples/exports_global.rs"
required-features = ["cranelift"]

[[example]]
name = "imported-global"
path = "examples/imports_global.rs"
required-features = ["cranelift"]

[[example]]
name = "wasi"
path = "examples/wasi.rs"
Expand Down
37 changes: 35 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,23 @@ example.
</details>

### Exports

8. [**Exported global**][exported-global], explains how to work with
exported globals: get/set their value, have information about their
type.

8. [**Exported function**][exported-function], explains how to get and
_Keywords_: export, global.

<details>
<summary><em>Execute the example</em></summary>

```shell
$ cargo run --example exported-globals --release --features "cranelift"
```

</details>

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.

Expand All @@ -166,9 +181,25 @@ example.

</details>

### Imports

10. [**Imported global**][imported-global], explains how to work with
imported globals: create globals, import them, get/set their value.

_Keywords_: import, global.

<details>
<summary><em>Execute the example</em></summary>

```shell
$ cargo run --example imported-globals --release --features "cranelift"
```

</details>

### Integrations

9. [**WASI**][wasi], explains how to use the [WebAssembly System
11. [**WASI**][wasi], explains how to use the [WebAssembly System
Interface][WASI] (WASI), i.e. the [`wasmer-wasi`] crate.

_Keywords_: wasi, system, interface
Expand All @@ -189,7 +220,9 @@ example.
[compiler-cranelift]: ./compiler_cranelift.rs
[compiler-llvm]: ./compiler_llvm.rs
[cross-compilation]: ./engine_cross_compilation.rs
[exported-global]: ./exports_global.rs
[exported-function]: ./exports_function.rs
[imported-global]: imports_global.rs
[wasi]: ./wasi.rs
[`wasmer-compiler-singlepass`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-singlepass
[`wasmer-compiler-cranelift`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-cranelift
Expand Down
143 changes: 143 additions & 0 deletions examples/exports_global.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
//! A Wasm module can export entities, like functions, memories,
//! globals and tables.
//!
//! This example illustrates how to use exported globals. They come
//! in 2 flavors:
//!
//! 1. Immutable globals (const),
//! 2. Mutable globals.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```shell
//! cargo run --example exported-global --release --features "cranelift"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Instance, Module, Mutability, Store, Type, Value};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;

fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
br#"
(module
(global $one (export "one") f32 (f32.const 1))
(global $some (export "some") (mut f32) (f32.const 0))
(func (export "get_one") (result f32) (global.get $one))
(func (export "get_some") (result f32) (global.get $some))
(func (export "set_some") (param f32) (global.set $some (local.get 0))))
"#,
)?;

// 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)?;

// Here we go.
//
// The Wasm module exports some globals. Let's get them.
// Note that
//
// ```
// get_global(name)
// ```
//
// is just an alias to
//
// ```
// get::<Global>(name)`.
// ```
let one = instance.exports.get_global("one")?;
let some = instance.exports.get_global("some")?;

println!("Getting global type informations...");
// 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);
assert_eq!(one_type.mutability, Mutability::Const);
assert_eq!(one_type.ty, Type::F32);

println!("some type: {:?} {:?}", some_type.mutability, some_type.ty);
assert_eq!(some_type.mutability, Mutability::Var);
assert_eq!(some_type.ty, Type::F32);

println!("Getting global values...");
// Getting the values of globals can be done in two ways:
// 1. Through an exported function,
// 2. Using the Global API directly.
//
// We will use an exported function for the `one` global
// and the Global API for `some`.
let get_one = instance
.exports
.get_function("get_one")?
.native::<(), f32>()?;

let one_result = get_one.call()?;
let some_result = some.get();

println!("one value: {:?}", one_result);
assert_eq!(one_result, 1.0);

println!("some value: {:?}", some_result);
assert_eq!(some_result, Value::F32(0.0));

println!("Setting global values...");
// Trying to set the value of a immutable global (`const`)
// will result in a `RuntimeError`.
let result = one.set(Value::F32(42.0));
assert_eq!(
result.expect_err("Expected an error").message(),
"Attempted to set an immutable global"
);

let one_result = one.get();
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:
// 1. Through an exported function,
// 2. Using the Global API directly.
//
// We will use both for the `some` global.
let set_some = instance
.exports
.get_function("set_some")?
.native::<f32, ()>()?;
set_some.call(21.0)?;
let some_result = some.get();
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);
assert_eq!(some_result, Value::F32(42.0));

Ok(())
}

#[test]
fn test_exported_global() -> Result<(), Box<dyn std::error::Error>> {
main()
}
120 changes: 120 additions & 0 deletions examples/imports_global.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//! A Wasm module can import entities, like functions, memories,
//! globals and tables.
//!
//! This example illustrates how to use imported globals. They come
//! in 2 flavors:
//!
//! 1. Immutable globals (const),
//! 2. Mutable globals.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```shell
//! cargo run --example imported-global --release --features "cranelift"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Global, Instance, Module, Store, Value};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;

fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
br#"
(module
(global $some (import "env" "some") f32)
(global $other (import "env" "other") (mut f32))
(func (export "get_some") (result f32) (global.get $some))
(func (export "get_other") (result f32) (global.get $other))
(func (export "set_other") (param f32) (global.set $other (local.get 0))))
"#,
)?;

// 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 the globals
let some = Global::new(&store, Value::F32(1.0));
let other = Global::new_mut(&store, Value::F32(2.0));

// Create an import object.
// We add the two required globals in the `env` namespace.
let import_object = imports! {
"env" => {
"some" => some.clone(),
"other" => other.clone(),
}
};

println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;

// Here we go.
//
// The Wasm module only imports some globals. We'll have to interact
// with them either using the Global API or exported functions.
let get_some = instance
.exports
.get_function("get_some")?
.native::<(), f32>()?;
let get_other = instance
.exports
.get_function("get_other")?
.native::<(), f32>()?;

let some_result = get_some.call()?;
let other_result = get_other.call()?;

println!("some value (via `get_some`): {:?}", some_result);
println!("some value (via Global API): {:?}", some.get());
println!("other value (via `get_other`): {:?}", other_result);
println!("other value (via Global API): {:?}", other.get());

assert_eq!(some_result, some.get().f32().unwrap());
assert_eq!(other_result, other.get().f32().unwrap());

println!("Setting global values...");
// Trying to set the value of a immutable global (`const`)
// will result in a `RuntimeError`.
let result = some.set(Value::F32(42.0));
assert_eq!(
result.expect_err("Expected an error").message(),
"Attempted to set an immutable global"
);

other.set(Value::F32(21.0))?;
let other_result = other.get();
println!("other value after `set`: {:?}", other_result);
assert_eq!(other_result, Value::F32(21.0));

println!("Altering global values through exported functions...");
// Changes made to global through exported functions will
// be reflected on the host side.
let set_other = instance
.exports
.get_function("set_other")?
.native::<f32, ()>()?;
set_other.call(42.0)?;

println!("other value (via Global API): {:?}", other.get());
assert_eq!(other.get(), Value::F32(42.0));

Ok(())
}

#[test]
fn test_imported_global() -> Result<(), Box<dyn std::error::Error>> {
main()
}
Loading

0 comments on commit 8782c0f

Please sign in to comment.