doc(examples): Add Global examples

This commit is contained in:
jubianchi
2020-10-22 18:20:40 +02:00
parent e6394e80ef
commit 8782c0f9ea
5 changed files with 415 additions and 5 deletions

View File

@@ -191,6 +191,16 @@ name = "exported-function"
path = "examples/exports_function.rs" path = "examples/exports_function.rs"
required-features = ["cranelift"] 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]] [[example]]
name = "wasi" name = "wasi"
path = "examples/wasi.rs" path = "examples/wasi.rs"

View File

@@ -150,8 +150,23 @@ example.
</details> </details>
### Exports ### 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, how to call an exported function. They come in 2 flavors: dynamic,
and “static”/native. The pros and cons are discussed briefly. and “static”/native. The pros and cons are discussed briefly.
@@ -166,9 +181,25 @@ example.
</details> </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 ### 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. Interface][WASI] (WASI), i.e. the [`wasmer-wasi`] crate.
_Keywords_: wasi, system, interface _Keywords_: wasi, system, interface
@@ -189,7 +220,9 @@ example.
[compiler-cranelift]: ./compiler_cranelift.rs [compiler-cranelift]: ./compiler_cranelift.rs
[compiler-llvm]: ./compiler_llvm.rs [compiler-llvm]: ./compiler_llvm.rs
[cross-compilation]: ./engine_cross_compilation.rs [cross-compilation]: ./engine_cross_compilation.rs
[exported-global]: ./exports_global.rs
[exported-function]: ./exports_function.rs [exported-function]: ./exports_function.rs
[imported-global]: imports_global.rs
[wasi]: ./wasi.rs [wasi]: ./wasi.rs
[`wasmer-compiler-singlepass`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-singlepass [`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 [`wasmer-compiler-cranelift`]: https://github.com/wasmerio/wasmer/tree/master/lib/compiler-cranelift

143
examples/exports_global.rs Normal file
View File

@@ -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
examples/imports_global.rs Normal file
View File

@@ -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()
}

View File

@@ -23,11 +23,35 @@ pub struct Global {
impl Global { impl Global {
/// Create a new `Global` with the initial value [`Val`]. /// Create a new `Global` with the initial value [`Val`].
///
/// # Example
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// assert_eq!(g.get(), Value::I32(1));
/// assert_eq!(g.ty().mutability, Mutability::Const);
/// ```
pub fn new(store: &Store, val: Val) -> Self { pub fn new(store: &Store, val: Val) -> Self {
Self::from_value(store, val, Mutability::Const).unwrap() Self::from_value(store, val, Mutability::Const).unwrap()
} }
/// Create a mutable `Global` with the initial value [`Val`]. /// Create a mutable `Global` with the initial value [`Val`].
///
/// # Example
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new_mut(&store, Value::I32(1));
///
/// assert_eq!(g.get(), Value::I32(1));
/// assert_eq!(g.ty().mutability, Mutability::Var);
/// ```
pub fn new_mut(store: &Store, val: Val) -> Self { pub fn new_mut(store: &Store, val: Val) -> Self {
Self::from_value(store, val, Mutability::Var).unwrap() Self::from_value(store, val, Mutability::Var).unwrap()
} }
@@ -54,27 +78,96 @@ impl Global {
} }
/// Returns the [`GlobalType`] of the `Global`. /// Returns the [`GlobalType`] of the `Global`.
///
/// # Example
///
/// ```
/// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType};
/// # let store = Store::default();
/// #
/// let c = Global::new(&store, Value::I32(1));
/// let v = Global::new_mut(&store, Value::I64(1));
///
/// assert_eq!(c.ty(), &GlobalType::new(Type::I32, Mutability::Const));
/// assert_eq!(v.ty(), &GlobalType::new(Type::I64, Mutability::Var));
/// ```
pub fn ty(&self) -> &GlobalType { pub fn ty(&self) -> &GlobalType {
self.global.ty() self.global.ty()
} }
/// Returns the [`Store`] where the `Global` belongs. /// Returns the [`Store`] where the `Global` belongs.
///
/// # Example
///
/// ```
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// assert_eq!(g.store(), &store);
/// ```
pub fn store(&self) -> &Store { pub fn store(&self) -> &Store {
&self.store &self.store
} }
/// Retrieves the current value [`Val`] that the Global has. /// Retrieves the current value [`Val`] that the Global has.
///
/// # Example
///
/// ```
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// assert_eq!(g.get(), Value::I32(1));
/// ```
pub fn get(&self) -> Val { pub fn get(&self) -> Val {
self.global.get() self.global.get()
} }
/// Sets a custom value [`Val`] to the runtime Global. /// Sets a custom value [`Val`] to the runtime Global.
/// ///
/// # Example
///
/// ```
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new_mut(&store, Value::I32(1));
///
/// assert_eq!(g.get(), Value::I32(1));
///
/// g.set(Value::I32(2));
///
/// assert_eq!(g.get(), Value::I32(2));
/// ```
///
/// # Errors /// # Errors
/// ///
/// This function will error if: /// Trying to mutate a immutable global will raise an error:
/// * The global is not mutable ///
/// * The type of the `Val` doesn't matches the Global type. /// ```should_panic
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// g.set(Value::I32(2)).unwrap();
/// ```
///
/// Trying to set a value of a incompatible type will raise an error:
///
/// ```should_panic
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// // This results in an error: `RuntimeError`.
/// g.set(Value::I64(2)).unwrap();
/// ```
pub fn set(&self, val: Val) -> Result<(), RuntimeError> { pub fn set(&self, val: Val) -> Result<(), RuntimeError> {
if !val.comes_from_same_store(&self.store) { if !val.comes_from_same_store(&self.store) {
return Err(RuntimeError::new("cross-`Store` values are not supported")); return Err(RuntimeError::new("cross-`Store` values are not supported"));
@@ -95,6 +188,17 @@ impl Global {
} }
/// Returns whether or not these two globals refer to the same data. /// Returns whether or not these two globals refer to the same data.
///
/// # Example
///
/// ```
/// # use wasmer::{Global, Store, Value};
/// # let store = Store::default();
/// #
/// let g = Global::new(&store, Value::I32(1));
///
/// assert!(g.same(&g));
/// ```
pub fn same(&self, other: &Self) -> bool { pub fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.global, &other.global) Arc::ptr_eq(&self.global, &other.global)
} }